Hi,
I am just writing some test applications using Netty so I can make sure I
understand the fundamentals before I start working on putting it into a
production environment and Im having a few issues with closing the
connection to the client from the server.
Here is what i have so far :-
I wire up the server using the following :-
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("decoder", new
LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE, 0, 2,
0, 2, true) );
ch.pipeline().addLast(new
ObjectDecoder(ClassResolvers.cacheDisabled(null)));
ch.pipeline().addLast("length", new LengthFieldPrepender(2));
ch.pipeline().addLast(new ObjectEncoder());
ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(10, 10, 0));
ch.pipeline().addLast(new MessageHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true); //Have tried without this
as well
//Bind And Start To Accept Incoming Connections
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
My server message handler is as follows :-
public class MessageHandler extends ChannelDuplexHandler {
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise)
throws Exception {
// TODO Auto-generated method stub
//super.disconnect(ctx, promise);
System.out.println("Client Reader From " + ctx.channel().remoteAddress() +
" has disconnected");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
if ( evt instanceof IdleStateEvent ) {
IdleStateEvent e = (IdleStateEvent)evt;
if ( e.state() == IdleState.READER_IDLE ) {
System.out.println("Client Reader From " + ctx.channel().remoteAddress() +
" is idle ");
//Close The Connection - Trying a few different things to try and force the
disconnect and see what happens
ctx.channel().close();
ctx.channel().deregister();
ctx.channel().disconnect();
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
}
private static final ChannelGroup channels = new DefaultChannelGroup(
GlobalEventExecutor.INSTANCE);
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
//super.channelRegistered(ctx);
//System.out.println("New Client Has Connected From " +
ctx.channel().remoteAddress() );
System.out.println("Client From " + ctx.channel().remoteAddress() + " is
Registered");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception
{
// TODO Auto-generated method stub
//super.channelUnregistered(ctx);
System.out.println("Client From " + ctx.channel().remoteAddress() + " has
Deregistered");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
//super.channelActive(ctx);
System.out.println("New Client Has Connected From " +
ctx.channel().remoteAddress() );
channels.add(ctx.channel());
System.out.println("There are currently " + channels.size() + " Channels
Connected");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
//super.channelInactive(ctx);
System.out.println("Client From " + ctx.channel().remoteAddress() + " is
Inactive");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws
Exception {
// TODO Auto-generated method stub
//super.channelRead(ctx, msg);
BaseMessage m = (BaseMessage)msg;
System.out.println("'" + channels.size() + "'" + " Received Mesage From " +
ctx.channel().remoteAddress() + " " + m.toString());
}
}
Then on the client side, I have the following :-
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("decoder", new
LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN,
Integer.MAX_VALUE, 0, 2, 0, 2, true));
ch.pipeline().addLast(new
ObjectDecoder(ClassResolvers.cacheDisabled(null)));
ch.pipeline().addLast("length", new LengthFieldPrepender(2));
ch.pipeline().addLast(new ObjectEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
// Start The Client
//I added the Listeners just to see what happened
and when they were called
//First try didnt have any of these listeners
ChannelFuture f = b.connect(this.ServerAddress, this.ServerPort).sync();
f.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture arg0) throws Exception {
if (arg0.isSuccess()) {
System.out.println("Client Has Connected");
addCloseListener(arg0.channel());
}
}
private void addCloseListener( Channel channel ) {
channel.closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture arg0) throws Exception {
System.out.println("Client Connection Lost ");
arg0.channel().close();
arg0.channel().deregister();
arg0.channel().disconnect();
}
});
}
});
// Wait Until The Connection Is Closed
f.channel().closeFuture().sync();
System.out.println("Client Is After Sync");
} catch ( Exception exc ) {
exc.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
System.out.println("Worker Group Shut Down Gracefully");
}
System.out.println("Client Is After Sync");
Then my client handler is as follows :-
public class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
//super.channelRegistered(ctx);
System.out.println("Client Channel is Registered");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception
{
// TODO Auto-generated method stub
//super.channelUnregistered(ctx);
System.out.println("Client Channel is Unregistered");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
super.channelInactive(ctx);
System.out.println("Client Channel is Inactive");
//Again Just testing here to see what happens..
ctx.channel().close().sync();
ctx.channel().close().syncUninterruptibly();
ctx.channel().closeFuture().sync();
ctx.channel().closeFuture().syncUninterruptibly();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
BaseMessage testMessage = new BaseMessage( 1, new Date() );
ctx.writeAndFlush( testMessage );
for ( int i=0; i < 10; i++) {
BaseMessage testMessage = new BaseMessage( 1, new Date() );
ctx.writeAndFlush( testMessage );
//Shouldnt really sleep in here but just for
testing should be ok
Thread.sleep(1000);
}
}
}
So essentially, my client connects and then sends through 10 messages and
then the server will detect the Channel Inactive event and at this point I
want the server to close the connection to the client. In a real world
scenario, I would send a request to see if the client is still online but
so I understand how it all goes together i thought I would try to force the
disconnect at this stage.
What is currently happening is as follows :-
Server detects that the client is connected and prints out the 10 messages
that are sent
Client From /127.0.0.1:22880 is Registered
New Client Has Connected From /127.0.0.1:22880
There are currently 1 Channels Connected
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:09 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:10 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:11 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:12 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:13 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:14 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:15 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:16 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:17 AEDT 2017
'1' Received Mesage From /127.0.0.1:22880 Message Type 1 - Sun Feb 26
16:44:18 AEDT 2017
The server then detects that the Client Reader is Idle
The server then detects that the Client Reader has Deregistered
The client then reconnects for some reason (this is the bit I am struggling
with)
Sun Feb 26 17:02:16 AEDT 2017 Client Reader From /127.0.0.1:24495 is idle
Sun Feb 26 17:02:16 AEDT 2017 Client From /127.0.0.1:24495 is Inactive
Sun Feb 26 17:02:16 AEDT 2017 Client From /127.0.0.1:24495 has Deregistered
Sun Feb 26 17:02:16 AEDT 2017 Client From /127.0.0.1:24549 is Registered
Sun Feb 26 17:02:16 AEDT 2017 New Client Has Connected From /127.0.0.1:24549
Sun Feb 26 17:02:16 AEDT 2017 There are currently 1 Channels Connected
The client then sends 10 more messages and then terminates
Sun Feb 26 17:01:57 AEDT 2017 Client Channel is Registered
Sun Feb 26 17:02:07 AEDT 2017 Client Has Connected
Sun Feb 26 17:02:16 AEDT 2017 Client Connection Lost
Sun Feb 26 17:02:16 AEDT 2017Client Is After First Sync
Sun Feb 26 17:02:16 AEDT 2017 Client Channel is Unregistered
Sun Feb 26 17:02:16 AEDT 2017 Worker Group Shut Down Gracefully
Sun Feb 26 17:02:16 AEDT 2017 Client Is After Finally
Sun Feb 26 17:02:16 AEDT 2017 Client Channel is Registered
Sun Feb 26 17:02:26 AEDT 2017 Client Has Connected
Sun Feb 26 17:02:35 AEDT 2017 Client Connection Lost
I must be missing something in the fundamental concepts as I thought the
calling ctx.channel().close(); in the server would force the client to
disconnect.
In a real world example, this reconnect is probably a good thing but I am
just trying to understand why it is happening.
Any assistance would be greatly appreciated.
Thanks,
Deacon.
--
You received this message because you are subscribed to the Google Groups
"Netty discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/netty/9580d249-9e86-4491-8e4b-48fdc7a210c9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.