具有AsynchronousServerSocketChannel的多线程服务器 [英] Multithreaded Server with AsynchronousServerSocketChannel

查看:391
本文介绍了具有AsynchronousServerSocketChannel的多线程服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须实现一个服务器,该服务器应接受更多连接.不用更深入的思考,我决定使用新的JAVA NIO.2类.

I have to implement a Server which should accept more connections. Without any deeper thoughts i decided to use the new JAVA NIO.2 classes.

我当前的方法是:

final Semaphore wait = new Semaphore(1);
while(true){
        wait.acquire();
        this.asyncSocket.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
            @Override
            public void completed(AsynchronousSocketChannel result, Void attachment) {
                wait.release();
                asyncSocket.accept(null, this);
                ...
             }
             ...
        }
}

如果我不添加信号灯,则会得到一个AcceptPendingException.它有效,但是,我不知道这是否是实现可处理更多开放套接字的服务器的正确方法.

if i don't add the semaphore, i get an AcceptPendingException. It works, however, i don't know if thats the proper way to implement a server which can handle more open sockets.

另一种方法是:

final Semaphore wait = new Semaphore(1);
    while(true){
        wait.acquire();
        final Future<AsynchronousSocketChannel> futureChannel = this.asyncSocket.accept();

        this.exec.execute(new Runnable() {
            @Override
            public void run() {
                try (final AsynchronousSocketChannel clientChannel = futureChannel.get()) {
                    wait.release();
                    try (ObjectInputStream ois = new ObjectInputStream(Channels.newInputStream(clientChannel))) {
                        final Command cmd = (Command) ois.readObject();

                        cmd.execute(util, clientChannel, null, logger).run();
                    }
                } catch (IOException | InterruptedException | ClassNotFoundException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        });

为什么我对这两种解决方案都不满意? 不幸的是,在这两种实现中,服务器都会在状态TIME_WAIT中留下很多打开的套接字,尽管我也在服务器端和客户端将其关闭了.

Why i'm unhappy with both solutions? Unfortunately, in both implementations, the server leaves a lot of open sockets in state TIME_WAIT, although i'm closing the it on the server as well on the client side..

实际上我有两个问题:

  • 使用AsynchronousServerSocketChannel来实现接受更多连接的服务器的正确方法是什么.
  • 如何摆脱处于TIME_WAIT状态的打开的套接字
  • Whats a proper way to use AsynchronousServerSocketChannel to implement a Server wich accepts more connections.
  • How to get rid of the open sockets in state TIME_WAIT

private <T extends Serializable> T sendCommand(final Command<T> command) throws ExecutionException, InterruptedException, IOException, ClassNotFoundException {
    T result = null;

    try (final AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(channelGroup)) {
        channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        channel.connect(this.mwInfo.getNextMiddleware()).get();

        final OutputStream os = Channels.newOutputStream(channel);
        final InputStream is = Channels.newInputStream(channel);

        try (final ObjectOutputStream oos = new ObjectOutputStream(os)) {
            oos.writeObject(command);
            oos.flush();

            try (final ObjectInputStream ois = new ObjectInputStream(is)) {
                result = (T) ois.readObject();
            }
        }
    }

    return result;
}

提前谢谢!

推荐答案

我只能回答第二个问题(不了解Java套接字的具体知识).要摆脱这些套接字,您必须在套接字上实现优雅关机"协议.也就是说,一个套接字在发送时关闭,另一个套接字在发送时关闭,而不是套接字在recv上关闭.这将确保没有套接字将保持在TIME_WAIT状态.

I can only answer the second question (no knowledge of Java socket specifics). To get rid of those sockets you must implement 'graceful shutdown' protocol on socket. That is, one socket does shutdown on send, another one does shutdown on send upon seing that, than sockets to shutdown on recv. This will ensure no sockets will stay in TIME_WAIT state.

另一种选择是摆弄套接字的SO_LINGER选项,但这是不明智的.

The other option would be to fiddle with SO_LINGER option of the socket, but this is ill-advised.

我还注意到,人们似乎只是将SO_REUSEADDR用作通用解决方案.您无法绑定到端口吗?指定SO_REUSEADDR,您的所有问题都将消失……这是错误的!如果SO_REUSEADDR是通用解决方案,为什么默认情况下不将其设置为ON?因为很危险.当您指定SO_REUSEADDR时,您将在同一端口上创建另一个套接字,现在您可以开始查看来自先前连接的消息了!当然,这不太可能发生.但这有可能发生!想象一下,排除故障是什么样的错误!

I also notice, that people seems to just use SO_REUSEADDR as a universal solution. You can't bind to a port? Specify SO_REUSEADDR and all your problems will go away... and this is wrong! If SO_REUSEADDR is universal solution, why is it not ON by default? Because it is dangerous. When you specify SO_REUSEADDR, you create another socket on the same port and now you can start seeing messages from the previous connection! This is not very likely to happen, of course. But it can happen! Imagine what kind of bug would it be to troubleshoot!

这篇关于具有AsynchronousServerSocketChannel的多线程服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆