1、TCP 粘包和拆包基本介绍
2、TCP 粘包和拆包 实例演示
3、netty 自定义协议解决 TCP 粘包和拆包
1、TCP 粘包和拆包基本介绍 <--返回目录
TCP 是面向连接的,面向流的,提供高可靠性服务,收发两端(客户端和服务器端)都要一 一成对的 socket。因此发送端为了将多个发给接收端的包更有效的发给对方,使用了优化方法(Nagle 算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样虽然提高了效率,但是接收端就难于分辨出完整的数据包了,因为面向流的通信是无消息保护边界的。
由TCP 无消息保护边界,需要在接收端处理消息边界问题,也就是我们所说的粘包、拆包问题。
2、TCP 粘包和拆包 实例演示 <--返回目录
在编写 netty 程序时,如果没有做处理,就会发生粘包和拆包的问题。看一个具体的实例:
Server 端程序
package com.oy.tcp; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; public class Server { public static void main(String[] args) { NioEventLoopGroup boss = new NioEventLoopGroup(1); NioEventLoopGroup work = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap .group(boss, work) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new MyServerHandler()); } }); ChannelFuture future = serverBootstrap.bind(8005).sync(); System.out.println("server started and listen " + 8005); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { boss.shutdownGracefully(); work.shutdownGracefully(); } } } package com.oy.tcp; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.CharsetUtil; import java.util.UUID; public class MyServerHandler extends SimpleChannelInboundHandler<ByteBuf> { private int count; @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { //System.out.println("服务器收到的数据:" + msg.toString(CharsetUtil.UTF_8)); byte[] buffer = new byte[msg.readableBytes()]; msg.readBytes(buffer); // 将 buffer 转成字符串 String message = new String(buffer, CharsetUtil.UTF_8); System.out.println("服务器接收数据 " + message); System.out.println("服务器接收到消息量= " + (++this.count)); // 服务器会送数据 ByteBuf response = Unpooled.copiedBuffer(UUID.randomUUID().toString(), CharsetUtil.UTF_8); ctx.writeAndFlush(response); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }