前面一文说了 基于http的netty demo
和http不一样,http可以用浏览器来充当客户端调用,所以基于socket的netty,必须要编写客户端和服务器的代码
实现功能:
客户端给服务器发消息,服务器给客户端回消息
一直循环
服务器代码
1 package com.bill.socketdemo; 2 3 4 import io.netty.bootstrap.ServerBootstrap; 5 import io.netty.channel.ChannelFuture; 6 import io.netty.channel.EventLoopGroup; 7 import io.netty.channel.nio.NioEventLoopGroup; 8 import io.netty.channel.socket.nio.NioServerSocketChannel; 9 10 public class SocketServer { 11 12 public static void main(String[] args) throws Exception { 13 14 // 这2个group都是死循环,阻塞式 15 EventLoopGroup bossGroup = new NioEventLoopGroup(); 16 EventLoopGroup workerGroup = new NioEventLoopGroup(); 17 18 try { 19 ServerBootstrap serverBootstrap = new ServerBootstrap(); 20 serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class). 21 childHandler(new SocketServerInitializer()); 22 23 ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); 24 channelFuture.channel().closeFuture().sync(); 25 } finally { 26 bossGroup.shutdownGracefully(); 27 workerGroup.shutdownGracefully(); 28 } 29 } 30 31 } 32 33 package com.bill.socketdemo; 34 35 import io.netty.channel.ChannelHandlerContext; 36 import io.netty.channel.SimpleChannelInboundHandler; 37 38 import java.util.UUID; 39 40 public class SocketServerHandler extends SimpleChannelInboundHandler<String> { 41 42 /** 43 * 读取客户端请求,并且返回给客户端数据的方法 44 */ 45 @Override 46 protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 47 System.out.println(ctx.channel().remoteAddress() + ", " + msg); 48 ctx.channel().writeAndFlush("from server:" + UUID.randomUUID()); 49 } 50 51 /** 52 * 处理异常的方法,一旦出现异常,就会调用此方法 53 */ 54 @Override 55 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 56 cause.printStackTrace(); 57 ctx.close(); 58 } 59 } 60 61 package com.bill.socketdemo; 62 63 import io.netty.channel.ChannelInitializer; 64 import io.netty.channel.ChannelPipeline; 65 import io.netty.channel.socket.SocketChannel; 66 import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 67 import io.netty.handler.codec.LengthFieldPrepender; 68 import io.netty.handler.codec.string.StringDecoder; 69 import io.netty.handler.codec.string.StringEncoder; 70 import io.netty.util.CharsetUtil; 71 72 public class SocketServerInitializer extends ChannelInitializer<SocketChannel> { 73 74 @Override 75 protected void initChannel(SocketChannel socketChannel) throws Exception { 76 77 ChannelPipeline pipeline = socketChannel.pipeline(); 78 79 pipeline.addLast("LengthFieldBasedFrameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); 80 pipeline.addLast("LengthFieldPrepender",new LengthFieldPrepender(4)); 81 pipeline.addLast("StringDecoder",new StringDecoder(CharsetUtil.UTF_8)); 82 pipeline.addLast("StringEncoder",new StringEncoder(CharsetUtil.UTF_8)); 83 pipeline.addLast("SocketServerHandler", new SocketServerHandler()); 84 } 85 }
客户端代码
1 package com.bill.socketdemo; 2 3 4 import io.netty.bootstrap.Bootstrap; 5 import io.netty.channel.ChannelFuture; 6 import io.netty.channel.EventLoopGroup; 7 import io.netty.channel.nio.NioEventLoopGroup; 8 import io.netty.channel.socket.nio.NioSocketChannel; 9 10 public class SocketClient { 11 12 public static void main(String[] args) throws Exception { 13 14 // 这2个group都是死循环,阻塞式 15 EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); 16 17 try { 18 Bootstrap bootstrap = new Bootstrap(); 19 bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class). 20 handler(new SocketClientInitializer()); 21 22 ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync(); 23 channelFuture.channel().closeFuture().sync(); 24 } finally { 25 eventLoopGroup.shutdownGracefully(); 26 } 27 } 28 29 } 30 31 package com.bill.socketdemo; 32 33 import io.netty.channel.ChannelHandlerContext; 34 import io.netty.channel.SimpleChannelInboundHandler; 35 36 import java.util.UUID; 37 38 public class SocketClientHandler extends SimpleChannelInboundHandler<String> { 39 40 /** 41 * 发送内容给服务器端 42 */ 43 @Override 44 protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 45 System.out.println(ctx.channel().remoteAddress()); 46 System.out.println("client output:" + msg); 47 ctx.writeAndFlush("from client:" + UUID.randomUUID()); 48 } 49 50 /** 51 * 该方法向服务器发数据,打破服务器-客户端一直等待对方发数据的僵局 52 */ 53 @Override 54 public void channelActive(ChannelHandlerContext ctx) throws Exception { 55 ctx.writeAndFlush("from client: hello world"); 56 } 57 58 /** 59 * 处理异常的方法,一旦出现异常,就会调用此方法 60 */ 61 @Override 62 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 63 cause.printStackTrace(); 64 ctx.close(); 65 } 66 } 67 68 package com.bill.socketdemo; 69 70 import io.netty.channel.ChannelInitializer; 71 import io.netty.channel.ChannelPipeline; 72 import io.netty.channel.socket.SocketChannel; 73 import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 74 import io.netty.handler.codec.LengthFieldPrepender; 75 import io.netty.handler.codec.string.StringDecoder; 76 import io.netty.handler.codec.string.StringEncoder; 77 import io.netty.util.CharsetUtil; 78 79 public class SocketClientInitializer extends ChannelInitializer<SocketChannel> { 80 81 @Override 82 protected void initChannel(SocketChannel socketChannel) throws Exception { 83 84 ChannelPipeline pipeline = socketChannel.pipeline(); 85 86 pipeline.addLast("LengthFieldBasedFrameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); 87 pipeline.addLast("LengthFieldPrepender",new LengthFieldPrepender(4)); 88 pipeline.addLast("StringDecoder",new StringDecoder(CharsetUtil.UTF_8)); 89 pipeline.addLast("StringEncoder",new StringEncoder(CharsetUtil.UTF_8)); 90 pipeline.addLast("SocketServerHandler", new SocketClientHandler()); 91 } 92 }
执行结果
先运行服务器:
再运行客户端:
运行完客户端后服务器的情况
完整代码下载:
https://download.csdn.net/download/mweibiao/10551574