java - ReadableByteChannel 在读取(bytebuffer)时挂起

标签 java multithreading connection bytebuffer socketchannel

我正在使用 java 1.6 开发即时通讯工具。 IM 使用多线程 - 主线程、接收和 ping。对于 tcp/ip 通信,我使用了 SocketChannel。从服务器接收更大的包裹似乎存在问题。服务器而不是服务器发送了几个包,这就是问题开始的地方。前 8 个字节表示包的类型以及包的大小。这就是我阅读的方式:

public void run(){
    while(true){
        try{
        Headbuffer.clear();
        bytes = readChannel.read(Headbuffer); //ReadableByteChannel
        Headbuffer.flip();
        if(bytes != -1){
            int head = Headbuffer.getInt();
            int size = Headbuffer.getInt();
            System.out.println("received pkg: 0x" + Integer.toHexString(head)+" with size "+ size+" bytes);
            switch(head){
            case incoming.Pkg1: ReadWelcome(); break;
            case incoming.Pkg2: ReadLoginFail();break;
            case incoming.Pkg3: ReadLoginOk();break;
            case incoming.Pkg4: ReadUserList();break;
            case incoming.Pkg5: ReadUserData();break;
            case incoming.Pkg6: ReadMessage();break;
            case incoming.Pkg7: ReadTypingNotify();break;
            case incoming.Pkg8: ReadListStatus();break;
            case incoming.Pkg9: ChangeStatus();break;
            }
        }
        }catch(Exception e){
            e.printStackTrace();
        }
    }   
}

在测试期间一切都很好,直到我登录我的帐户并导入我的好友列表。我向服务器发送状态请求,他给我发回了 80 个联系人中的大约 10 个。所以我想出了这样的东西:

public synchronized void readInStatus(ByteBuffer headBuffer){

    byteArray.add(headBuffer); //Store every buffer in ArrayList
    int buddies = MainController.controler.getContacts().getSize();
    while(buddies>0){

          readStuff();
          readDescription();
        --buddies; 
    }       
}

每个 readStuff() 和 readDescription() 都会检查每个参数大小以及缓冲区中的剩余字节:

 if(byteArray.get(current).remaining() >= 4){

      uin = byteArray.get(current).getInt();
      }else{
          byteArray.add(Receiver.receiver.read());
          current = current +1;
          uin = byteArray.get(current).getInt(); 
      }

而 Receiver.receiver.read() 是:

public ByteBuffer read(){
    try {
        ByteBuffer bb = ByteBuffer.allocate(40000);
        bb.order(ByteOrder.LITTLE_ENDIAN);
        bytes = readChannel.read(bb);
        bb.flip();
        return bb;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

因此,应用程序已启动、记录,然后发送联系人。服务器只发回我的列表的一部分。但在方法 readInStatus(ByteBuffer headBuffer) 中,我尝试强制列表的其余部分。现在有趣的部分 - 一段时间后它到达 Receiver.receiver.read() 并在 bytes = readChannel.read(bb) 上它停止了,我不知道为什么,没有错误,甚至在一段时间后什么也没有,我没有想法。我整整一周都在奋斗,但我没有找到解决方案。我将不胜感激任何建议。谢谢。

<小时/>

感谢您的回复。是的,我正在使用阻塞 SocketChannel,我尝试过非阻塞,但它变得疯狂并且失控,所以我跳过了这个想法。关于我期望的字节 - 这有点奇怪,因为它只在头部给我一次大小,但它的第一部分的大小而不是整个包,其他部分根本不包含头字节。我无法预测它会有多少字节,原因是 - 具有 255 字节容量的描述。这正是我在以下位置创建变量 buddies 的原因:public synchronized void readInStatus(ByteBuffer headBuffer) 这基本上是我的好友列表的长度,在读取每个字段之前,我会检查是否还有足够的字节,如果没有,我会执行read()。但描述之前的最后一个字段是传入描述长度的整数。但在完成某些处理之前,无法确定包的长度。 @robert 你认为在这种情况下我应该再次尝试切换到非阻塞 SocketChannel 吗?

最佳答案

问题很可能是您发送的字节数少于您尝试读取的字节数。您可能错过了一些内容、写错了顺序、误读了尺寸字段或类似的内容。

我想我可以通过添加跟踪代码来计算和记录读取和写入的字节数、名义数据包大小等来解决这个问题。然后运行并比较跟踪,看看哪里开始不同步。

关于java - ReadableByteChannel 在读取(bytebuffer)时挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7307783/

相关文章:

java - Java Swing 中的空指针异常

java - org.eclipse.jdt.core.dom.ASTNode 的 child

java - 服务器和客户端之间的简单连接。客户端发送消息,服务器正确接收消息。但是当服务器尝试回复时什么也不起作用?

按名称的android tcp连接

ubuntu - WSL Ubuntu(Linux 的 Windows 子系统)上没有互联网连接

java - 将字符串拆分为全部字母和全部数字

java - 在 openjdk11 下执行 sonar-maven-plugin 时不支持的类文件主要版本 55

c# - .net 中的线程

java - Sun 的 Thread.join 方法是否因为使用 Thread 对象同步而损坏?

java - 单客户端到多客户端支持 : multithreading conversion in java