Preface
We explained the basic use of Netty earlier. This time, we will use Netty to complete a group chat system to realize simple data communication between the server and the client;
Basic requirements of group chat system:
- The server can monitor the client online, offline, and forward the client message;
- The client can send messages to other users in groups or receive messages sent by other customers;
Code example
Server:
public class GroupChatServer { private String host; private int port; public GroupChatServer(String host, int port) { this.host = host; this.port = port; } public void start() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) // Set the number of connections in the thread queue .childOption(ChannelOption.SO_KEEPALIVE, true) // Set keep active connection state .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // Get pipeline ChannelPipeline pipeline = socketChannel.pipeline(); // Add decoder pipeline.addLast(new StringDecoder()); // Add encoder pipeline.addLast(new StringEncoder()); // Add custom business processing handler pipeline.addLast(new GroupChatServerHandler()); } }); System.out.println("Netty Group chat server started~"); ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); channelFuture.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new GroupChatServer("127.0.0.1", 8899).start(); } }
Server custom handler:
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> { private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * Connection establishment event * * @param ctx * @throws Exception */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); String msg = channel.remoteAddress() + "Joined the chat~"; channelGroup.writeAndFlush(msg); // Add channel to channelGroup channelGroup.add(channel); } /** * Disconnect event * * @param ctx * @throws Exception */ @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); String msg = "[Server]: " + channel.remoteAddress() + "Offline.~"; channelGroup.writeAndFlush(msg); } /** * channel Handling activity status events * * @param ctx * @throws Exception */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println(simpleDateFormat.format(new Date()) + "/" + ctx.channel().remoteAddress() + "Online.~"); } /** * channel Inactive * * @param ctx * @throws Exception */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println(simpleDateFormat.format(new Date()) + "/" + ctx.channel().remoteAddress() + " Offline~"); } /** * Read data event * * @param ctx * @param s * @throws Exception */ @Override protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { Channel channel = ctx.channel(); System.out.println(simpleDateFormat.format(new Date()) + "/" + "Server received from[" + channel.remoteAddress() + "]Message for[" + s + "]"); System.out.println("The server starts forwarding messages..."); for (Channel ch : channelGroup) { if (channel != ch) { ch.writeAndFlush(channel.remoteAddress() + "Said:" + s); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }
Client:
public class GroupChatClient { private String serverHost; private int serverPort; public GroupChatClient(String serverHost, int serverPort) { this.serverHost = serverHost; this.serverPort = serverPort; } public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); // Add decoder pipeline.addLast(new StringDecoder()); // Add encoder pipeline.addLast(new StringEncoder()); // Add custom business processing handler pipeline.addLast(new GroupChatClientHandler()); } }); ChannelFuture channelFuture = bootstrap.connect(serverHost, serverPort).sync(); Channel channel = channelFuture.channel(); System.out.println("---" + channel.localAddress() + "---"); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { String msg = scanner.nextLine(); channel.writeAndFlush(msg); } } finally { group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new GroupChatClient("127.0.0.1", 8899).start(); } }
Client custom handler:
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { // Print message output System.out.println(s); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }
Communication Demonstration:
Server:
Netty group chat server started~ 2020-02-04 12:22:11 / / 127.0.0.1:4099 go online~ 2020-02-04 12:22:14 / / 127.0.0.1:4141 go online~ 2020-02-04 12:22:24 / the server receives a message from [/ 127.0.0.1:4099], the content is [I am 4099] The server starts forwarding messages... 2020-02-04 12:22:31 / the server received a message from [[127.0.0.1:4141] with the content of [I am 4141] The server starts forwarding messages...
client1:
---/127.0.0.1:4099--- /127.0.0.1:4141 join chat~ I am 4099. /127.0.0.1:4141 say: I'm 4141
client2:
---/127.0.0.1:4141--- /127.0.0.1:4099 say: I am 4099 I am 4141.