使用java7的nio2搭建了server socket和client socket,从client发送消息到server没有问题,但是server收到消息后,向订阅的client转发消息后,订阅的client只收到了部分消息,通过log发现,虽然server端转发了全部的消息到订阅端,但是订阅端的read方法的完成接口并未全部响应。按道理说,服务器write完成后会发送完成事件通知客户端进行read,为什么现在server端的write操作和client端的read操作的次数会不一致呢,希望大神帮忙分析一下,谢谢。
------解决思路----------------------
我猜测你的write函数并没有把数据全部发送出去。由于是nio,读写都是非阻塞的,当发送缓存区满了,write直接返回0,ByteBuffer中的数据并没有发出去,造成数据丢失,你最好检查下write的返回值,或者write后用ByteBuffer.hasRemainning()去测试是否全部发送。还有就是发送次数和接收次数,对于基于流的TCP协议,发送次数和接收次数本来就没有关系,比如client每次写1024大小的数据,server中的read的buffer大小为2048,。这样可能的结果是:client发送两次,Server只需接收一次就搞定。
另据说Java NIO BUG较多,建议去看看netty或者mina
------解决思路----------------------
"因为log是在write完成后才输出的,所以根据log条数可以确定成功write了所有的message",这句我真不知道这是什么逻辑,write()肯定是会返回的,不管是写完还是没写完。如果没写完,返回0后也能log啊?还有就是
if (wbuffer.hasRemaining()) {
wbuffer.compact();
socket.write(wbuffer, null, this);
}
这几行代码怎么能确保数据全部发送,发送缓冲区满了它一样返回0吧
------解决思路----------------------
其实关键在于tcp_nodelay也不能阻止下层协议或者接收端缓存合并你的段吧。
tcp本身是流式的(不是一个包一个包这样的逻辑结构,而是一个流的逻辑结构),想用块式还需要自己加上块标记。
------解决思路----------------------
使用tcp传输数据一般是不会出现乱序这样的状况的。。
------解决思路----------------------
其实关键在于tcp_nodelay也不能阻止下层协议或者接收端缓存合并你的段吧。
tcp本身是流式的(不是一个包一个包这样的逻辑结构,而是一个流的逻辑结构),想用块式还需要自己加上块标记。
你说的对,我后来发现read到的不是一条消息,而是一批数据,而程序只处理了第一条就read下一批数据了,所以造成消息的丢失。
现在又有新的问题了,如果处理到最后剩余的字节只是某个消息的前半部分,按理说只需要把这半个消息和下次读取的数据组合起来进行处理就可以了,但是现状却是,紧接着第二次读取到的数据并不一定是消息的后半部分,而是另外一批消息,后半部分的消息有可能在下几次read才能拿到,这就比较麻烦了。
你检查下发送端是不是出现发送数据乱序的问题。