TCP粘包/拆包--利用DelimiterBasedFrameDecoder解決TCP粘包問題
阿新 • • 發佈:2019-02-05
前面我們介紹了利用LineBasedFrameDecoder解決TCP的粘包/拆包的問題,
現在我們繼續介紹Netty的另外一種解碼器--DelemiterBasedFrameDecoder。
1. DelimiterBasedFrameDecoder服務端開發
EchoServer.java
import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; 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.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; public class EchoServer { private final static int port = 8080; public static void main(String[] args) { start(); } private static void start() { final EchoServerHandler serverHandler = new EchoServerHandler(); // 建立EventLoopGroup EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); // 建立EventLoopGroup ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); socketChannel.pipeline().addLast( new DelimiterBasedFrameDecoder(1024, delimiter)); socketChannel.pipeline().addLast(new StringDecoder()); socketChannel.pipeline().addLast(serverHandler); } }); try { // 非同步地繫結伺服器;呼叫sync方法阻塞等待直到繫結完成 ChannelFuture f = b.bind(port).sync(); // 獲取Channel的CloseFuture,並且阻塞當前執行緒直到它完成 f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 優雅的關閉EventLoopGroup,釋放所有的資源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
2. EchoSeverHandler.java
3. EchoClient.javaimport io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @Sharable public class EchoServerHandler extends ChannelInboundHandlerAdapter{ private int counter = 0; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String body = (String )msg; System.out.println( "This is " + ++counter +" times receive client [" + body +"]" ); body += "$_"; ByteBuf resp = Unpooled.copiedBuffer(body.getBytes()); ctx.writeAndFlush(resp); } /** * 異常處理 * @param ctx * @param cause * @throws Exception */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { //列印異常棧跟蹤 cause.printStackTrace(); // 關閉該Channel ctx.close(); } }
4. EchoClientHandler.javaimport io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; 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.NioSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; import java.net.InetSocketAddress; public class EchoClient { private final static String HOST = "localhost"; private final static int PORT = 8080; public static void start() { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter)); socketChannel.pipeline().addLast(new StringDecoder()); socketChannel.pipeline().addLast(new EchoClientHandler()); } }); try { ChannelFuture f = bootstrap.connect(HOST,PORT).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { group.shutdownGracefully(); } } public static void main(String[] args) { start(); } }
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
@Sharable
public class EchoClientHandler extends ChannelInboundHandlerAdapter {
private int counter;
static final String ECHO_REQ = "Hi, Welcome to Netty World!$_";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String body = (String) msg;
System.out.println(
"This is "+ ++counter + " times receive server:[" + body +"]"
);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for (int i = 0; i < 10; i++) {
ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));
}
}
}
這裡我們用"$_"做為分隔符、分別執行EchoServer和EchoClient
服務端控制檯列印結果如下:
-------------------------------------------------
This is 1 times receive client [Hi, Welcome to Netty World!]
This is 2 times receive client [Hi, Welcome to Netty World!]
This is 3 times receive client [Hi, Welcome to Netty World!]
This is 4 times receive client [Hi, Welcome to Netty World!]
This is 5 times receive client [Hi, Welcome to Netty World!]
This is 6 times receive client [Hi, Welcome to Netty World!]
This is 7 times receive client [Hi, Welcome to Netty World!]
This is 8 times receive client [Hi, Welcome to Netty World!]
This is 9 times receive client [Hi, Welcome to Netty World!]
This is 10 times receive client [Hi, Welcome to Netty World!]
客戶端控制檯列印結果如下。
-------------------------------------------------------------------------------------------------
This is 1 times receive server:[Hi, Welcome to Netty World!]
This is 2 times receive server:[Hi, Welcome to Netty World!]
This is 3 times receive server:[Hi, Welcome to Netty World!]
This is 4 times receive server:[Hi, Welcome to Netty World!]
This is 5 times receive server:[Hi, Welcome to Netty World!]
This is 6 times receive server:[Hi, Welcome to Netty World!]
This is 7 times receive server:[Hi, Welcome to Netty World!]
This is 8 times receive server:[Hi, Welcome to Netty World!]
This is 9 times receive server:[Hi, Welcome to Netty World!]
This is 10 times receive server:[Hi, Welcome to Netty World!]