{"id":1129,"date":"2021-12-30T08:49:49","date_gmt":"2021-12-30T00:49:49","guid":{"rendered":"http:\/\/www.max-shu.com\/blog\/?p=1129"},"modified":"2021-12-30T08:49:49","modified_gmt":"2021-12-30T00:49:49","slug":"%e4%bd%bf%e7%94%a8netty%e4%bd%9c%e4%b8%batcp%e7%9a%84%e7%b2%98%e5%8c%85%e5%88%86%e5%8c%85%e5%a4%84%e7%90%86","status":"publish","type":"post","link":"http:\/\/www.max-shu.com\/blog\/?p=1129","title":{"rendered":"\u4f7f\u7528Netty\u4f5c\u4e3aTCP\u7684\u7c98\u5305\u5206\u5305\u5904\u7406"},"content":{"rendered":"<p><strong><span style=\"color: #ff0000;\">\u5e73\u5e38\u7528tcp\u4f5c\u4e3a\u6d88\u606f\u4f20\u8f93\u7684\u8f7d\u4f53\u65f6\uff0c\u9700\u8981\u505a\u6d88\u606f\u7684\u7c98\u5305\u548c\u62c6\u5305\u7684\u5904\u7406\uff0c\u4e2a\u4eba\u5efa\u8bae\u4f7f\u7528SCTP\u534f\u8bae\u66f4\u597d\uff08SCTP\u6709\u7c7b\u4f3cUDP\u4ee5\u6d88\u606f\u4e3a\u5355\u4f4d\u5bf9\u5916\u53d1\u9001\u3001\u7c7b\u4f3cTCP\u6709\u6d88\u606f\u4e0d\u4e22\u5931\u7684\u4f18\u70b9\uff0c\u6700\u9002\u5408\u4f20\u8f93\u6d88\u606f\u7c7b\u6570\u636e\uff09\u3002<\/span><\/strong><\/p>\n<h2>\u5148\u770bserver\u7aef\uff1a<\/h2>\n<ul>\n<li><strong>\u5efa\u7acb\u4e00\u4e2aserver\uff1a<\/strong><\/li>\n<\/ul>\n<div>\n<div>public void start(){<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \u7528\u6765\u63a5\u6536\u8fdb\u6765\u7684\u8fde\u63a5<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 EventLoopGroup bossGroup = new NioEventLoopGroup();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \u7528\u6765\u5904\u7406\u5df2\u7ecf\u88ab\u63a5\u6536\u7684\u8fde\u63a5\uff0c\u4e00\u65e6bossGroup\u63a5\u6536\u5230\u8fde\u63a5\uff0c\u5c31\u4f1a\u628a\u8fde\u63a5\u4fe1\u606f\u6ce8\u518c\u5230workerGroup\u4e0a<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 EventLoopGroup workGroup = new NioEventLoopGroup();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/ nio\u670d\u52a1\u7684\u542f\u52a8\u7c7b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ServerBootstrap server = new ServerBootstrap().group(bossGroup,workGroup)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .channel(NioServerSocketChannel.class) \/\/ \u8bf4\u660e\u4e00\u4e2a\u65b0\u7684Channel\u5982\u4f55\u63a5\u6536\u8fdb\u6765\u7684\u8fde\u63a5<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .option(ChannelOption.SO_BACKLOG, 128) \/\/ tcp\u6700\u5927\u7f13\u5b58\u94fe\u63a5\u4e2a\u6570<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .childOption(ChannelOption.SO_KEEPALIVE, true) \/\/\u4fdd\u6301\u8fde\u63a5<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .handler(new LoggingHandler(LogLevel.INFO)) \/\/ \u6253\u5370\u65e5\u5fd7\u7ea7\u522b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .childHandler(new TcpServerChannelInitializer());<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 try {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ChannelFuture future = server.bind(port).sync(); \/\/ \u7ed1\u5b9a\u7aef\u53e3\uff0c\u5f00\u59cb\u63a5\u53d7\u94fe\u63a5<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 future.channel().closeFuture().sync();\/\/ \u7b49\u5f85\u670d\u52a1\u7aef\u53e3\u7684\u5173\u95ed\uff1b\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\u4e0d\u4f1a\u53d1\u751f\uff0c\u4f46\u4f60\u53ef\u4ee5\u4f18\u96c5\u5b9e\u73b0\uff1b\u5173\u95ed\u4f60\u7684\u670d\u52a1<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 } catch (InterruptedException e) {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Log.e(TAG,&#8221;server start fail&#8221;,e);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 }finally {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 bossGroup.shutdownGracefully();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 workGroup.shutdownGracefully();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<\/div>\n<div><\/div>\n<ul>\n<li><strong>\u518d\u7ee7\u627f\u5efa\u7acb\u4e00\u4e2a\u901a\u9053\u521d\u59cb\u5316\u7c7b\uff1a<\/strong><\/li>\n<\/ul>\n<div>\n<div>\n<div>public class TcpServerChannelInitializer extends ChannelInitializer&lt;SocketChannel&gt; {<\/div>\n<div>\u00a0 \u00a0 protected void initChannel(SocketChannel socketChannel) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ChannelPipeline pipeline = socketChannel.pipeline();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/*<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u4e3a\u4e86\u89e3\u51b3\u7f51\u7edc\u6570\u636e\u6d41\u7684\u62c6\u5305\u7c98\u5305\u95ee\u9898\uff0cNetty \u4e3a\u6211\u4eec\u5185\u7f6e\u4e86\u5982\u4e0b\u7684\u89e3\u7801\u5668\uff1a<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ByteToMessageDecoder\uff1a\u5982\u679c\u60f3\u5b9e\u73b0\u81ea\u5df1\u7684\u534a\u5305\u89e3\u7801\u5668\uff0c\u5b9e\u73b0\u8be5\u7c7b\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 MessageToMessageDecoder\uff1a\u4e00\u822c\u4f5c\u4e3a\u4e8c\u6b21\u89e3\u7801\u5668\uff0c\u5f53\u6211\u4eec\u5728 ByteToMessageDecoder \u5c06\u4e00\u4e2a bytes \u6570\u7ec4\u8f6c\u6362\u6210\u4e00\u4e2a java \u5bf9\u8c61\u7684\u65f6\u5019\uff0c\u6211\u4eec\u53ef\u80fd\u8fd8\u9700\u8981\u5c06\u8fd9\u4e2a\u5bf9\u8c61\u8fdb\u884c\u4e8c\u6b21\u89e3\u7801\u6210\u5176\u4ed6\u5bf9\u8c61\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u7ee7\u627f\u8fd9\u4e2a\u7c7b\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 LineBasedFrameDecoder\uff1a\u901a\u8fc7\u5728\u5305\u5c3e\u6dfb\u52a0\u56de\u8f66\u6362\u884c\u7b26 \\r\\n \u6765\u533a\u5206\u6574\u5305\u6d88\u606f\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 StringDecoder\uff1a\u5b57\u7b26\u4e32\u89e3\u7801\u5668\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 DelimiterBasedFrameDecoder\uff1a\u7279\u6b8a\u5b57\u7b26\u4f5c\u4e3a\u5206\u9694\u7b26\u6765\u533a\u5206\u6574\u5305\u6d88\u606f\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 FixedLengthFrameDecoder\uff1a\u62a5\u6587\u5927\u5c0f\u56fa\u5b9a\u957f\u5ea6\uff0c\u4e0d\u591f\u7a7a\u683c\u8865\u5168\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ProtoBufVarint32FrameDecoder\uff1a\u901a\u8fc7 Protobuf \u89e3\u7801\u5668\u6765\u533a\u5206\u6574\u5305\u6d88\u606f\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ProtobufDecoder\uff1a Protobuf \u89e3\u7801\u5668\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 LengthFieldBasedFrameDecoder\uff1a\u6307\u5b9a\u957f\u5ea6\u6765\u6807\u8bc6\u6574\u5305\u6d88\u606f\uff0c\u901a\u8fc7\u5728\u5305\u5934\u6307\u5b9a\u6574\u5305\u957f\u5ea6\u6765\u7ea6\u5b9a\u5305\u957f\u3002<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Netty \u8fd8\u5185\u7f6e\u4e86\u5982\u4e0b\u7684\u7f16\u7801\u5668\uff1a<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ProtobufEncoder\uff1aProtobuf \u7f16\u7801\u5668\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 MessageToByteEncoder\uff1a\u5c06 Java \u5bf9\u8c61\u7f16\u7801\u6210 ByteBuf\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 MessageToMessageEncoder\uff1a\u5982\u679c\u4e0d\u60f3\u5c06 Java \u5bf9\u8c61\u7f16\u7801\u6210 ByteBuf\uff0c\u800c\u662f\u81ea\u5b9a\u4e49\u7c7b\u5c31\u7ee7\u627f\u8fd9\u4e2a\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 LengthFieldPrepender\uff1aLengthFieldPrepender \u662f\u4e00\u4e2a\u975e\u5e38\u5b9e\u7528\u7684\u5de5\u5177\u7c7b\uff0c\u5982\u679c\u6211\u4eec\u5728\u53d1\u9001\u6d88\u606f\u7684\u65f6\u5019\u91c7\u7528\u7684\u662f\uff1a\u6d88\u606f\u957f\u5ea6\u5b57\u6bb5+\u539f\u59cb\u6d88\u606f\u7684\u5f62\u5f0f\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528 LengthFieldPrepender\u3002\u8fd9\u662f\u56e0\u4e3a LengthFieldPrepender \u53ef\u4ee5\u5c06\u5f85\u53d1\u9001\u6d88\u606f\u7684\u957f\u5ea6\uff08\u4e8c\u8fdb\u5236\u5b57\u8282\u957f\u5ea6\uff09\u5199\u5230 ByteBuf \u7684\u524d\u4e24\u4e2a\u5b57\u8282\u3002<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 *\/<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \u8fd9\u91cc\u76f8\u5f53\u4e8e\u8fc7\u6ee4\u5668\uff0c\u53ef\u4ee5\u914d\u7f6e\u591a\u4e2a<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/\u5904\u7406\u7c98\u5305\uff0c\u8981\u548c\u5ba2\u6237\u5668\u7aef\u53d1\u9001\u6d88\u606f\u5bf9\u5e94\uff0c\u6d88\u606f\u683c\u5f0f\u5e94\u8be5\u4e3a\uff1a4\u5b57\u8282\u6d88\u606f\u5185\u5bb9\u957f\u5ea6+\u6d88\u606f\u5185\u5bb9<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 pipeline.addLast(new LengthFieldBasedFrameDecoder(<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 1024, \/\/ \u5e27\u7684\u6700\u5927\u957f\u5ea6\uff0c\u5373\u6bcf\u4e2a\u6570\u636e\u5305\u6700\u5927\u9650\u5ea6<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 0, \/\/ \u957f\u5ea6\u5b57\u6bb5\u504f\u79fb\u91cf<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 4, \/\/ \u957f\u5ea6\u5b57\u6bb5\u6240\u5360\u7684\u5b57\u8282\u6570<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 0, \/\/ \u957f\u5ea6\u7684\u4fee\u6b63\u503c\uff0c\u5982\u679c\u957f\u5ea6\u5b57\u6bb5\u6ca1\u6709\u5305\u542b\u5c3e\u90e8\u6240\u6709\u957f\u5ea6\uff0c\u5219\u8fd9\u91cc\u4e3a\u6b63\uff0c\u5982\u679c\u957f\u5ea6\u5b57\u6bb5\u5305\u542b\u4e86\u957f\u5ea6\u81ea\u8eab\u548c\u957f\u5ea6\u504f\u79fb\u91cf\uff0c\u5219\u8fd9\u91cc\u4e3a\u8d1f<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 4) \/\/ \u9700\u8981\u5ffd\u7565\u7684\u5b57\u8282\u6570\uff0c\u4ece\u6d88\u606f\u5e27\u7684\u7b2c\u4e00\u5b57\u8282\u5f00\u59cb\u7b97<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 );<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \u81ea\u5df1\u7684\u903b\u8f91Handler<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 pipeline.addLast(&#8220;handler&#8221;, new TcpServerHandler());<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>}<\/div>\n<\/div>\n<ul>\n<li><strong>\u6700\u540e\u7ee7\u627f\u5b9e\u73b0\u4e00\u4e2a\u901a\u9053\u5904\u7406\u7c7b\uff1a<\/strong><\/li>\n<\/ul>\n<div>\n<div>\n<div>public class TcpServerHandler extends SimpleChannelInboundHandler {<\/div>\n<div>\u00a0 \u00a0 private static final String TAG = &#8220;TcpServerHandler&#8221;;<\/div>\n<div>\u00a0 \u00a0 private int counter;<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 public void channelActive(ChannelHandlerContext ctx) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Log.i(TAG, &#8220;server channelActive&#8221;);<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/\u63a5\u6536\u6d88\u606f\u7684\u5904\u7406<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ByteBuf buf = (ByteBuf) msg;<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 byte[] req = new byte[buf.readableBytes()];<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 buf.readBytes(req);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 String body = new String(req, StandardCharsets.UTF_8);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 System.out.println(&#8220;&#8212;&#8211;start&#8212;&#8212;\\n&#8221;+ body + &#8220;\\n&#8212;&#8212;end&#8212;&#8212;&#8220;);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/\u53d1\u9001\u6d88\u606f\u5230\u5ba2\u6237\u7aef<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 String content = &#8220;receive&#8221; + ++counter;<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ByteBuf resp = Unpooled.buffer();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 resp.writeShort(content.getBytes(StandardCharsets.UTF_8).length);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 resp.writeBytes(content.getBytes(StandardCharsets.UTF_8));<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ctx.writeAndFlush(resp);<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 super.exceptionCaught(ctx, cause);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ctx.close();<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>}<\/div>\n<\/div>\n<h2>\u518d\u770bClient\u7aef<\/h2>\n<div>\u5176\u5b9eclient\u7aef\u548cserver\u7684\u5904\u7406\u7c7b\u4f3c\u3002<\/div>\n<ul>\n<li><strong>\u5148\u8fde\u63a5\u5230server\u7aef\uff1a<\/strong><\/li>\n<\/ul>\n<div>\n<div>\n<div>\u00a0 \u00a0 public void start(){<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 EventLoopGroup group = new NioEventLoopGroup();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Bootstrap bootstrap = new Bootstrap();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 bootstrap.group(group)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .channel(NioSocketChannel.class)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .option(ChannelOption.TCP_NODELAY, true)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .handler(new TcpClientChannelInitializer());<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 try {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ChannelFuture future = bootstrap.connect(address,port).sync();\/\/ \u5ba2\u6237\u7aef\u5f00\u542f<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 future.channel().writeAndFlush(&#8220;Hello world, i&#8217;m online&#8221;);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 future.channel().closeFuture().sync();\/\/ \u7b49\u5f85\u76f4\u5230\u8fde\u63a5\u4e2d\u65ad<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 } catch (Exception e) {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Log.e(TAG, &#8220;client start fail&#8221;,e);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 }finally {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 group.shutdownGracefully();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div><\/div>\n<div>\n<ul>\n<li><strong>\u7136\u540e\u5efa\u7acb\u901a\u9053\u521d\u59cb\u5316\u7c7b\uff1a<\/strong><\/li>\n<\/ul>\n<div>\n<div>\n<div>public class TcpClientChannelInitializer extends ChannelInitializer&lt;SocketChannel&gt; {<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 protected void initChannel(SocketChannel socketChannel) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ChannelPipeline pipeline = socketChannel.pipeline();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/*<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u4e3a\u4e86\u89e3\u51b3\u7f51\u7edc\u6570\u636e\u6d41\u7684\u62c6\u5305\u7c98\u5305\u95ee\u9898\uff0cNetty \u4e3a\u6211\u4eec\u5185\u7f6e\u4e86\u5982\u4e0b\u7684\u89e3\u7801\u5668\uff1a<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ByteToMessageDecoder\uff1a\u5982\u679c\u60f3\u5b9e\u73b0\u81ea\u5df1\u7684\u534a\u5305\u89e3\u7801\u5668\uff0c\u5b9e\u73b0\u8be5\u7c7b\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 MessageToMessageDecoder\uff1a\u4e00\u822c\u4f5c\u4e3a\u4e8c\u6b21\u89e3\u7801\u5668\uff0c\u5f53\u6211\u4eec\u5728 ByteToMessageDecoder \u5c06\u4e00\u4e2a bytes \u6570\u7ec4\u8f6c\u6362\u6210\u4e00\u4e2a java \u5bf9\u8c61\u7684\u65f6\u5019\uff0c\u6211\u4eec\u53ef\u80fd\u8fd8\u9700\u8981\u5c06\u8fd9\u4e2a\u5bf9\u8c61\u8fdb\u884c\u4e8c\u6b21\u89e3\u7801\u6210\u5176\u4ed6\u5bf9\u8c61\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u7ee7\u627f\u8fd9\u4e2a\u7c7b\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 LineBasedFrameDecoder\uff1a\u901a\u8fc7\u5728\u5305\u5c3e\u6dfb\u52a0\u56de\u8f66\u6362\u884c\u7b26 \\r\\n \u6765\u533a\u5206\u6574\u5305\u6d88\u606f\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 StringDecoder\uff1a\u5b57\u7b26\u4e32\u89e3\u7801\u5668\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 DelimiterBasedFrameDecoder\uff1a\u7279\u6b8a\u5b57\u7b26\u4f5c\u4e3a\u5206\u9694\u7b26\u6765\u533a\u5206\u6574\u5305\u6d88\u606f\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 FixedLengthFrameDecoder\uff1a\u62a5\u6587\u5927\u5c0f\u56fa\u5b9a\u957f\u5ea6\uff0c\u4e0d\u591f\u7a7a\u683c\u8865\u5168\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ProtoBufVarint32FrameDecoder\uff1a\u901a\u8fc7 Protobuf \u89e3\u7801\u5668\u6765\u533a\u5206\u6574\u5305\u6d88\u606f\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ProtobufDecoder\uff1a Protobuf \u89e3\u7801\u5668\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 LengthFieldBasedFrameDecoder\uff1a\u6307\u5b9a\u957f\u5ea6\u6765\u6807\u8bc6\u6574\u5305\u6d88\u606f\uff0c\u901a\u8fc7\u5728\u5305\u5934\u6307\u5b9a\u6574\u5305\u957f\u5ea6\u6765\u7ea6\u5b9a\u5305\u957f\u3002<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Netty \u8fd8\u5185\u7f6e\u4e86\u5982\u4e0b\u7684\u7f16\u7801\u5668\uff1a<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ProtobufEncoder\uff1aProtobuf \u7f16\u7801\u5668\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 MessageToByteEncoder\uff1a\u5c06 Java \u5bf9\u8c61\u7f16\u7801\u6210 ByteBuf\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 MessageToMessageEncoder\uff1a\u5982\u679c\u4e0d\u60f3\u5c06 Java \u5bf9\u8c61\u7f16\u7801\u6210 ByteBuf\uff0c\u800c\u662f\u81ea\u5b9a\u4e49\u7c7b\u5c31\u7ee7\u627f\u8fd9\u4e2a\uff1b<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 LengthFieldPrepender\uff1aLengthFieldPrepender \u662f\u4e00\u4e2a\u975e\u5e38\u5b9e\u7528\u7684\u5de5\u5177\u7c7b\uff0c\u5982\u679c\u6211\u4eec\u5728\u53d1\u9001\u6d88\u606f\u7684\u65f6\u5019\u91c7\u7528\u7684\u662f\uff1a\u6d88\u606f\u957f\u5ea6\u5b57\u6bb5+\u539f\u59cb\u6d88\u606f\u7684\u5f62\u5f0f\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528 LengthFieldPrepender\u3002\u8fd9\u662f\u56e0\u4e3a LengthFieldPrepender \u53ef\u4ee5\u5c06\u5f85\u53d1\u9001\u6d88\u606f\u7684\u957f\u5ea6\uff08\u4e8c\u8fdb\u5236\u5b57\u8282\u957f\u5ea6\uff09\u5199\u5230 ByteBuf \u7684\u524d\u4e24\u4e2a\u5b57\u8282\u3002<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 *\/<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/\u5904\u7406\u7c98\u5305\uff0c\u8981\u548c\u670d\u52a1\u5668\u7aef\u53d1\u9001\u6d88\u606f\u5bf9\u5e94\uff0c\u6d88\u606f\u683c\u5f0f\u5e94\u8be5\u4e3a\uff1a2\u5b57\u8282\u6d88\u606f\u5185\u5bb9\u957f\u5ea6+\u6d88\u606f\u5185\u5bb9<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 pipeline.addLast(new LengthFieldBasedFrameDecoder(<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 1024, \/\/ \u5e27\u7684\u6700\u5927\u957f\u5ea6\uff0c\u5373\u6bcf\u4e2a\u6570\u636e\u5305\u6700\u5927\u9650\u5ea6<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 0, \/\/ \u957f\u5ea6\u5b57\u6bb5\u504f\u79fb\u91cf<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 2, \/\/ \u957f\u5ea6\u5b57\u6bb5\u6240\u5360\u7684\u5b57\u8282\u6570<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 0, \/\/ \u957f\u5ea6\u7684\u4fee\u6b63\u503c\uff0c\u5982\u679c\u957f\u5ea6\u5b57\u6bb5\u6ca1\u6709\u5305\u542b\u5c3e\u90e8\u6240\u6709\u957f\u5ea6\uff0c\u5219\u8fd9\u91cc\u4e3a\u6b63\uff0c\u5982\u679c\u957f\u5ea6\u5b57\u6bb5\u5305\u542b\u4e86\u957f\u5ea6\u81ea\u8eab\u548c\u957f\u5ea6\u504f\u79fb\u91cf\uff0c\u5219\u8fd9\u91cc\u4e3a\u8d1f<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 2) \/\/ \u9700\u8981\u5ffd\u7565\u7684\u5b57\u8282\u6570\uff0c\u4ece\u6d88\u606f\u5e27\u7684\u7b2c\u4e00\u5b57\u8282\u5f00\u59cb\u7b97<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 );<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \u5ba2\u6237\u7aef\u7684\u903b\u8f91<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 pipeline.addLast(&#8220;handler&#8221;, new TcpClientHandler());<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>}<\/div>\n<\/div>\n<ul>\n<li><strong>\u6700\u540e\u5b9e\u73b0\u81ea\u5df1\u901a\u9053\u7684\u5904\u7406\uff1a<\/strong><\/li>\n<\/ul>\n<div>\n<div>\n<div>public class TcpClientHandler extends SimpleChannelInboundHandler {<\/div>\n<div>\u00a0 \u00a0 private static final String TAG = &#8220;TcpClientHandler&#8221;;<\/div>\n<div>\u00a0 \u00a0 private int counter;<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/\u63a5\u6536\u6d88\u606f\u7684\u5904\u7406<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 ByteBuf buf = (ByteBuf) msg;<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 byte[] req = new byte[buf.readableBytes()];<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 buf.readBytes(req);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 String body = new String(req, StandardCharsets.UTF_8);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/System.out.println(body + &#8221; count:&#8221; + ++counter + &#8220;&#8212;-end&#8212;-\\n&#8221;);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Log.w(TAG, body + &#8221; count:&#8221; + ++counter + &#8220;&#8212;-end&#8212;-\\n&#8221;);<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 public void channelActive(ChannelHandlerContext ctx) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Log.i(TAG, &#8220;client channelActive&#8221;);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \/\/\u53d1\u9001\u6d88\u606f\u5230\u670d\u52a1\u7aef<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 for (int i = 0; i &lt; 100; i++) {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 byte[] req = (&#8220;\u6211\u662f\u4e00\u6761\u6d4b\u8bd5\u6d88\u606f\uff0c\u5feb\u6765\u8bfb\u6211\u5427\uff0c\u5566\u5566\u5566&#8221; + i).getBytes();<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ByteBuf message = Unpooled.buffer(req.length);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 message.writeInt(req.length);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 message.writeBytes(req);<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ctx.writeAndFlush(message);\/\/ \u53d1\u9001\u5ba2\u6237\u7aef\u7684\u8bf7\u6c42<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>\u00a0 \u00a0 @Override<\/div>\n<div>\u00a0 \u00a0 public void channelInactive(ChannelHandlerContext ctx) throws Exception {<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 Log.i(TAG, &#8220;Client is close&#8221;);<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<div>}<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u5e73\u5e38\u7528tcp\u4f5c\u4e3a\u6d88\u606f\u4f20\u8f93\u7684\u8f7d\u4f53\u65f6\uff0c\u9700\u8981\u505a\u6d88\u606f\u7684\u7c98\u5305\u548c\u62c6\u5305\u7684\u5904\u7406\uff0c\u4e2a\u4eba\u5efa\u8bae\u4f7f\u7528SCTP\u534f\u8bae\u66f4\u597d\uff08SCTP\u6709\u7c7b\u4f3cU &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[330,329,335,857,858,856],"class_list":["post-1129","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-netty","tag-sctp","tag-tcp","tag-857","tag-858","tag-856"],"views":1429,"_links":{"self":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1129"}],"version-history":[{"count":1,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1129\/revisions"}],"predecessor-version":[{"id":1130,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1129\/revisions\/1130"}],"wp:attachment":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1129"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}