首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ReadableByteChannel挂起读取(字节缓冲区)

ReadableByteChannel挂起读取(字节缓冲区)
EN

Stack Overflow用户
提问于 2011-09-05 12:02:49
回答 2查看 1.9K关注 0票数 1

我正在使用java 1.6编写即时信使。IM使用多线程-主线程、接收和ping。对于tcp/ip通信,我使用了SocketChannel。从服务器接收更大的包似乎存在问题。服务器(而不是一个)发送了几个包,这就是问题的开始。前8个字节显示的是包的类型以及它的大小。我就是这样读到的:

代码语言:javascript
运行
复制
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个发回给我。所以我想出了这样的东西:

代码语言:javascript
运行
复制
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()都在用缓冲区中剩余的字节检查每个参数的大小:

代码语言:javascript
运行
复制
 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()是:

代码语言:javascript
运行
复制
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(),在字节= readChannel.read(bb)上,它只是停止了,我不知道为什么,没有错误,即使过了一段时间,也没有任何错误,我也不知道。我整个星期都在努力,我没有办法解决这个问题。如有任何建议,我将不胜感激。谢谢。

谢谢你的回应。是的,我使用的是阻塞SocketChannel,我尝试了非阻塞,但它变得疯狂和失控,所以我跳过了这个想法。关于我所期望的字节--这有点奇怪,因为它只在头中给了我一次大小,但是它的第一部分的大小不是整个包,其他部分根本不包含头字节。我无法预测它将是多少字节,原因是-255个字节容量的描述。这就是为什么我在:中创建了变量:public synchronized void readInStatus(ByteBuffer headBuffer)主要是我的好友列表的长度,在读取每个字段之前,我要检查是否还有足够的字节(如果没有),我做read()。但是描述之前的最后一个字段是整数,带有传入描述的长度。但是,在完成某些处理之前,不可能确定包的长度。@罗伯特,在这种情况下,你认为我应该再次尝试改用非阻塞的SocketChannel吗?

EN

回答 2

Stack Overflow用户

发布于 2011-09-05 12:43:31

这个问题很可能是因为你发送的字节比你想要读取的要少。你可能错过了写一些东西,写错了顺序,误读了一个大小字段或类似的东西。

我想我应该通过添加跟踪代码来计算和记录读和写的字节数、概念包大小等等来解决这个问题。然后运行,并比较跟踪,以了解从哪里开始失去同步。

票数 1
EN

Stack Overflow用户

发布于 2011-09-07 09:27:44

如果您使用的是阻塞的SocketChannel,那么读取将被阻塞,直到缓冲区被填充或服务器交付流的结束为止。对于连接保持活跃的服务器,服务器不会发送流的结束,它只会停止发送数据,读取将无限期地挂起或直到超时。

您也可以这样做:(i)尝试使用非阻塞的SocketChannel,反复读取直到读取传递0字节(但小心0字节并不一定意味着流的结束-这可能意味着中断),或者(ii)如果您必须使用阻塞版本,并且您知道从服务器上期望从服务器获得多少字节,例如,当需要读取的字节数小于buffer.capacity()时,移动缓冲区的位置和/或限制,以便在读取之前只在缓冲区中留下所需的空间。我现在正在解决这个问题。如果对你有用,请告诉我!

据我所知,如果您必须使用阻塞的SocketChannel,并且不知道您期望的字节数,并且服务器不发送流的结束,则没有解决方案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7307783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档