我在我的项目中使用了来自nio2的java AsynchronousSocketChannel
。我也在ubuntu 14.04上使用oracle jdk 1.7.0_80。
我的项目是处理二进制数据的服务器。
代码在CompletionHandler
匿名类的已完成方法中递归调用read操作,如下所示:
private final CompletionHandler<Integer,AsynchronousSocketChannel> readHandler=new CompletionHandler<Integer,AsynchronousSocketChannel>(){
@Override
public void completed(Integer result,AsynchronousSocketChannel attachment) {
if(result<0){
attachment.close();
return;
}
attachment.read(swap, attachment, this);
}
}
变量swap是ByteBuffer实例。
显然,一切都运作良好。但是,有一个总大小为3832字节的数据包,当服务器收到整个数据包时,没有段,没有问题。但是,有时这个数据包被分为两个或多个部分(TCP段)。例如:第一段的大小为2896字节,第二段的大小为936字节。
最后一段没有标题,这打破了我的算法。 我想知道,有没有办法做API调用&#34;完成&#34;方法只有在读完整个数据包之后?
我已将SO_RCVBUF
增加到64K,但它无法正常工作。
答案 0 :(得分:1)
我想知道,有没有办法在读取整个数据包后才能调用API“完成”方法?
不,没有办法做到这一点。
TCP协议可以分解任意大小的数据包中的字节流。您在TCP之上使用的应用程序级协议不得依赖于始终在一个TCP数据包中完全发送的消息。
您必须设计应用程序级协议,以便能够处理以任意大小的数据包分组的邮件。
执行此操作的一种常见方法是通过长度字段为应用程序级消息添加前缀。例如,应用程序级消息由4个字节的字段组成,其中包含消息其余部分的长度。当您收到消息时,您首先会收到该消息,然后您应该继续接收,直到您收到那么多字节,然后您可以将它们组合成一个应用程序级别的消息。
AsynchronousSocketChannel
API无法自动为您重新组合应用程序级消息,因为它对您的应用程序级协议一无所知。