日期:2014-05-20  浏览次数:20848 次

java网络编程,分包接收数据的疑惑,望大侠指点!
最近在做java接收二进制流的测试,一个服务端一个客户,服务端接收到客户端的请求后,向客户端一次性发送50kB左右的二进制数据包;包头占四个字节,指示了数据包的长度;

客户端收到四个字节的包头后,打印包体的长度length,正确,

于是分配50kb的buff,byte[] buff=new byte[length];

int canread=socket.avaliable();
//canread的大小也是正常的;

int readlen=socket.getinputstream().read(buff,0,length);
//readlen的长度为length的大小,按API的说法是读到了length个字节,但缓冲区中却没有那么多数据;
//如果readlen不可靠,那么如何才能获得可靠的接收到的数据?
//因为50kb不可能在一个TCP包中传过来,肯定分成多包来传的,我想知道我具体已经接收了多少了,给我的感觉是socket.getinputstream().read()的返回值是不可靠的;

感谢大侠的指点!

------解决方案--------------------
你有没有尝试过查看一下read后buff里面的数据?
看下真实的长度是多少,如何真的不对,你去看一下你的服务器端发送数据的时候有没有
flush();
如果还不行我就没办法了。

------解决方案--------------------
楼主参照下:ByteArrayInputStream 应该可以满足你的需求!
------解决方案--------------------
常见问题,循环读取就行了,参考如下:

InputStream is = socket.getinputstream();
byte[] buff=new byte[length];
int pos = 0;
while (pos < length) {
    pos += is.read(buff, pos, length-pos);
}

------解决方案--------------------
readlen会不对吗?按理这么简单的一个功能api不太可能会出错的
------解决方案--------------------
不是一次性发送那么多数据,那就循环读取就好
------解决方案--------------------
阻塞式循环读取。
最好使用非阻塞式,接收方每接收到一次正确包就发送一个小标示给服务器发请求送下一个包。
------解决方案--------------------
引用:
刚刚调试了一下,在循环中把每次收到的一个分包转换成可显示字符打印出来,发现几次收到的数据有的是相同的;难道socket在读完缓冲区后没有清空?反复的读一同一段内容?


除非你的发送逻辑写错了。
------解决方案--------------------
引用:
引用:
readlen会不对吗?按理这么简单的一个功能api不太可能会出错的
的确不对。readlen和写入buffer中的数据长度不一致,也就是:

有的时候返回了readlen,但没有读到数据。

根据javadoc,返回的字节数和实际读取到的字节应该是一致的,不管读取过程是以何种方式结束的,包括读完length字节,检测到EOF,异常产生。

楼主不妨贴下调试截图。
------解决方案--------------------
引用:
刚刚调试了一下,在循环中把每次收到的一个分包转换成可显示字符打印出来,发现几次收到的数据有的是相同的;难道socket在读完缓冲区后没有清空?反复的读一同一段内容?


我也遇到过这种情况,具体原因当时也没仔细查,不过只要把服务器端程序改成每发送一次就休眠几十毫秒就没问题了。
不过休眠几十毫秒又觉得太浪费时间,最终决定把所要发送的字节数组包装成了一个对象:
class sendObj {
    byte[] bytes;
}
然后使用objectoutputstream 和 objectinputstream,以对象的方式发送和接受也就没问题了。

------解决方案--------------------
在网络上发送对象要记得序列化!~