Netty实践(二):TCP拆包、粘包问题-学海无涯 心境无限-51CTO博客 http://blog.51cto.com/zhangfengzhe/1890577

2017-01-09 21:56:06

什么是TCP拆包、粘包?

在网络通信中,数据在底层都是以字节流形式在流动,那么发送方和接受方理应有一个约定(协议),只有这样接受方才知道需要接受多少数据,哪些数据需要在一起处理;如果没有这个约定,就会出现本应该一起处理的数据,被TCP划分为多个包发给接收方进行处理,如下图:

看一个TCP拆包、粘包的实例

客户端Handler:

服务端Handler:

运行结果:

上面的程序本意是CLIENT发送3次消息给SERVER,SERVER端理应处理3次,可是结果SERVER却将3条消息一次处理了。

那么如何解决TCP拆包、粘包问题呢?其实思路不外乎有3种:

第一种:发定长数据

接收方拿固定长度的数据,发送方发送固定长度的数据即可。但是这样的缺点也是显而易见的:如果发送方的数据长度不足,需要补位,浪费空间。

第二种:在包尾部增加特殊字符进行分割

发送方发送数据时,增加特殊字符;在接收方以特殊字符为准进行分割

第三种:自定义协议

类似于HTTP协议中的HEAD信息,比如我们也可以在HEAD中,告诉接收方数据的元信息(数据类型、数据长度等)

Netty如何解决TCP拆包、粘包问题?

《Java通信实战:编写自定义通信协议实现FTP服务》中,涉及到了JAVA SOCKET这方面的处理,大家可以参考。接下来,我们来看Netty这个框架是如何帮助我们解决这个问题的。本篇博客的代码在《Netty实践(一):轻松入门》基础上进行。

方式一:定长消息

Server启动类:

Client Handler:

运行结果:

利用FixedLengthFrameDecoder,加入到管道流处理中,长度够了接收方才能收到。

方式二:自定义分隔符

Server启动类:

Client Handler:

运行结果:

方式三:自定义协议

下面我们将简单实现一个自定义协议:

HEAD信息中包含:数据长度、数据版本

数据内容

MyHead

public class MyHead {

    //数据长度
private int length; //数据版本
private int version; public MyHead(int length, int version) {
this.length = length;
this.version = version;
} public int getLength() {
return length;
} public void setLength(int length) {
this.length = length;
} public int getVersion() {
return version;
} public void setVersion(int version) {
this.version = version;
} } MyMessage public class MyMessage {
//消息head
private MyHead head;
//消息body
private String content; public MyMessage(MyHead head, String content) {
this.head = head;
this.content = content;
} public MyHead getHead() {
return head;
} public void setHead(MyHead head) {
this.head = head;
} public String getContent() {
return content;
} public void setContent(String content) {
this.content = content;
} @Override
public String toString() {
return String.format("[length=%d,version=%d,content=%s]",head.getLength(),head.getVersion(),content);
}
} 编码器 /**
* Created by Administrator on 17-1-9.
* 编码器 将自定义消息转化成ByteBuff
*/
public class MyEncoder extends MessageToByteEncoder { @Override
protected void encode(ChannelHandlerContext channelHandlerContext, MyMessage myMessage, ByteBuf byteBuf) throws Exception { int length = myMessage.getHead().getLength();
int version = myMessage.getHead().getVersion();
String content = myMessage.getContent(); byteBuf.writeInt(length);
byteBuf.writeInt(version);
byteBuf.writeBytes(content.getBytes(Charset.forName("UTF-8"))); }
} 解码器 /**
* Created by Administrator on 17-1-9.
* 解码器 将ByteBuf数据转化成自定义消息
*/
public class MyDecoder extends ByteToMessageDecoder { @Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List
 

运行结果

到这里,你会发现Netty处理TCP拆包、粘包问题很简单,通过编解码技术支持,让我们编写自定义协议也很方便,在后续的Netty博客中,我将继续为大家介绍Netty在实际中的一些应用(比如实现心跳检测),See You~

Netty处理TCP拆包、粘包的更多相关文章

  1. 架构师养成记--20.netty的tcp拆包粘包问题

    问题描述 比如要发ABC DEFG HIJK 这一串数据,其中ABC是一个包,DEFG是一个包,HIJK是一个包.由于TCP是基于流发送的,所以有可能出现ABCD EFGH 这种情况,那么ABC和D就 ...

  2. TCP拆包粘包之分隔符解码器

    TCP以流的方式进行数据传输,上层的应用协议为了对消息进行区分,往往采用如下4种方式. (1)消息长度固定,累计读取到长度总和为定长LEN的报文后,就认为读取到了一个完整的消息:将计数器置位,重新开始 ...

  3. 使用Netty如何解决拆包粘包的问题

    首先,我们通过一个DEMO来模拟TCP的拆包粘包的情况:客户端连续向服务端发送100个相同消息.服务端的代码如下: AtomicLong count = new AtomicLong(0); NioE ...

  4. tomcat Http11NioProtocol如何解析http请求及如何解决TCP拆包粘包

    前言 tomcat是常用的Web 应用服务器,目前国内有很多文章讲解了tomcat架构,请求流程等,但是没有如何解析http请求及如何解决TCP粘包拆包,所以这篇文章的目的就是介绍这块内容,一下内容完 ...

  5. Netty—TCP的粘包和拆包问题

    一.前言 虽然TCP协议是可靠性传输协议,但是对于TCP长连接而言,对于消息发送仍然可能会发生粘贴的情形.主要是因为TCP是一种二进制流的传输协议,它会根据TCP缓冲对包进行划分.有可能将一个大数据包 ...

  6. 《精通并发与Netty》学习笔记(14 - 解决TCP粘包拆包(二)Netty自定义协议解决粘包拆包)

    一.Netty粘包和拆包解决方案 Netty提供了多个解码器,可以进行分包的操作,分别是: * LineBasedFrameDecoder (换行)   LineBasedFrameDecoder是回 ...

  7. Netty 拆包粘包和服务启动流程分析

    Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...

  8. netty的解码器和粘包拆包

    Tcp是一个流的协议,一个完整的包可能会被Tcp拆成多个包进行发送,也可能把一个小的包封装成一个大的数据包发送,这就是所谓的粘包和拆包问题 粘包.拆包出现的原因: 在流传输中出现,UDP不会出现粘包, ...

  9. 【转】Netty 拆包粘包和服务启动流程分析

    原文:https://www.cnblogs.com/itdragon/archive/2018/01/29/8365694.html Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你 ...

随机推荐

  1. js生成二维码的jquery组件–qrcode

    js生成二维码的jquery组件–qrcode 2015/01/30 / 2508 VIEWS / JAVASCRIPT, JQUERY 有一些耗cpu的计算,完全可以在客户端上计算,比如生成二维码. ...

  2. firewalld增加端口访问权限

    firewall-cmd --zone=public --add-port=80/tcp --permanent firewall-cmd --reload

  3. [转]James Bach:测试人员的角色

    [转]James Bach:测试人员的角色 2015-05-13 以前,我是个开发人员.我不喜欢这个工作,无尽的压力让我疲惫.我几乎从未感觉到自己的工作做得足够好.我从未有过真正的休息.如果我没做好, ...

  4. spring cloud outh2

    使用Spring Cloud Security OAuth2搭建授权服务http://www.blogjava.net/paulwong/archive/2016/09/16/431797.html? ...

  5. jQuery瀑布流插件 Masonry

    http://www.jq22.com/yanshi362 参考案例 http://image.quanjing.com/lvyou/

  6. 同一个String在使用不同的charset编码的时候equals仍然是返回true吗

    1.对于ASCII字符,是的(只要该charset涵盖了ASCII编码),使用任何charset编码都不会影响equals的判断 2.对于非ASCII字符,不一定.例如同中文字符串"你好&q ...

  7. 16位结构的CPU,8086给出物理地址的方法

    .16位结构的CPU 概括地讲,16位结构(16位机,字长为16位等常见说法,与16位结构的含义相同)描述了一个CPU具有下面几方面结构特性: 1.运算器一次最多可以处理16位的数据结构 2.寄存器的 ...

  8. dp之多重背包poj1276

    题意:有现今cash,和n种钱币,每种钱币有ni个,价值为di,求各种钱币组成的不超过cash的最大钱数....... 思路:二进制拆分转化为01背包,或者转化为完全背包都是可以的. 反思:这个题目我 ...

  9. hive中创建hive-json格式的表及查询

    在hive中对于json的数据格式,可以使用get_json_object或json_tuple先解析然后查询. 也可以直接在hive中创建json格式的表结构,这样就可以直接查询,实战如下(hive ...

  10. Spring.Net框架二:配置Spring.Net框架环境

    一.下载DLL文件 去Spring的官方网站下载并解压,然后直接添加dll文件的引用就可以了.在上一篇文章中,已经介绍过Spring.Net框架中需要使用到的dll文件.这些程序集文件位于Spring ...