前面一文說了 基於http的netty demojava
和http不同,http能夠用瀏覽器來充當客戶端調用,因此基於socket的netty,必需要編寫客戶端和服務器的代碼bootstrap
實現功能:
客戶端給服務器發消息,服務器給客戶端回消息
一直循環瀏覽器
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 }
先運行服務器:服務器
再運行客戶端:dom
運行完客戶端後服務器的狀況socket
完整代碼下載:ide