Java 如何使用异步socketchannel#循环读取或递归读取?
我找到了一个示例,但它并没有特别有用,因为它没有提供完整的示例 问题:如何使用固定大小的缓冲区读取未知长度的数据 第一次尝试(读取一次):Java 如何使用异步socketchannel#循环读取或递归读取?,java,nio2,Java,Nio2,我找到了一个示例,但它并没有特别有用,因为它没有提供完整的示例 问题:如何使用固定大小的缓冲区读取未知长度的数据 第一次尝试(读取一次): final int bufferSize=1024; 最终SocketAddress地址=/*ip:port*/; final ThreadFactory ThreadFactory=Executors.defaultThreadFactory(); final ExecutorService executor=Executors.newCachedThre
final int bufferSize=1024;
最终SocketAddress地址=/*ip:port*/;
final ThreadFactory ThreadFactory=Executors.defaultThreadFactory();
final ExecutorService executor=Executors.newCachedThreadPool(threadFactory);
final AsynchronousChannelGroup AsynchronousChannelGroup=AsynchronousChannelGroup.withCachedThreadPool(执行器,5);
最终AsynchronousSocketChannel客户端=AsynchronousSocketChannel.open(AsynchronousChannelGroup);
client.connect(address).get(5,TimeUnit.SECONDS)//阻塞,直到建立连接
//写下请求
Integer BytesWrite=client.write(StandardCharsets.US_ASCII.encode(“二进制格式的自定义请求”)).get();
//阅读回复
final ByteBuffer readTo=ByteBuffer.allocate(缓冲区大小);
最终StringBuilder responseBuilder=新StringBuilder();
read(readTo,readTo,new CompletionHandler(){
公共无效已完成(整数字节读取,字节缓冲区){
flip();
append(StandardCharsets.US_ASCII.decode(buffer.toString());
试一试{
client.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
公共作废失败(可丢弃的exc、ByteBuffer附件){
试一试{
client.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
);
asyncChannelGroup.awaitTermination(5,时间单位秒);
asyncChannelGroup.shutdown();
System.out.println(responseBuilder.toString());
在
bytesRead!=-1
(即到达流的末尾)?在我看来,最简单的方法是将此代码拆分为自己的方法,然后让CompletionHandler在字节读取时递归调用该方法!=-1
。这样,您可以分离代码的责任,避免在异步读取运行时“忙等待”或使用Thread.sleep()的必要性。当然,您也可以添加一个case whenbytesRead==-1
来处理读入的数据。由于回调方法失败和完成在不受您控制的线程上运行,我不会做任何延长的事情
我知道,即使流已到达其结尾(bytesRead==-1
),您也希望继续侦听套接字中的新字节。
将read
方法置于while(true)
循环中。在它里面,收听由失败
和完成
方法设置的同步
字段。让我们称之为myBytesRead
为了能够停止无休止的读取,请将while(true)
替换为其他一些synchronized
条件
private static final BYTES_READ_INIT_VALUE = Integer.MIN_VALUE;
private static final BYTES_READ_COMPLETED_VALUE = -1;
private static final BYTES_READ_FAILED_VALUE = -2;
private Integer myBytesRead = BYTES_READ_INIT_VALUE;
private void setMyBytesRead(final Integer bytesRead) {
synchronized(myBytesRead) {
this.myBytesRead = bytesRead;
}
}
private Integer getMyBytesRead() {
synchronized(myBytesRead) {
return myBytesRead;
}
}
...
// in your method
while (true) {
final int lastBytesRead = getMyBytesRead();
if (lastBytesRead == BYTES_READ_FAILED_VALUE) {
// log failure and retry?
} else if (lastBytesRead != BYTES_READ_COMPLETED_VALUE) {
// Thread.sleep( a while ); to avoid exhausting CPU
continue;
}
// else lastBytesRead == BYTES_READ_COMPLETED_VALUE and you can start a new read operation
client.read(readTo, readTo, new CompletionHandler<Integer, ByteBuffer>() {
public void completed(Integer bytesRead, ByteBuffer buffer) {
setMyBytesRead(bytesRead);
buffer.flip();
responseBuilder.append(StandardCharsets.US_ASCII.decode(buffer).toString());
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void failed(Throwable exc, ByteBuffer attachment) {
try {
setMyBytesRead(BYTES_READ_FAILED_VALUE);
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
);
}
private static final BYTES\u READ\u INIT\u VALUE=Integer.MIN\u VALUE;
私有静态最终字节\u读取\u完成\u值=-1;
私有静态最终字节\u读取\u失败\u值=-2;
私有整数myBytesRead=BYTES\u READ\u INIT\u值;
私有void setMyBytesRead(最终整数bytesRead){
已同步(myBytesRead){
this.myBytesRead=bytesRead;
}
}
私有整数getMyBytesRead(){
已同步(myBytesRead){
返回myBytesRead;
}
}
...
//用你的方法
while(true){
final int lastBytesRead=getMyBytesRead();
if(lastBytesRead==字节\u读取\u失败\u值){
//记录失败并重试?
}else if(lastBytesRead!=字节\u读取\u完成\u值){
//睡眠(一段时间);避免耗尽CPU
继续;
}
//else lastBytesRead==BYTES\u READ\u COMPLETED\u值,您可以启动新的读取操作
read(readTo,readTo,new CompletionHandler(){
公共无效已完成(整数字节读取,字节缓冲区){
设置我的字节读(字节读);
flip();
append(StandardCharsets.US_ASCII.decode(buffer.toString());
试一试{
client.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
公共作废失败(可丢弃的exc、ByteBuffer附件){
试一试{
setMyBytesRead(字节\读取\失败\值);
client.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
);
}
我的初次尝试:
package com.example;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
public class LoopingReader implements Callable<String> {
final AsynchronousSocketChannel client;
final String responseTerminator;
final StringBuilder responseBuilder;
LoopingReader(
AsynchronousSocketChannel client,
String responseTerminator
) {
this.client = client;
this.responseTerminator = responseTerminator;
responseBuilder = new StringBuilder();
}
public String call() {
boolean doLoop;
do {
int bytesRead = executeIteration();//blocking
boolean didReachEndOfStream = bytesRead == -1;
boolean didEncounterResponseTerminator = responseBuilder.indexOf(responseTerminator) != -1;
doLoop = !didReachEndOfStream && !didEncounterResponseTerminator;
} while(doLoop);
return responseBuilder.toString();
}
int executeIteration() {
final ByteBuffer buffer = ByteBuffer.allocate(256);//use pool here
final int bytesRead;
try {
bytesRead = client.read(buffer).get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Failed to read", e);
}
decodeAndAppend(buffer);
return bytesRead;
}
void decodeAndAppend(ByteBuffer buffer) {
buffer.flip();
responseBuilder.append(StandardCharsets.US_ASCII.decode(buffer));
}
}
package.com.example;
导入java.nio.ByteBuffer;
导入java.nio.channels.AsynchronousSocketChannel;
导入java.nio.charset.StandardCharset;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutionException;
公共类LoopingReader实现了可调用{
最终异步socketchannel客户端;
最终串响应器;
最终StringBuilder responseBuilder;
循环读取器(
异步socketchannel客户端,
串响应器
) {
this.client=client;
this.responseTerminator=responseTerminator;
responseBuilder=新的StringBuilder();
}
公共字符串调用(){
布尔doLoop;
做{
int bytesRead=执行操作();//阻塞
布尔DIDRACHENDOFSTREAM=字节读取==-1;
布尔值didEncounterResponseTerminator=responseBuilder.indexOf(responseTerminator)!=1;
doLoop=!DidReachenOfStream&!didEncounterResponseTerminator;
}while(doLoop);
返回responseBuilder.toString();
package com.example;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
public class LoopingReader implements Callable<String> {
final AsynchronousSocketChannel client;
final String responseTerminator;
final StringBuilder responseBuilder;
LoopingReader(
AsynchronousSocketChannel client,
String responseTerminator
) {
this.client = client;
this.responseTerminator = responseTerminator;
responseBuilder = new StringBuilder();
}
public String call() {
boolean doLoop;
do {
int bytesRead = executeIteration();//blocking
boolean didReachEndOfStream = bytesRead == -1;
boolean didEncounterResponseTerminator = responseBuilder.indexOf(responseTerminator) != -1;
doLoop = !didReachEndOfStream && !didEncounterResponseTerminator;
} while(doLoop);
return responseBuilder.toString();
}
int executeIteration() {
final ByteBuffer buffer = ByteBuffer.allocate(256);//use pool here
final int bytesRead;
try {
bytesRead = client.read(buffer).get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Failed to read", e);
}
decodeAndAppend(buffer);
return bytesRead;
}
void decodeAndAppend(ByteBuffer buffer) {
buffer.flip();
responseBuilder.append(StandardCharsets.US_ASCII.decode(buffer));
}
}
class SomeUtilClass {
public interface Processor<T> {
boolean process(Integer byteCount, ByteBuffer buffer);
T result();
}
public static <T> ListenableFuture<T> read(
final AsynchronousSocketChannel delegate,
final Processor<T> processor,
ByteBuffer buffer
) {
final SettableFuture<T> resultFuture = SettableFuture.create();
delegate.read(buffer, buffer, new Handler<T, Integer, ByteBuffer>(resultFuture) {
public void completed(Integer bytesRead, ByteBuffer buffer) {
buffer.flip();
if(processor.process(bytesRead, buffer)) {
buffer.clear();
delegate.read(buffer, buffer, this);
} else {
resultFuture.set(processor.result());
}
}
});
return resultFuture;
}
}