Java 收到响应时Netty ChannelFuture超时
我是netty的新手,我有一个用netty开发的tcp客户端应用程序。当我使用future从服务器获取异步响应时,会返回一些响应,但future并没有完成超时。TCPClient类,如下所示Java 收到响应时Netty ChannelFuture超时,java,spring,netty,future,Java,Spring,Netty,Future,我是netty的新手,我有一个用netty开发的tcp客户端应用程序。当我使用future从服务器获取异步响应时,会返回一些响应,但future并没有完成超时。TCPClient类,如下所示 public TcpClient { public boolean connect(Host host) { try { Bootstrap clientBootstrap = new Bootstrap() .grou
public TcpClient {
public boolean connect(Host host) {
try {
Bootstrap clientBootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE,true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 50)
.remoteAddress(new InetSocketAddress(host.getIp(), host.getPort()))
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) {
socketChannel.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(2146));
FalconClientHandler falconClientHandler = new FalconClientHandler(host);
host.setFalconClientHandler(falconClientHandler);
socketChannel.pipeline().addLast(falconClientHandler);
}
});
channelFuture = clientBootstrap.connect().sync(); //BAŞARI İLE BAĞLANDI
channelFuture.channel().closeFuture().sync();
return host.isActive();
} catch (Exception e) {
log.info("Connection timed out --> " + e);
host.setActive(false);
return false;
} finally {
host.setActive(false);
}
}
public synchronized ResponseFuture send(long transactionId,String message) {
final Map<Long,ResponseFuture> responseFuture = new ConcurrentHashMap<>();
responseFuture.put(transactionId,new ResponseFuture());
if (!hostSelector.getUpHostList().isEmpty()) {
int hostCount = hostSelector.getUpHostList().size();
Host host;
host = hostSelector.getUpHostList().get(index.incrementAndGet() % hostCount);
if (host.isActive()) {
int headerLength = Integer.parseInt(message.substring(8, 12));
log.info("[{}] Host {} Tcp Request",message.substring(52, 52 + headerLength),host.getIp());
channelFuture.addListener((GenericFutureListener<ChannelFuture>) future -> {
log.info("[{}] Tcp request added to map",transactionId);
channelFuture.channel().pipeline().get(FalconClientHandler.class).setResponseFuture(responseFuture);
byte[] byteBuffer = message.getBytes();
channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer(byteBuffer));
});
}
} else {
log.error("AYAKTA HOST YOK");
}
return responseFuture.get(transactionId);
}
}
ResponseFuture responseFuture = falconClient.send(Long.valueOf(transactionId), finalMessage);
try {
Object obj = responseFuture.get(ddaTimeoutParam, TimeUnit.MILLISECONDS);
if(obj!=null) {
response = obj.toString();
ddaDelta = System.currentTimeMillis()-ddaRequestStartTime;
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.warn("[{}] DDA timeout. Timeout parameter: {}",transactionId,ddaTimeoutParam);
responseFuture.cancel(true);
response = "TIMEOUT";
ddaDelta = System.currentTimeMillis()-ddaRequestStartTime;
}
Response future是一个基本的future实现类。提出并获得这样的方法
public class ResponseFuture implements Future<String> {
private volatile State state = State.WAITING;
ArrayBlockingQueue<String> blockingResponse = new ArrayBlockingQueue<String>(1);
private enum State {
WAITING,
DONE
}
@Override
public String get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
final String responseAfterWait = blockingResponse.poll(timeout, unit);
if (responseAfterWait == null) {
throw new TimeoutException();
}
return responseAfterWait;
}
public void set(String msg) {
if (state == State.DONE) {
return;
}
try {
blockingResponse.put(msg);
state = State.DONE;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
My Handler class for receive server response message like following;
public class FalconClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
private ChannelHandlerContext ctx;
private Map<Long,ResponseFuture> responseFuture;
public synchronized void setResponseFuture(Map<Long,ResponseFuture> responseFuture) {
log.info("{} ResponseFuture setted",responseFuture.keySet());
this.responseFuture = responseFuture;
}
@Override
public void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf in) {
String input = in.toString(CharsetUtil.UTF_8);
String transactionKey = input.substring(52, 66).trim();
if(responseFuture.get(Long.valueOf(transactionKey))!=null)
responseFuture.get(Long.valueOf(transactionKey)).set(input);
else
log.info("[{}] Tcp Response map is empty",transactionKey);
}
}
公共类响应未来实现未来{
私有易失性状态State=State.WAITING;
ArrayBlockingQueue blockingResponse=新的ArrayBlockingQueue(1);
私有枚举状态{
等待,
完成
}
@凌驾
公共字符串get(长超时,时间单位)抛出InterruptedException,
ExecutionException,TimeoutException{
最终字符串responseAfterWait=blockingResponse.poll(超时,单位);
if(responseAfterWait==null){
抛出新的TimeoutException();
}
返回responseAfterWait;
}
公共无效集(字符串消息){
if(state==state.DONE){
返回;
}
试一试{
blockingResponse.put(味精);
state=state.DONE;
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
接收服务器响应消息的我的处理程序类,如下所示;
公共类FalconClientHandler扩展了SimpleChannelInboundHandler{
专用通道HandlerContext ctx;
私有地图响应未来;
公共同步的void setResponseFuture(映射responseFuture){
log.info(“{}ResponseFuture setted”,ResponseFuture.keySet());
this.responseFuture=responseFuture;
}
@凌驾
public void channelRead0(ChannelHandlerContext ChannelHandlerContext,ByteBuf in){
字符串输入=in.toString(CharsetUtil.UTF_8);
String transactionKey=input.substring(52,66).trim();
if(responseFuture.get(Long.valueOf(transactionKey))!=null)
responseFuture.get(Long.valueOf(transactionKey)).set(input);
其他的
log.info(“[{}]Tcp响应映射为空”,transactionKey);
}
}
当我在高负载(如每秒30个事务)下运行此代码时,tcp响应从netty服务器返回,但未来的get方法收到超时。这种情况不会发生在每个请求上,例如%20请求在40个tps中30个tps%50请求失败时失败。负载下会发生什么 您的代码是不可复制的,因此很难在这方面提供帮助。一个关键点是,由EventLoopGroup处理的任何内容,线程都不应该阻止。另外,由于我无法运行您的代码对其进行测试,您是否也查看了
send(longtransactionid,String message)
在另一个请求已挂起的情况下调用它时,根据行.setResponseFuture(responseFuture)如何反应代码>,似乎它只能同时处理1个请求感谢响应问题与未来承诺相关,因此当此行responseFuture.get(Long.valueOf(transactionKey)).set(input)时在responseFuture.get和inputs之前工作会混合每个事务id。我如何一次只提供一个请求?您的代码不可复制,因此很难在这方面提供帮助。一个关键点是,由EventLoopGroup处理的任何内容,线程都不应该阻止。另外,由于我无法运行您的代码对其进行测试,您是否也查看了send(longtransactionid,String message)
在另一个请求已挂起的情况下调用它时,根据行.setResponseFuture(responseFuture)如何反应代码>,似乎它只能同时处理1个请求感谢响应问题与未来承诺相关,所以当此行responseFuture.get(Long.valueOf(transactionKey)).set(input)在responseFuture.get之前工作时,输入和每个事务id混合在一起。如何一次只处理1个请求?