一.TCP粘包/拆包问题说明

TCP是个“流”协议,就是没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包拆分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

二.利用LinedBasedFrameDecoder解决TCP粘包问题

为了解决TCP粘包/拆包导致的半包读写问题,netty默认提供了多种解码器用于处理半包,只要能熟练掌握这些类库使用,TCP粘包问题就会非常容易。

2.1 支持TCP粘包的服务端开发

2.1.1  TimeServer实现:

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelOption;

import io.netty.channel.EventLoopGroup;

importio.netty.channel.nio.NioEventLoopGroup;

importio.netty.channel.socket.SocketChannel;

importio.netty.channel.socket.nio.NioServerSocketChannel;

importio.netty.handler.codec.LineBasedFrameDecoder;

import io.netty.handler.codec.string.StringDecoder;

/*

* 利用LineBasedFrameDecoder解决TCP粘包问题

*/

public class TimeServerNoStick {

publicvoid bind(int port) throws Exception{

//配置服务端的NIO线程组

EventLoopGroupbossGroup =new NioEventLoopGroup();

EventLoopGroupworkerGroup =new NioEventLoopGroup();

try{

//用于启动NIO服务器的辅助启动类,降低服务端的开发复杂度

ServerBootstrapb=new ServerBootstrap();

b.group(bossGroup,workerGroup)

.channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG,1024)

.childHandler(newChildChannelHandler());

//绑定端口,同步等待成功

ChannelFuturef=b.bind(port).sync();

//等待服务端监听端口关闭

f.channel().closeFuture().sync();

}catch (Exception e) {

//TODO: handle exception

}finally{

//优雅退出,释放线程池资源

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

}

privateclass ChildChannelHandler extends ChannelInitializer <SocketChannel> {

@Override

protectedvoid initChannel(SocketChannel arg0) throws Exception{

// 增加2个解码器:LineBasedFrameDecoder和StringDecoder

arg0.pipeline().addLast(newLineBasedFrameDecoder(1024));

arg0.pipeline().addLast(newStringDecoder());

arg0.pipeline().addLast(newTimeServerHandlerNoStick());

}

}

publicstatic void main(String[] args) throws Exception{

intport=8080;

if(args!=null&&args.length>0){

try{

port=Integer.valueOf(args[0]);

}catch (NumberFormatException e) {

//TODO: handle exception

}

}

newTimeServerNoStick().bind(port);

}

}

2.1.2  TimeServerHandler实现

/*

* 利用LineBasedFrameDecoder解决TCP粘包问题

*/

public class TimeServerHandlerNoStickextends ChannelHandlerAdapter{

privateint counter;

@Override

publicvoid channelRead(ChannelHandlerContext ctx,Object msg) throws Exception{

// 可以发现接收到的msg就是删除回车换行符后的请求消息,

//不需要额外考虑处理读半包问题,也不需要对请求消息进行编码

Stringbody=(String) msg;

System.out.println("The time server receiveorder:"+body+";the counter is"+ ++counter);

StringcurrentTime="QUERY TIME ORDER".equalsIgnoreCase(body)?

newjava.util.Date(System.currentTimeMillis()).toString():"BAD ORDER";

ByteBufresp=Unpooled.copiedBuffer(currentTime.getBytes());

ctx.writeAndFlush(resp);

}

@Override

publicvoid exceptionCaught(ChannelHandlerContext ctx,Throwable cause){

ctx.close();

}

}

2.2 支持TCP粘包的客户端开发

2.2.1 TimeClient实现

import io.netty.bootstrap.Bootstrap;

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;

importio.netty.channel.socket.SocketChannel;

importio.netty.channel.socket.nio.NioSocketChannel;

importio.netty.handler.codec.LineBasedFrameDecoder;

importio.netty.handler.codec.string.StringDecoder;

/*

* 利用LineBasedFrameDecoder解决TCP粘包问题

*/

public class TimeClientNoStick {

publicvoid connect(int port,String host) throws Exception{

//配置客户端NIO线程组

EventLoopGroupgroup=new NioEventLoopGroup();

try{

Bootstrapb=new Bootstrap();

b.group(group).channel(NioSocketChannel.class)

.option(ChannelOption.TCP_NODELAY,true)

.handler(newChannelInitializer<SocketChannel>() {

@Override

publicvoid initChannel(SocketChannel ch) throws Exception{

ch.pipeline().addLast(newLineBasedFrameDecoder(1024));

ch.pipeline().addLast(newStringDecoder());

ch.pipeline().addLast(newTimeClientHandlerNoStick(1024));

}

});

//发起异步连接操作

ChannelFuturef=b.connect(host,port).sync();

//等待客户端链路关闭

f.channel().closeFuture().sync();

}catch (Exception e) {

//TODO: handle exception

}finally{

//优雅退出,释放NIO线程组

group.shutdownGracefully();

}

}

publicstatic void main(String[] args) throws Exception{

intport=8080;

if(args!=null&&args.length>0){

try{

port=Integer.valueOf(args[0]);

}catch (NumberFormatException e) {

//TODO: handle exception

}

newTimeClient().connect(port,"127.0.0.1");

}

}

}

2.2.2 TimeClientHandler的实现

import java.util.logging.Logger;

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

importio.netty.channel.ChannelHandlerAdapter;

importio.netty.channel.ChannelHandlerContext;

/*

* 利用LineBasedFrameDecoder和StringDecoder解决TCP粘包问题

*/

public class TimeClientHandlerNoStickextends ChannelHandlerAdapter{

privatestatic final Logger logger=Logger.getLogger(TimeClientHandler.class.getName());

privateint counter;

privatebyte[] req;

publicTimeClientHandlerNoStick(){

req=("QUERYTIME ORDER"+System.getProperty("line.separator")).getBytes();

}

@Override

publicvoid channelActive(ChannelHandlerContext ctx){

ByteBufmessage=null;

for(inti=0;i<100;i++){

message=Unpooled.buffer(req.length);

message.writeBytes(req);

ctx.writeAndFlush(message);

}

}

@Override

publicvoid channelRead(ChannelHandlerContext ctx,Object msg) throws Exception{

//此时msg已经是解码成字符串之后的应答消息

Stringbody=(String) msg;

System.out.println("Nowis:"+body+";the counter is"+ ++counter);

}

@Override

publicvoid exceptionCaught(ChannelHandlerContext ctx,Throwable cause){

//释放资源

logger.warning("Unexpectedexception from downstream:"+cause.getMessage());

ctx.close();

}

}

三.运行支持TCP粘包的时间服务器程序

为了尽量模拟TCP粘包的半包场景,采用简单的压力测试,链路建立成功之后,客户端连续发送100条消息给服务端,然后查看服务端和客户端运行结果,分别运行TimeServer和TimeClient,服务端执行结果为:

。。。

客户端执行结果为:

。。。

运行结果完全符合预期,说明通过使用LinedBasedFrameDecoder和StringDecoder成功解决了TCP粘包导致的读半包问题。

Netty解决TCP粘包/拆包导致的半包读写问题相关推荐

  1. netty解决TCP粘包/拆包导致的半包读写问题的三种方案

    解决方案一:LineBasedFrameDecoder+StringDecoder来解决TCP的粘包/拆包问题 只需要在客户端和服务端加上45.46两行代码并且在发送消息的时候加上换行符即可解决TCP ...

  2. Netty学习总结(5)——Netty之TCP粘包/拆包问题的解决之道

    无论是服务端还是客户端,读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议. 流:没有界限的一串数据.如同河里的流水,它们是连成 ...

  3. 【Netty】TCP粘包和拆包

    一.前言 前面已经基本上讲解完了Netty的主要内容,现在来学习Netty中的一些可能存在的问题,如TCP粘包和拆包. 二.粘包和拆包 对于TCP协议而言,当底层发送消息和接受消息时,都需要考虑TCP ...

  4. Netty解决TCP的粘包和分包(二)

    2019独角兽企业重金招聘Python工程师标准>>> Netty解决TCP的粘包和分包(二) 使用LengthFieldBasedFrameDecoder解码器分包 先看一下这个类 ...

  5. golang解决TCP粘包问题

    6行代码解决golang TCP粘包 转自:https://studygolang.com/articles/12483 什么是TCP粘包问题以及为什么会产生TCP粘包,本文不加讨论.本文使用gola ...

  6. c#解决TCP“粘包”问题

    c#解决TCP"粘包"问题 参考文章: (1)c#解决TCP"粘包"问题 (2)https://www.cnblogs.com/wangjun8868/p/71 ...

  7. Linux socket编程(一):客户端服务端通信、解决TCP粘包

    一.服务端程序 服务端程序工作流程: 创建socket →\rightarrow→ 绑定监听的IP地址和端口 →\rightarrow→ 监听客户端连接 →\rightarrow→ 接受/发送数据.对 ...

  8. 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)

    一.粘包/拆包概念 TCP是一个"流"协议,所谓流,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的 ...

  9. Netty 之 TCP粘包拆包场景

    转自:http://blog.csdn.net/z69183787/article/details/52595980 TCP编程底层都有粘包和拆包机制,因为我们在C/S这种传输模型下,以TCP协议传输 ...

最新文章

  1. Android初级开发笔记-- activity启动模式的学习(1)
  2. python实现gif动画(matplotlib、imageio、pillow))
  3. Oracle学习:序列
  4. (转载)python多行注释
  5. 快速理解编程结构_为什么系统编程全都用英文而不用中文?听完专家的解释恍然大悟!...
  6. 何必言精通——十年杂感
  7. 双重检查锁实现单例模式的线程安全问题
  8. 数据库事务(Database Transaction)
  9. X5档案-参加业务架构平台研讨会后记
  10. 两平面平行但不重合的条件是_____2012江苏省数学竞赛《提优教程》教案:第77讲_组合几何...
  11. mysql,oracle,sql server数据库默认的端口号,端口号可以为负数吗?
  12. 雷电html查看程序编辑程序,NC程序编辑器(nEditor)
  13. 计算机护眼模式怎么设置的,为你解答电脑护眼设置怎么开
  14. 解决jdk证书问题-生成jssecacerts PKIX path building failed
  15. 程序开发类本科论文结构【2022年修改】
  16. 基于PHP的聚合数据车辆违章查询接口调用代码示例
  17. OpenGL初探:二维卡通人物交互设计
  18. selenium下Edge()配置错误问题
  19. android工程师培训价格,徐州android工程师培训基地
  20. win_server_2008x64升级powershell到4.0

热门文章

  1. 库 01_EOS 普元 EOS Platform 7.6 开发版安装时没装coframe,后续再部署coframe源码的操作步骤
  2. spring boot新建报错,多处显示导包失败,显示犹如The import org.junit cannot be resolved报错
  3. Error creating bean with name ‘servletEndpointRegistrar‘ defined in class path resource
  4. 关于安装双系统时多重引导的说明
  5. bzoj2754【SCOI2012】喵星球上的点名
  6. 【工作感悟】路自在前,冷暖自知
  7. Linux中防火墙firewalld
  8. java计算机毕业设计网上购物商城源代码+数据库+系统+lw文档
  9. 挑战UnityShader学习之八——用最简单的方法实现下雨天积水效果
  10. 飞行的小鸟论文python_80+行代码实现简单的“飞行的小鸟”游戏