所用jar包
netty-all-4.1.30.Final.jar 密码:rzwe
NettyConfig.java,存放连接的客户端
1 import io.netty.channel.group.ChannelGroup; 2 import io.netty.channel.group.DefaultChannelGroup; 3 import io.netty.util.concurrent.GlobalEventExecutor; 4 5 public class NettyConfig { 6 7 /** 8 * 存储每一个客户端接入进来时的channel对象 9 */ 10 public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 11 12 }
Server.java,netty配置信息
1 import io.netty.bootstrap.ServerBootstrap; 2 import io.netty.channel.ChannelFuture; 3 import io.netty.channel.ChannelInitializer; 4 import io.netty.channel.ChannelOption; 5 import io.netty.channel.ChannelPipeline; 6 import io.netty.channel.EventLoopGroup; 7 import io.netty.channel.nio.NioEventLoopGroup; 8 import io.netty.channel.socket.ServerSocketChannel; 9 import io.netty.channel.socket.SocketChannel; 10 import io.netty.channel.socket.nio.NioServerSocketChannel; 11 12 public class Server { 13 private int port; 14 private ServerSocketChannel serverSocketChannel; 15 16 public Server(int port){ 17 this.port = port; 18 bind(); 19 } 20 21 private void bind() { 22 Thread thread = new Thread(new Runnable() { 23 @Override 24 public void run() { 25 //服务端要建立两个group,一个负责接收客户端的连接,一个负责处理数据传输 26 //连接处理group 27 EventLoopGroup boss = new NioEventLoopGroup(); 28 //事件处理group 29 EventLoopGroup worker = new NioEventLoopGroup(); 30 ServerBootstrap bootstrap = new ServerBootstrap(); 31 // 绑定处理group 32 bootstrap.group(boss, worker).channel(NioServerSocketChannel.class) 33 //保持连接数 34 .option(ChannelOption.SO_BACKLOG, 300) 35 //有数据立即发送 36 .option(ChannelOption.TCP_NODELAY, true) 37 //保持连接 38 .childOption(ChannelOption.SO_KEEPALIVE, true) 39 //处理新连接 40 .childHandler(new ChannelInitializer<SocketChannel>() { 41 @Override 42 protected void initChannel(SocketChannel sc) throws Exception { 43 // 增加任务处理 44 ChannelPipeline p = sc.pipeline(); 45 p.addLast( 46 // //使用了netty自带的编码器和解码器 47 // new StringDecoder(), 48 // new StringEncoder(), 49 //心跳检测,读超时,写超时,读写超时 50 //new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS), 51 //自定义的处理器 52 new ServerHandler()); 53 } 54 }); 55 56 //绑定端口,同步等待成功 57 ChannelFuture future; 58 try { 59 future = bootstrap.bind(port).sync(); 60 if (future.isSuccess()) { 61 serverSocketChannel = (ServerSocketChannel) future.channel(); 62 System.out.println("服务端启动成功,端口:"+port); 63 } else { 64 System.out.println("服务端启动失败!"); 65 } 66 67 //等待服务监听端口关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程 68 future.channel().closeFuture().sync(); 69 } catch (Exception e) { 70 e.printStackTrace(); 71 } 72 finally { 73 //优雅地退出,释放线程池资源 74 boss.shutdownGracefully(); 75 worker.shutdownGracefully(); 76 } 77 } 78 }); 79 thread.start(); 80 } 81 82 public void sendMessage(Object msg){ 83 if(serverSocketChannel != null){ 84 serverSocketChannel.writeAndFlush(msg); 85 } 86 } 87 88 public static void main(String[] args) { 89 Server server = new Server(8088); 90 } 91 }
ServerHandler.java,业务处理
1 import io.netty.channel.ChannelHandlerContext; 2 import io.netty.channel.ChannelInboundHandlerAdapter; 3 4 public class ServerHandler extends ChannelInboundHandlerAdapter { 5 6 /** 7 * 客户端与服务端创建连接的时候调用 8 */ 9 @Override 10 public void channelActive(ChannelHandlerContext ctx) throws Exception { 11 System.out.println("客户端与服务端连接开始..."); 12 NettyConfig.group.add(ctx.channel()); 13 } 14 15 /** 16 * 客户端与服务端断开连接时调用 17 */ 18 @Override 19 public void channelInactive(ChannelHandlerContext ctx) throws Exception { 20 System.out.println("客户端与服务端连接关闭..."); 21 NettyConfig.group.remove(ctx.channel()); 22 } 23 24 /** 25 * 服务端接收客户端发送过来的数据结束之后调用 26 */ 27 @Override 28 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 29 ctx.flush(); 30 System.out.println("信息接收完毕..."); 31 } 32 33 /** 34 * 工程出现异常的时候调用 35 */ 36 @Override 37 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 38 cause.printStackTrace(); 39 ctx.close(); 40 } 41 42 /** 43 * 服务端处理客户端websocket请求的核心方法,这里接收了客户端发来的信息 44 */ 45 @Override 46 public void channelRead(ChannelHandlerContext channelHandlerContext, Object info) throws Exception { 47 System.out.println("接收到了:"+info); 48 ByteBuf buf = (ByteBuf) info; 49 byte[] req = new byte[buf.readableBytes()]; 50 buf.readBytes(req); 51 String body = new String(req, "UTF-8"); 52 System.out.println("接收客户端数据:" + body); 53 ByteBuf pingMessage = Unpooled.buffer(); 54 pingMessage.writeBytes(req); 55 channelHandlerContext.writeAndFlush(pingMessage); 56 57 58 //服务端使用这个就能向 每个连接上来的客户端群发消息 59 //NettyConfig.group.writeAndFlush(info); 60 // Iterator<Channel> iterator = NettyConfig.group.iterator(); 61 // while(iterator.hasNext()){ 62 // //打印出所有客户端的远程地址 63 // System.out.println((iterator.next()).remoteAddress()); 64 // } 65 } 66 67 68 }
使用网络调试助手进行连接测试 下载地址
https://www.wanpishe.top/detail?blogId=fc62fce2-020a-4815-8388-0903e4a54e1f