Reputation: 123
I am in the middle of learning Netty an started some tutorials using spring boot. My goal is to create an application which set up a tcp port for receiving messages and to present them over a rest api.
Most of the tutorials are saying that I should add something like this
serverChannel = serverBootstrap.bind(tcpPort).sync().channel().closeFuture().sync().channel();
to start netty. When I do that, the rest services which I implemented are not working. Now when I use the following code snippet to start the application:
serverChannel = serverBootstrap.bind(tcpPort).sync().channel();
everything seems to be working just fine. Could someone explain me what might cause this issue?
Thanks
Upvotes: 8
Views: 3941
Reputation: 941
Old, but I had same issue with my RestController not starting. Other answer helped solve it for me but here is full code for the Spring component.
import com.myserver.netty.handler.ClientInboundHandler;
import com.myserver.netty.handler.PacketDecoder;
import com.myserver.netty.handler.PacketEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
@Log4j2
public class NettyServer {
private EventLoopGroup masters = new NioEventLoopGroup();
private EventLoopGroup workers = new NioEventLoopGroup();
private Channel mainChannel;
@PostConstruct
public void start() {
try {
ServerBootstrap bootstrap = init();
mainChannel = bootstrap.bind(8484).sync().channel(); // save the main channel so we can cleanly close it when app is shutdown
log.info("Netty Server started......");
} catch (Exception e) {
e.printStackTrace();
}
}
@PreDestroy
public void stop() throws InterruptedException {
log.info("Shutting down netty server");
workers.shutdownGracefully().sync();
masters.shutdownGracefully().sync();
mainChannel.closeFuture().sync();
log.info("Shutdown complete");
}
private ServerBootstrap init() {
return new ServerBootstrap()
.group(masters, workers)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 5000)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
.addLast(new PacketDecoder())
.addLast(new ClientInboundHandler())
.addLast(new PacketEncoder());
}
});
}
}
Upvotes: 0
Reputation: 2206
The first part start the server, 1) binding it on a TCP port, 2) wait for the server to be ready (socket is listening) 3) and return the associated channel.
serverBootstrap.bind(tcpPort).sync().channel();
(1) (2) (3)
The second part is to wait for the main channel (listening socket) to shutdown (closeFuture().sync()
) where closeFuture
gives you the "future" on "close" operation (meaning shutdown of the server socket), and sync
waiting for this future to be done. channel()
gives you back the very same channel than first time, except it is now closed.
So you might find this code in various example because generally you start the server (bind) in the main thread or so, and then if you don't wait for something, the main thread will end up, giving your JVM finishing, and therefore your server to stop immediately after starting.
So in general, what we do is:
See for instance Shutdown netty programmatically
Upvotes: 9