首次连接后,Netty服务器不接受连接

时间:2016-01-05 11:00:22

标签: java netty nio

运行使用Netty的服务时遇到问题。它启动并正常工作,但只有一次。之后,不接受任何连接(它们会被立即删除)。

我有多个侦听器,每个侦听器只接受ony连接,之后就无法连接到同一个侦听器。

代码

这是我的Listener.java

public class Listener
{
    /* ... */

    public void run()
    {
        // check if there is any sense in running this listener
        if (this.address == null) {
            this.logger.info("\"{}\" was not enabled for connection, no point to start it.", this.getName());
            return;
        }

        final int maxPacketSize = this.getMaxPacketSize();
        final ChannelHandler handler = new DispatcherHandler<ContextType>(this.context, this.dispatcher);
        EventLoopGroup acceptors = new NioEventLoopGroup();
        EventLoopGroup workers = new NioEventLoopGroup();

        try {
            // network service configuration
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap
                .group(acceptors, workers)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_REUSEADDR, true)
                .handler(new LoggingHandler(Listener.class))
                .childHandler(new ChannelInitializer<Channel> () {
                    @Override
                    public void initChannel(Channel channel)
                    {
                        // network service configuration
                        channel.pipeline().addLast(
                            new LoggingHandler(handler.getClass()),
                            new LineBasedFrameDecoder(maxPacketSize),
                            new StringDecoder(StandardCharsets.UTF_8),
                            new StringEncoder(StandardCharsets.UTF_8),
                            handler
                        );
                    }
                });

            // start the server
            this.channel = bootstrap.bind(this.address).sync().channel();

            this.logger.info("Started."); // (1)

            // wait until channel is closed
            this.channel.closeFuture().sync();

            this.logger.info("Stopped."); // (2)
        } catch (InterruptedException error) {
            // don't worry - it's what we want in fact
            this.logger.error("Interrupted."); // (3)
            //CHECKSTYLE:OFF: IllegalCatchCheck
        } catch (Throwable error) {
            //CHECKSTYLE:ON: IllegalCatchCheck
            // this is not expected
            this.logger.error("IO connection error: {}.", error.getMessage()); // (4)
        } finally {
            this.logger.info("Finalizing."); // (5)
            this.channel = null;

            // close connections
            acceptors.shutdownGracefully();
            workers.shutdownGracefully();
            this.logger.info("Done."); // (6)
        }
    }
}

DispatcherHandler.java

public class DispatcherHandler<ContextType extends ContextInterface> extends ChannelInboundHandlerAdapter
{
    /* ... */

    @Override
    public void exceptionCaught(ChannelHandlerContext session, Throwable error)
    {
        this.logger.error(
            "Session ID {}: connection exteption.",
            session.name(),
            error
        );
        session.writeAndFlush(new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, null));
        session.close();
    }

    @Override
    public void channelRead(ChannelHandlerContext session, Object message)
    {
        JSONRPC2Response response = null;

        try {
            // parse the request
            JSONRPC2Request request = JSONRPC2Request.parse(message.toString());

            // dispatch it
            try {
                response = this.dispatcher.dispatch(request, this.context);
                //CHECKSTYLE:OFF: IllegalCatchCheck
            } catch (Throwable error) {
                //CHECKSTYLE:ON: IllegalCatchCheck
                // we DO WANT to catch all exceptions to avoid listener thread to die
                this.logger.error("Internal error.", error);
                response = new JSONRPC2Response(
                    JSONRPC2Error.INTERNAL_ERROR.appendMessage(": " + error.getMessage() + "."),
                    request.getID()
                );
            }
        } catch (JSONRPC2ParseException error) {
            response = new JSONRPC2Response(JSONRPC2Error.PARSE_ERROR, null);
            this.logger.error("Could not parse JSON-RPC request.");
        }

        // send response to client
        session.writeAndFlush(response.toJSONString());
    }
}

(我知道有些东西可以简化,它是一个仍然可以重现问题的快捷版本)

第一次会议

当我第一次使用nc localhost 6000(示例端口,无论什么)连接到服务器时,一切正常:

客户会话:

rafal.wrzeszcz@devel0:~$ nc -vv localhost 6000
localhost [127.0.0.1] 6000 (?) open
test
{"id":null,"error":{"code":-32700,"message":"JSON parse error"},"jsonrpc":"2.0"}^C
rafal.wrzeszcz@devel0:~$

服务器日志:

10:45:37.036 [nioEventLoopGroup-3-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0xd8fbf0ce, /0:0:0:0:0:0:0:0:6000] RECEIVED: [id: 0xb89181bd, /172.17.0.1:56485 => /172.17.0.2:6000]
10:45:37.056 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 => /172.17.0.2:6000] REGISTERED
10:45:37.056 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 => /172.17.0.2:6000] ACTIVE
10:45:39.285 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 => /172.17.0.2:6000] RECEIVED: test
10:45:39.293 [nioEventLoopGroup-11-1] ERROR pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - Could not parse JSON-RPC request.
10:45:39.294 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 => /172.17.0.2:6000] WRITE: {"id":null,"error":{"code":-32700,"message":"JSON parse error"},"jsonrpc":"2.0"}
10:45:39.297 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 => /172.17.0.2:6000] FLUSH
10:45:40.066 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 :> /172.17.0.2:6000] INACTIVE
10:45:40.067 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb89181bd, /172.17.0.1:56485 :> /172.17.0.2:6000] UNREGISTERED

(不要担心JSON-RPC错误,它的逻辑错误,正确的请求和响应它的工作方式完全相同)

第二次会议

但在关闭客户端连接后,再也无法连接。

客户会话:

rafal.wrzeszcz@devel0:~$ nc -vv localhost 6000
localhost [127.0.0.1] 6000 (x11) open
 sent 0, rcvd 0
rafal.wrzeszcz@devel0:~$

服务器日志:

10:45:40.539 [nioEventLoopGroup-3-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0xd8fbf0ce, /0:0:0:0:0:0:0:0:6000] RECEIVED: [id: 0x9e3dc0b1, /172.17.0.1:56487 => /172.17.0.2:6000]
10:45:40.545 [nioEventLoopGroup-11-2] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x9e3dc0b1, /172.17.0.1:56487 :> /172.17.0.2:6000] INACTIVE
10:45:40.547 [nioEventLoopGroup-11-2] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x9e3dc0b1, /172.17.0.1:56487 :> /172.17.0.2:6000] UNREGISTERED

- 编辑 -

Netty版本:4.0.33.Final

- 编辑2 -

只要连接处于活动状态,服务器就可以正常工作 - 我能够连续交换请求/响应,直到我关闭连接。

不要被IP地址混淆,它是转发到Docker的本地端口,应用程序在这里启动。它应该不是问题,我有 Apache MINA 应用程序以相同的方式运行,并尝试将其移植到Netty。

- 编辑3 -

从评论

应用更改后

客户端

rafal.wrzeszcz@devel0:~$ nc -vv localhost 6000
localhost [127.0.0.1] 6000 (x11) open
test
{"id":null,"error":{"code":-32700,"message":"JSON parse error"},"jsonrpc":"2.0"}test
{"id":null,"error":{"code":-32700,"message":"JSON parse error"},"jsonrpc":"2.0"}^C sent 10, rcvd 160
rafal.wrzeszcz@devel0:~$ nc -vv localhost 6000
localhost [127.0.0.1] 6000 (x11) open
sent 0, rcvd 0

其他消息后的服务器日志:

一切都是一样的,在我按[CTRL] + [C]

之前,父频道才会关闭
12:05:53.720 [chilldev.pl-frontend] INFO  pl.chilldev.commons.jsonrpc.daemon.Listener - Started.
12:05:58.075 [nioEventLoopGroup-6-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0x7cbe3265, /0:0:0:0:0:0:0:0:6000] RECEIVED: [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000]
12:05:58.095 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] REGISTERED
12:05:58.096 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] ACTIVE
12:06:02.122 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] RECEIVED: test
12:06:02.129 [nioEventLoopGroup-11-1] ERROR pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - Could not parse JSON-RPC request.
12:06:02.129 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] WRITE: {"id":null,"error":{"code":-32700,"message":"JSON parse error"},"jsonrpc":"2.0"}
12:06:02.132 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] FLUSH
12:06:03.414 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] RECEIVED: test
12:06:03.415 [nioEventLoopGroup-11-1] ERROR pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - Could not parse JSON-RPC request.
12:06:03.416 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] WRITE: {"id":null,"error":{"code":-32700,"message":"JSON parse error"},"jsonrpc":"2.0"}
12:06:03.416 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 => /172.17.0.2:6000] FLUSH
12:06:04.091 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 :> /172.17.0.2:6000] INACTIVE
12:06:04.091 [nioEventLoopGroup-11-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0xb284a0b1, /172.17.0.1:57853 :> /172.17.0.2:6000] UNREGISTERED
12:06:07.923 [nioEventLoopGroup-6-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0x7cbe3265, /0:0:0:0:0:0:0:0:6000] RECEIVED: [id: 0x0def7d2a, /172.17.0.1:57856 => /172.17.0.2:6000]
12:06:07.932 [nioEventLoopGroup-11-2] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0def7d2a, /172.17.0.1:57856 :> /172.17.0.2:6000] INACTIVE
12:06:07.933 [nioEventLoopGroup-11-2] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0def7d2a, /172.17.0.1:57856 :> /172.17.0.2:6000] UNREGISTERED
^C12:08:25.329 [Thread-14] INFO  pl.chilldev.commons.jsonrpc.daemon.AbstractApplication - Stopping…
12:08:25.335 [nioEventLoopGroup-6-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0x7cbe3265, /0:0:0:0:0:0:0:0:6000] CLOSE()
12:08:25.337 [chilldev.pl-frontend] INFO  pl.chilldev.commons.jsonrpc.daemon.Listener - Stopped.
12:08:25.337 [nioEventLoopGroup-6-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0x7cbe3265, /0:0:0:0:0:0:0:0:6000] UNREGISTERED
12:08:25.337 [chilldev.pl-frontend] INFO  pl.chilldev.commons.jsonrpc.daemon.Listener - Finalizing.
12:08:25.345 [chilldev.pl-frontend] INFO  pl.chilldev.commons.jsonrpc.daemon.Listener - Done.
  1. 已记录且服务器正在运行
  2. 在我终止服务器([CTRL] + [C])之前,不会记录
  3. 永远不会被记录
  4. 永远不会被记录
  5. 在套接字未绑定后记录
  6. 之后
  7. 记录
  8. - 编辑4 -

    LoggingHandler为第一个处理程序

    的示例日志
    12:18:52.396 [nioEventLoopGroup-3-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0xbec73d3f, /0:0:0:0:0:0:0:0:6000] RECEIVED: [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000]
    12:18:52.432 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] REGISTERED
    12:18:52.435 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] ACTIVE
    12:18:53.479 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] RECEIVED: 5B
            +-------------------------------------------------+
            |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
    +--------+-------------------------------------------------+----------------+
    |00000000| 74 65 73 74 0a                                  |test.           |
    +--------+-------------------------------------------------+----------------+
    12:18:53.495 [nioEventLoopGroup-9-1] ERROR pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - Could not parse JSON-RPC request.
    12:18:53.497 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] WRITE: 80B
            +-------------------------------------------------+
            |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
    +--------+-------------------------------------------------+----------------+
    |00000000| 7b 22 69 64 22 3a 6e 75 6c 6c 2c 22 65 72 72 6f |{"id":null,"erro|
    |00000010| 72 22 3a 7b 22 63 6f 64 65 22 3a 2d 33 32 37 30 |r":{"code":-3270|
    |00000020| 30 2c 22 6d 65 73 73 61 67 65 22 3a 22 4a 53 4f |0,"message":"JSO|
    |00000030| 4e 20 70 61 72 73 65 20 65 72 72 6f 72 22 7d 2c |N parse error"},|
    |00000040| 22 6a 73 6f 6e 72 70 63 22 3a 22 32 2e 30 22 7d |"jsonrpc":"2.0"}|
    +--------+-------------------------------------------------+----------------+
    12:18:53.499 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] FLUSH
    12:18:54.369 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] RECEIVED: 5B
            +-------------------------------------------------+
            |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
    +--------+-------------------------------------------------+----------------+
    |00000000| 74 65 73 74 0a                                  |test.           |
    +--------+-------------------------------------------------+----------------+
    12:18:54.370 [nioEventLoopGroup-9-1] ERROR pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - Could not parse JSON-RPC request.
    12:18:54.372 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] WRITE: 80B
            +-------------------------------------------------+
            |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
    +--------+-------------------------------------------------+----------------+
    |00000000| 7b 22 69 64 22 3a 6e 75 6c 6c 2c 22 65 72 72 6f |{"id":null,"erro|
    |00000010| 72 22 3a 7b 22 63 6f 64 65 22 3a 2d 33 32 37 30 |r":{"code":-3270|
    |00000020| 30 2c 22 6d 65 73 73 61 67 65 22 3a 22 4a 53 4f |0,"message":"JSO|
    |00000030| 4e 20 70 61 72 73 65 20 65 72 72 6f 72 22 7d 2c |N parse error"},|
    |00000040| 22 6a 73 6f 6e 72 70 63 22 3a 22 32 2e 30 22 7d |"jsonrpc":"2.0"}|
    +--------+-------------------------------------------------+----------------+
    12:18:54.372 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 => /172.17.0.2:6000] FLUSH
    12:18:55.174 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 :> /172.17.0.2:6000] INACTIVE
    12:18:55.181 [nioEventLoopGroup-9-1] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x0c8be37b, /172.17.0.1:58020 :> /172.17.0.2:6000] UNREGISTERED
    12:19:01.203 [nioEventLoopGroup-3-1] DEBUG pl.chilldev.commons.jsonrpc.daemon.Listener - [id: 0xbec73d3f, /0:0:0:0:0:0:0:0:6000] RECEIVED: [id: 0x9fa99c9e, /172.17.0.1:58022 => /172.17.0.2:6000]
    12:19:01.210 [nioEventLoopGroup-9-2] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x9fa99c9e, /172.17.0.1:58022 :> /172.17.0.2:6000] INACTIVE
    12:19:01.210 [nioEventLoopGroup-9-2] DEBUG pl.chilldev.commons.jsonrpc.netty.DispatcherHandler - [id: 0x9fa99c9e, /172.17.0.1:58022 :> /172.17.0.2:6000] UNREGISTERED
    

2 个答案:

答案 0 :(得分:3)

好的,想通了。 @zapl添加其他日志的想法促使我为io.netty添加了记录器。这是下次连接尝试后发生的事情:

12:25:53.007 [nioEventLoopGroup-8-2] WARN  io.netty.channel.ChannelInitializer - Failed to initialize a channel. Closing: [id: 0xed038b64, /172.17.0.1:58276 => /172.17.0.2:6000]
io.netty.channel.ChannelPipelineException: pl.chilldev.commons.jsonrpc.netty.DispatcherHandler is not a @Sharable handler, so can't be added or removed multiple times.

我认为它足够清楚;)。

答案 1 :(得分:0)

感谢Rafał为您answer

我还想分享其他信息,如果您使用的是非Sharable处理程序,则每次将其添加到管道时都需要创建一个新实例。

来自Netty 4.1 docs

  

public static @interface ChannelHandler.Sharable

     

表示带注释的ChannelHandler的相同实例可以   在没有竞赛的情况下多次添加到一个或多个ChannelPipelines   条件。

     

如果未指定此注释,则必须创建新的处理程序   每次将它添加到管道时,因为它已取消共享   状态,如成员变量。