最近在学习netty,看了几天的博客之后,打算自己写一个练手的程序。
这个程序很简单:客户端发送一个ping
,服务端会相应地回复一个pong
,当监测到服务端失去连接后,即断开。
整个代码分为client与server两部分,结构如下:
引入netty包:
io.netty netty-all 4.1.15.Final
client端:
PingClient.java
package org.attempt.netty4.demo001.client;import io.netty.bootstrap.Bootstrap;import io.netty.channel.Channel;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.codec.string.StringDecoder;import io.netty.handler.codec.string.StringEncoder;public class PingClient { /** 服务器IP地址 */ private String host = "127.0.0.1"; /** 服务器端口 */ private int port = 8000; private EventLoopGroup group = null; private Bootstrap b = null; private Channel channel = null; public PingClient() throws Exception { group = new NioEventLoopGroup(); b = new Bootstrap(); b.group(group) .option(ChannelOption.SO_KEEPALIVE, true) .channel(NioSocketChannel.class) .handler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline() //字符串解码和编码 .addLast(new StringDecoder()) .addLast(new StringEncoder()) //客户端的逻辑 .addLast(new PingClientHandler()); } }); } public Channel getChannel() throws Exception { if(null == channel || !channel.isActive()) { channel = b.connect(host, port).sync().channel(); } return channel; } public static void main(String[] args) throws Exception { PingClient client = null; try { client = new PingClient(); Channel channel = client.getChannel(); while(true) { //输出channel的状态,对应于close() System.out.println(channel.isOpen()); //判断连接状态 if(channel.isActive()) { channel.writeAndFlush("ping"); } else { System.out.println("失去连接,关闭客户端"); channel.close(); break; } Thread.sleep(5000); } } finally { if(null != client) { client.stop(); } } } public void stop() { if(null != group) { //优雅退出,释放线程池资源 group.shutdownGracefully(); } }}
PingClientHandler.java
package org.attempt.netty4.demo001.client;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;public class PingClientHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("receive from server: " + msg.toString()); }}
server端: PongServer.java
package org.attempt.netty4.demo001.server;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.codec.string.StringDecoder;import io.netty.handler.codec.string.StringEncoder;public class PongServer { public static void main(String[] args) throws Exception { int port = 8000; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { //采用默认值 } } new PongServer().bind(port); } public void bind(int port) throws Exception { //配置服务端的NIO线程组 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline() //字符串解码和编码 .addLast(new StringDecoder()) .addLast(new StringEncoder()) //服务器的逻辑 .addLast(new PongServerHandler()); } }); //绑定端口,同步等待成功 ChannelFuture f = b.bind(port).sync(); //等待服务器监听端口关闭 f.channel().closeFuture().sync(); } finally { //优雅退出,释放线程池资源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }}
PongServerHandler.java
package org.attempt.netty4.demo001.server;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;/** * @author admin * @date 2018-09-06 22:48 */public class PongServerHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("receive from client: " + msg.toString()); //返回客户端消息 if(msg.toString().equals("ping")) { ctx.writeAndFlush("pong"); } else { ctx.writeAndFlush("UNKONWN"); } }}
运行,先启动server端,再启动client端,结果如下:
- server端:
receive from client: pingreceive from client: pingreceive from client: pingreceive from client: pingreceive from client: pingProcess finished with exit code -1
- client端:
truereceive from server: pongtruereceive from server: pongtruereceive from server: pongtruereceive from server: pongtruereceive from server: pongfalse失去连接,关闭客户端
代码中的一些类及用法,后面再说。