我正在使用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(),在字节= readChannel.read(bb)上,它只是停止了,我不知道为什么,没有错误,即使过了一段时间,也没有任何错误,我也不知道。我整个星期都在努力,我没有办法解决这个问题。如有任何建议,我将不胜感激。谢谢。
谢谢你的回应。是的,我使用的是阻塞SocketChannel,我尝试了非阻塞,但它变得疯狂和失控,所以我跳过了这个想法。关于我所期望的字节--这有点奇怪,因为它只在头中给了我一次大小,但是它的第一部分的大小不是整个包,其他部分根本不包含头字节。我无法预测它将是多少字节,原因是-255个字节容量的描述。这就是为什么我在:中创建了变量:public synchronized void readInStatus(ByteBuffer headBuffer)主要是我的好友列表的长度,在读取每个字段之前,我要检查是否还有足够的字节(如果没有),我做read()。但是描述之前的最后一个字段是整数,带有传入描述的长度。但是,在完成某些处理之前,不可能确定包的长度。@罗伯特,在这种情况下,你认为我应该再次尝试改用非阻塞的SocketChannel吗?
发布于 2011-09-05 12:43:31
这个问题很可能是因为你发送的字节比你想要读取的要少。你可能错过了写一些东西,写错了顺序,误读了一个大小字段或类似的东西。
我想我应该通过添加跟踪代码来计算和记录读和写的字节数、概念包大小等等来解决这个问题。然后运行,并比较跟踪,以了解从哪里开始失去同步。
发布于 2011-09-07 09:27:44
如果您使用的是阻塞的SocketChannel,那么读取将被阻塞,直到缓冲区被填充或服务器交付流的结束为止。对于连接保持活跃的服务器,服务器不会发送流的结束,它只会停止发送数据,读取将无限期地挂起或直到超时。
您也可以这样做:(i)尝试使用非阻塞的SocketChannel,反复读取直到读取传递0字节(但小心0字节并不一定意味着流的结束-这可能意味着中断),或者(ii)如果您必须使用阻塞版本,并且您知道从服务器上期望从服务器获得多少字节,例如,当需要读取的字节数小于buffer.capacity()时,移动缓冲区的位置和/或限制,以便在读取之前只在缓冲区中留下所需的空间。我现在正在解决这个问题。如果对你有用,请告诉我!
据我所知,如果您必须使用阻塞的SocketChannel,并且不知道您期望的字节数,并且服务器不发送流的结束,则没有解决方案。
https://stackoverflow.com/questions/7307783
复制相似问题