Netty 4.2ソケット通信コードをssl(自己署名証明書)で実行しています。SSLを使用したNettyサーバー接続の呼び出し後のクライアント接続の破棄
問題: クライアントがSSLを使用してサーバーに接続しようとすると、サーバーはすぐに接続を切断します。サーバーはすぐにchannelUnregistered()メソッドをトリガーします。
私が気づいたのは、サーバーが始動した後、クライアントの接続が維持され、うまく動作することです。しかし、クライアントが切断され、サーバーに再び接続しようとすると、すぐに接続が切断されます。
SSLを使用しないと、問題なく正常に動作します。
クライアントコード:
public Channel initializeNettySocket()
{
group = new NioEventLoopGroup();
try
{
ClientAdapterInitializer clientAdapterInitializer = null;
if (ServerSettings.isUseSSL())
{
// SSLEngine engine = SSLContextFactory.getClientContext().createSSLEngine();
SSLEngine engine = SSLContext.getDefault().createSSLEngine(host,port);
engine.setUseClientMode(true);
clientAdapterInitializer = new ClientAdapterInitializer(engine);
}
else
{
clientAdapterInitializer = new ClientAdapterInitializer();
}
Bootstrap bootstrap = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(clientAdapterInitializer);
channel = bootstrap.connect(host,port).sync().channel();
Thread.sleep(3000);
setChannel(channel);
}
catch (Exception e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}
return channel;
}
public class ClientAdapterInitializer extends ChannelInitializer<SocketChannel>
{
private SSLEngine sslCtx = null;
public ClientAdapterInitializer(SSLEngine sslCtx)
{
this.sslCtx = sslCtx;
}
public ClientAdapterInitializer()
{
}
@Override
protected void initChannel(SocketChannel channel) throws Exception
{
ChannelPipeline pipeline = channel.pipeline();
if (ServerSettings.isUseSSL())
{
// Add SSL handler first to encrypt and decrypt everything.
// In this example, we use a bogus certificate in the server side
// and accept any invalid certificates in the client side.
// You will need something more complicated to identify both
// and server in the real world.
//pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT));
pipeline.addLast(new SslHandler(sslCtx));
}
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ClientAdapterHandler());
}
サーバ側コード
public class ServerAdapterInitializer extends ChannelInitializer<SocketChannel>
{
private SSLEngine sslEngine;
public ServerAdapterInitializer(SSLEngine sslEngine)
{
this.sslEngine = sslEngine;
}
public ServerAdapterInitializer()
{
}
@Override
protected void initChannel(SocketChannel channel) throws Exception
{
ChannelPipeline pipeline = channel.pipeline();
if (sslEngine != null)
{
pipeline.addLast(new SslHandler(sslEngine));
}
Listeners.getInstance().getAllListeners().size();
RTReceiverAdapterHandler rtReceiverAdapterHandler = new RTReceiverAdapterHandler();
pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 10)); // add
// with
// name
pipeline.addLast("decoder", new MyStringDecoder(rtReceiverAdapterHandler));
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", rtReceiverAdapterHandler);
}
}
public class RTReceiverAdapterHandler extends ChannelInboundHandlerAdapter
{
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
if (ServerSettings.isUseSSL())
{
// Once session is secured, send a greeting and register the channel
// to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(new GenericFutureListener<Future<Channel>>()
{
@Override
public void operationComplete(Future<Channel> future) throws Exception
{
ctx.writeAndFlush("Welcome!\n");
ctx.writeAndFlush("Your session is protected by " + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite()
+ " cipher suite.\n");
channels.add(ctx.channel());
}
});
}
else
{
super.channelActive(ctx);
}
}
}
次のオプションを使用してデバッグをログに記録できます。System.setProperty( "javax.net.debug"、 "ssl"); System.setProperty( "ssl.debug"、 "true"); –
OK、これを試します –
有効なプロトコルと暗号を有効にしました。私が得ていた問題はなくなった。しかし、今度は、クライアントと接続したサーバーは数秒待って接続を閉じ、クライアントで例外 - > _nioEventLoopGroup-2-1、致命的なエラー:80:ピアのclose_notifyを受信する前に受信を閉じた:切り捨ての可能性がある_ –