当我在本地(在我自己的计算机上)运行下面的程序时,它工作得很好--我可以向它发送消息,它可以正确地读取它们。只要我把它放在远程服务器上并发送一条消息,就只有一半的消息被读取。
try {
this.asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(80));
this.asynchronousServerSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel asynchronousSocketChannel, Void att) {
try {
asynchronousServerSocketChannel.accept(null, this);
ByteBuffer byteBuffer = ByteBuffer.allocate(10485760);
asynchronousSocketChannel.read(byteBuffer).get(120000, TimeUnit.SECONDS);
byteBuffer.flip();
System.out.println("request: " + Charset.defaultCharset().decode(byteBuffer).toString());
} catch (CorruptHeadersException | CorruptProtocolException | MalformedURLException ex) {
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
}
}
@Override
public void failed(Throwable exc, Void att) {
}
});
} catch (IOException ex) {
}我已经查看了其他questions,并尝试了一些答案,但到目前为止都没有奏效。我认为原因可能是当它被远程放置时,由于它在网络上的速度较慢而超时,但增加超时并不能解决问题。我还认为消息可能太大,但为ByteBuffer分配更多容量也不能解决问题。
发布于 2018-01-11 00:00:34
我相信你的问题出在你使用的代码的异步特性上。您所拥有的是一个打开的连接,并且您已经在套接字上调用了异步read方法。这将从通道读取n字节,其中n是从0到可用缓冲区大小的任何值。
我坚信你必须循环阅读。也就是说,使用Java NIO;您可能需要在CompletionHandler上从completed方法再次调用read,方法可能是将AsynchronousSocketChannel作为新completed方法的附件传递给为read创建的CompletionHandler,而不是为accept方法创建的an。
我认为这与使用this再次调用accept时使用的模式是相同的,因为在用于accept方法调用的CompletionHandler中,它是completed方法中的完成处理程序。
然后,将"Escape“子句放入CompletionHandler中就变得很重要了,例如,如果result是-1,或者如果ByteBuffer已经读取了X的字节数,或者基于ByteBuffer中的最终byte是否是您与发送应用程序约定的特定消息终止字节。
关于这个问题的Java Documentation甚至说,read方法只会在调用时读取dst上的字节数量。
总而言之,对read处理程序的completed方法调用似乎是在将某些内容写入通道后执行的;但是,如果正在流式传输某些内容,您可能会获得一半的字节,因此您需要继续读取,直到您满意地获得了它们所发送的内容的结尾。
下面是我在阅读时拼凑起来的一些代码,异步地在阅读时响应。与我不同的是,它可以边说边听。
public class ReadForeverCompletionHandler implements CompletionHandler<Integer, Pair<AsynchronousSocketChannel, ByteBuffer>> {
@Override
public void completed(Integer bytesRead, Pair<AsynchronousSocketChannel, ByteBuffer> statefulStuff) {
if(bytesRead != -1) {
final ByteBuffer receivedByteBuffer = statefulStuff.getRight();
final AsynchronousSocketChannel theSocketChannel = statefulStuff.getLeft();
if (receivedByteBuffer.position()>8) {
//New buffer as existing buffer is in use
ByteBuffer response = ByteBuffer.wrap(receivedByteBuffer.array());
receivedByteBuffer.clear(); //safe as we've not got any outstanding or in progress reads, yet.
theSocketChannel.read(receivedByteBuffer,statefulStuff,this); //Basically "WAIT" on more data
Future<Integer> ignoredBytesWrittenResult = theSocketChannel.write(response);
}
}
else {
//connection was closed code
try {
statefulStuff.getLeft().shutdownOutput(); //maybe
}
catch (IOException somethingBad){
//fire
}
}
}
@Override
public void failed(Throwable exc, Pair<AsynchronousSocketChannel, ByteBuffer> attachment) {
//shout fire
}读操作最初是由来自处理程序中的completed方法的调用启动的,该调用来自服务器套接字上非常原始的异步accept,例如
public class AcceptForeverCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Pair<AsynchronousServerSocketChannel, Collection<AsynchronousSocketChannel>>> {
private final ReadForeverCompletionHandler readForeverAndEverAndSoOn = new ReadForeverCompletionHandler();
@Override
public void completed(AsynchronousSocketChannel result, Pair<AsynchronousServerSocketChannel, Collection<AsynchronousSocketChannel>> statefulStuff) {
statefulStuff.getLeft().accept(statefulStuff, this); //Accept more new connections please as we go
statefulStuff.getRight().add(result); //Collect these in case we want to for some reason, I don't know
ByteBuffer buffer = ByteBuffer.allocate(4098); //4k seems a nice number
result.read(buffer, Pair.of(result, buffer ),readForeverAndEverAndSoOn); //Kick off the read "forever"
}
@Override
public void failed(Throwable exc, Pair<AsynchronousServerSocketChannel, Collection<AsynchronousSocketChannel>> attachment) {
//Shout fire
}}
https://stackoverflow.com/questions/38012948
复制相似问题