How to Close channel when Main Application is blocked via ChannelFuture.channel().closeFuture().sync()

576 views
Skip to first unread message

L_DisplayName

unread,
Jan 31, 2017, 10:03:46 PM1/31/17
to Netty discussions
Greetings All, 
I have a FileSender Application that sends data to a server via a FileHandler (not shown here, but in previous post). All data is successfully sent and received, but to keep the FileSenderHandler from terminating early, I had to use the following statement: f.channel().closeFuture().sync(); in the FileSender.java Application (the main application) which blocks the main program preventing it from terminating as well as the FileSenderHandler Application. My Question is: HOW CAN I CLOSE THE CHANNEL AND UNBLOCK THE MAIN FileSender APPLICATION ONCE THE FileSenderHandler HAS SUCCESSFULLY SENT AND ACKNOWLEDGED ALL DATA? I currently can't do it within the FileSender class because the application is blocked at that point. I tried closing the channel within the FileSenderHandler class by doing ctx.channel().close() which I thought would unblock the FileSender App since the App is waiting on the close channel event but that didn't work, I also tried closing the channel on the receiver/server side by doing ctx.channel().close() within the FileReceiverHandler but that still didn't unblock the FileSender App. Any help or suggestions would be greatly appreciated.

FileSender.java - Bootstraps the channel and connects this client/host to another host
public static void main(String[] args) throws Exception {
 // Configure the client/ File Sender
 EventLoopGroup group = new NioEventLoopGroup();
 try {
 Bootstrap b = new Bootstrap();
 b.group(group)
 .channel(NioSocketChannel.class)
 .option(ChannelOption.TCP_NODELAY, true)
 .handler(new FileSenderInitializer());

 // Start the client.
 ChannelFuture f = b.connect(HOST, PORT).sync();

 // Wait until the connection is closed.
 f.channel().closeFuture().sync();
 } finally {
 // Shut down the event loop to terminate all threads.
 group.shutdownGracefully();
 }
 }
}

L_DisplayName

unread,
Feb 1, 2017, 12:08:09 PM2/1/17
to Netty discussions
The reason I need to unblock the application is so I can print the throughput to the console after all data has been sent and acknowledged.  if I have multiple data channels and the program is blocked only the first data channel handler throughput will be printed. So the FileSender.java would look as below. But even if I have one data Channel and I attempt to close the channel in FileSenderHandler, the main app (FileSender.java) still block and hangs on ChannelFuture.channel().closeFuture().sync(); To quit, I must type control C at the terminal. 
ANY IDEAS ON HOW I CAN UNBLOCK THE MAIN APP ONCE ALL DATA IS SENT AND RECEIVED?

FileSender.java - Bootstraps the channel and connects this client/host to another host
public static void main(String[] args) throws Exception {
 // Configure the client/ File Sender
 EventLoopGroup group = new NioEventLoopGroup();
 try {
for (int i =0; i<numOfDataChannels; i++) {
 Bootstrap b = new Bootstrap();
 b
.group(group)
 
.channel(NioSocketChannel.class)
 
.option(ChannelOption.TCP_NODELAY, true)
 
.handler(new FileSenderInitializer());

 
// Start the client.
 
ChannelFuture f = b.connect(HOST, PORT).sync();
 
addChannelFutureToList(f);
}

 
// Wait until the connection is closed for each data channel, but also who can actually close the channel
for ( ChannelFuture f: channelFutureList){
 
f.channel().closeFuture().sync();
}

//When Channel is closed PRINT THROUGHPUT OF ALL THE DATA CHANNELS
printThroughput();
 } finally {
 
// Shut down the event loop to terminate all threads.
 
group.shutdownGracefully();
 
}
 
}
}

FileSenderHandler.java - Handles I/O Channel events such as Read/Write
public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
try {
 .
 .
 //After received msg Ack, close the channel, this should unblock the main application (FileSender.java) since after closing the channel closeFuture will be fulfilled
 ctx.channel().close();

}catch(Exception e){
    System.err.printf("ChannelRead Error Msg: " + e.getMessage());
e.printStackTrace();

}


On Tuesday, January 31, 2017 at 10:03:46 PM UTC-5, L_DisplayName wrote:
Greetings All, 
I have a FileSender Application that sends data to a server via a FileHandler (not shown here, but in previous post). All data is successfully sent and received, but to keep the FileSenderHandler from terminating early, I had to use the following statement: f.channel().closeFuture().sync(); in the FileSender.java Application (the main application) which blocks the main program preventing it from terminating as well as the FileSenderHandler Application. My Question is: HOW CAN I CLOSE THE CHANNEL AND UNBLOCK THE MAIN FileSender APPLICATION ONCE THE FileSenderHandler HAS SUCCESSFULLY SENT AND ACKNOWLEDGED ALL DATA? I currently can't do it within the FileSender class because the application is blocked at that point. I tried closing the channel within the FileSenderHandler class by doing ctx.channel().close() which I thought would unblock the FileSender App since the App is waiting on the close channel event but that didn't work, I also tried closing the channel on the receiver/server side by doing ctx.channel().close() within the FileReceiverHandler but that still didn't unblock the FileSender App. Any help or suggestions would be greatly appreciated.

aFileSender.java - Bootstraps the channel and connects this client/host to another host
public static void main(String[] args) throws Exception {
 // Configure the client/ File Sender
 EventLoopGroup group = new NioEventLoopGroup();
 try {
 Bootstrp b = new Bootstrap();

Tim Boudreau

unread,
Feb 13, 2017, 11:42:58 PM2/13/17
to Netty discussions
It sounds like this application is just supposed to send some data somewhere and exit, right?

If so, then a couple of options:

1.  If the application is supposed to exit, the FileSenderHandler knows when it has finished writing the data, right?  When it's done, call System.exit(0).  Do your logging in the finally block in your main method.

2.  Pass FileSenderHandler a reference to the EventLoopGroup, and have it call shutdown() on it when the data has been sent, acknowledged, yadda yadda.  Or call channel.close(), which will also bail you out of sync().

Sounds like you're missing a few details on how Netty works.  First, the main thread does nothing except start a thread pool and open a connection, and then wait for something else to close that connection.  All the real work happens, not on the main thread at all, but on background threads created by the EventLoopGroup.  So while the *main thread* is blocked, you can always toss your own runnables or callables into the EventLoopGroup and get them scheduled to run in the background (so you can do whatever you want, or wait for whatever event you like, while the main thread is blocked).  From what you wrote, I got the impression you were thinking all the work was happening synchronously in the main thread, and there was no way to do anything while it's blocked.

You block the main thread in Netty because all the other threads in the application are *daemon* threads - ones that, to the JVM, don't count as the application "doing anything" that means it isn't done with its work.  So if you didn't block on sync() in your one non-daemon, the JVM would decide it had nothing left to do and the program would exit before your socket was even open.  That's why the pattern of blocking the main thread is there.  And if you block your only non-daemon thread, but your program does have a clear-cut exit point, then the code that knows when you hit that point needs to do something to unblock it (this is why Thread.interrupt() exists, but closing the thing it's blocked on is what you should do when you can).

Anyway, you're probably better off doing your logging in the thing that writes the data, rather than waiting until everything's done (so if something fails, you have some idea of where it got to without a debugger).

HTH,

-Tim


On Tuesday, January 31, 2017 at 10:03:46 PM UTC-5, L_DisplayName wrote:

L_DisplayName

unread,
Mar 27, 2017, 2:56:50 PM3/27/17
to Netty discussions
Thank you Tim that helped a lot.  
I have another question that you may be able to answer.  Do you know how I can find out what eventLoop is associated with a channelHandler if I have multiple channelHandlers running?  From my understanding the EventLoopGroup can spawn multiple eventLoops and a single event loop can be assigned to multiple channelHandlers and I think 1 thread is associated with a single eventLoop.  I know I can get the thread ID of a channel handler which can allow me to determine if Channel Handlers are sharing an event loop, but it doesn't give information on which event loop it is as well as how many other event loops may have been created by the EventLoopGroup.
Reply all
Reply to author
Forward
0 new messages