首次连接后 Netty 服务器不接受连接
Netty server doesn't accept connections after first connect
我有一个问题 运行 使用 Netty 的服务。它启动并正常工作,但只有一次。之后没有连接被接受(它们被立即丢弃)。
我有多个监听器,每个监听器只接受一个连接,之后就不可能连接到同一个监听器了。
代码
这是我的 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());
}
}
(我知道有些东西可以简化,这是一个仍然重现问题的快捷版本)
第一个session
当我第一次使用 nc localhost 6000
(示例端口,随便什么)连接到服务器时,一切正常:
客户端session:
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 错误,这是逻辑错误,通过正确的请求和响应,它的工作方式完全相同)
第二个session
但是我关闭客户端连接后就无法再连接了
客户端session:
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 --
只要连接处于活动状态,服务器就可以正常工作 - 我可以连续交换 requests/responses,直到我关闭连接。
不要被 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
服务器在附加消息后记录:
一切都是一样的,parent频道没有关闭直到我按下[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.
- 已登录且服务器 运行
- 在我终止服务器之前不会记录 (
[CTRL] + [C]
)
- 从未记录
- 从未记录
- 套接字解除绑定后记录
- 之后记录
-- 编辑 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
好的,明白了。 @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.
我觉得已经够清楚了 ;).
感谢拉法尔 。
我还想分享更多信息,如果您使用的是非共享处理程序,则每次将其添加到管道时都需要创建一个新实例。
public static @interface ChannelHandler.Sharable
Indicates that the same instance of the annotated ChannelHandler can
be added to one or more ChannelPipelines multiple times without a race
condition.
If this annotation is not specified, you have to create a new handler
instance every time you add it to a pipeline because it has unshared
state such as member variables.
我有一个问题 运行 使用 Netty 的服务。它启动并正常工作,但只有一次。之后没有连接被接受(它们被立即丢弃)。
我有多个监听器,每个监听器只接受一个连接,之后就不可能连接到同一个监听器了。
代码
这是我的 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());
}
}
(我知道有些东西可以简化,这是一个仍然重现问题的快捷版本)
第一个session
当我第一次使用 nc localhost 6000
(示例端口,随便什么)连接到服务器时,一切正常:
客户端session:
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 错误,这是逻辑错误,通过正确的请求和响应,它的工作方式完全相同)
第二个session
但是我关闭客户端连接后就无法再连接了
客户端session:
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 --
只要连接处于活动状态,服务器就可以正常工作 - 我可以连续交换 requests/responses,直到我关闭连接。
不要被 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
服务器在附加消息后记录:
一切都是一样的,parent频道没有关闭直到我按下[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.
- 已登录且服务器 运行
- 在我终止服务器之前不会记录 (
[CTRL] + [C]
) - 从未记录
- 从未记录
- 套接字解除绑定后记录
- 之后记录
-- 编辑 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
好的,明白了。 @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.
我觉得已经够清楚了 ;).
感谢拉法尔
我还想分享更多信息,如果您使用的是非共享处理程序,则每次将其添加到管道时都需要创建一个新实例。
public static @interface ChannelHandler.Sharable
Indicates that the same instance of the annotated ChannelHandler can be added to one or more ChannelPipelines multiple times without a race condition.
If this annotation is not specified, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.