如何将响应与Netty中的请求相关联?

时间:2016-09-03 17:46:38

标签: java request udp response netty

我的客户端有一个异步方法,它向服务器发送一个udp请求并返回 Promise 。我需要以某种方式将此Promise传递给我的一个入站处理程序,以便它能够将其标记为" done"然后通过 Promise.setSuccess(结果)发回响应。

你是怎么做到的?一旦入站处理程序收到响应,您如何将请求实例与处理程序的响应相关联?

本网站建议的一些方法对我来说也没有用处:

我的代码:

客户端:

private final EventLoopGroup group;
private final Bootstrap bootstrap;
private Channel channel;
private BlockingQueue<GameQuery> requestQueue;

public SourceServerQueryClient() {
    group = new NioEventLoopGroup();
    bootstrap = new Bootstrap();

    configureBootstrap(bootstrap);

    try {
        channel = bootstrap.bind(0).sync().channel();
    } catch (InterruptedException e) {
        log.error("InterruptedException", e);
    }
}

public void configureBootstrap(Bootstrap bootstrap) {
    //Contains our request queue
    requestQueue = new ArrayBlockingQueue<>(50);

    //Configure our bootstrap
    bootstrap.group(group).channel(NioDatagramChannel.class)
            .handler(new ChannelInitializer<NioDatagramChannel>() {
                @Override
                protected void initChannel(NioDatagramChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new ErrorHandler());
                    pipeline.addLast(new SourcePacketVerifierHandler());
                    pipeline.addLast(new SourceQueryEncoder());
                    pipeline.addLast(new MasterServerDecoder());
                    pipeline.addLast(new SourceServerInfoDecoder());
                    pipeline.addLast(new QueryResponseHandler(requestQueue));
                }
            });
}

public Promise<SourceServer> getServerDetails(InetSocketAddress address, QueryCallback<SourceServer> callback) {
    Promise<SourceServer> p = sendQuery(new ServerInfoQuery(address));
    p.addListener(future -> {
        if (future.isSuccess())
            callback.onReceive(p.get());
    });
    return p;
}

private Promise sendQuery(GameQuery query) {
    Promise promise = channel.eventLoop().newPromise();
    query.setPromise(promise);
    ChannelFuture f = null;
    try {
        requestQueue.put(query);
        f = channel.writeAndFlush(query).sync();
    } catch (InterruptedException e) {
        if (f != null)
            promise.setFailure(f.cause());
    }
    return promise;
}

public static void main(String[] args) throws InterruptedException {
    try (SourceServerQueryClient client = new SourceServerQueryClient()) {

        Promise query1 = client.getServerDetails(new InetSocketAddress("169.38.68.44", 27015), msg -> log.info("REPLY FROM SERVER: {}, EXPECTED: 169.38.68.44:27015", msg.toString()));
        Promise query2 = client.getServerDetails(new InetSocketAddress("112.211.234.23", 27016), msg -> log.info("REPLY FROM SERVER: {}, EXPECTED: 112.211.234.23:27016", msg.toString()));

        query2.awaitUninterruptibly();

        log.info("Done");
    } catch (IOException e) {
        log.error(e.getMessage(), e);
    }
}

入站处理程序:

public class QueryResponseHandler<T extends GameQuery> extends SimpleChannelInboundHandler<Object> {
    private static final Logger log = LoggerFactory.getLogger(QueryResponseHandler.class);
    private BlockingQueue<T> requestQueue;

    public QueryResponseHandler(BlockingQueue<T> requestQueue) {
        this.requestQueue = requestQueue;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.debug("From QueryResponseHandler: {}", msg);
        T request = requestQueue.poll(); 
        Promise p = request.getPromise();
        if (request != null) {
            p.setSuccess(msg);
        } else
            p.setFailure(new BufferUnderflowException());
    }
}

在我的测试中,我同时运行了两个请求。第一个不应该工作,因为它是一个死的服务器。第二个电话应该发回一个回复。

输出

REPLY FROM SERVER: 112.211.234.23:27016, EXPECTED: 169.38.68.44:27015

正如您所看到的,由于设计的原因,它没有像预期的那样成功。第一个查询收到了针对第二个查询的响应。

我已经没有想法如何正确设计,所以任何输入都将非常感谢!感谢。

2 个答案:

答案 0 :(得分:1)

可能会添加一个&#34; id&#34;请求,当你&#34;民意调查&#34;它,你确实可以得到正确的一个(所以通过一种队列地图,而不仅仅是一个队列)?

这个&#34; id&#34;可以基于你显示的输出信息(也许不是?)。

WDYT?

答案 1 :(得分:0)

由于UDP 无状态,您需要提供一条消息ID,以便能够关联并跟进对请求的回复。

虽然如果你想进行有状态的沟通,为什么不简单地使用TCP?