netty实现tcp通信服务端出现数据粘包问题解决办法

    这里介绍两种解决办法:1、利用LengthFieldBasedFrameDecoder解码器  2、设置自定义编解码。

    一般出现数据粘包问题很难复现,因为在开发中,我们都是模拟发数据,真正上线了,我们的数据发送就没有什么规律,可能很快,也可能慢,频率不同,难以捕捉问题,但是肯定会出现一些粘包问题。

    所谓粘包,就是接收的数据,无法分开,一个包的数据可能是两个或者多个报文记录,我们需要严格按照报文格式将这些合在一起的包拆开。思路就是要么报文有严格的分隔符,要么定长,再就是自定义解码器或者利用netty自带的LengthFieldBasedFrameDecoder解码器。

    前面说过,粘包问题在实际中很难复现,这对于我们查找问题不是很方便,但是我这里通过自己编写的client发送报文,几乎可以100%的复现。

    这个客户端,就是前面两篇博客中提到的c语言自定义tcp协议实现socket通信的客户端。

    netty实现的tcp server代码如下所示:

package com.xxx.huali.hualitest.nettyio;
import java.nio.ByteOrder;

import com.xxx.huali.hualitest.nettyio.decode.MyDecoder;
import com.xxx.huali.hualitest.nettyio.decode.MyHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class ServerApp {
	private final static int port  = 6666;
	public static void main(String[] args) {
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup work = new NioEventLoopGroup();
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(boss, work)
					 .channel(NioServerSocketChannel.class)
					 .handler(new LoggingHandler(LogLevel.INFO))
					 .childHandler(new ChannelInitializer<SocketChannel>() {

						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							//ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 65535, 8 , 4, 1, 0, true));
							//ch.pipeline().addLast("decoder",new MyDecoder());
							ch.pipeline().addLast(new ServerHandler());
							//ch.pipeline().addLast("handler", new MyHandler());
						}
					})
					 .option(ChannelOption.SO_BACKLOG, 1024)
					 .childOption(ChannelOption.SO_KEEPALIVE, true);
			ChannelFuture future = bootstrap.bind(port).sync();
			future.channel().closeFuture().sync();     
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			boss.shutdownGracefully();
			work.shutdownGracefully();
		}
	}
}

class ServerHandler extends SimpleChannelInboundHandler<ByteBuf>{
	int count = 1;

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
		// TODO Auto-generated method stub
		// flag version type reserved length payload checksum
		//   2    2       2     2       4     length   1
		
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luffy5459

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值