本文参考于CSDN博客wxy941011

1、疑问

我们使用第四个博客中的项目。

修改客户端为:连接成功后循环向服务器发送从1-100的数字。看看服务器会不会正常的接收100次数据。



可是我们发现服务器只接收了两次数据,为什么和期望的不一样呢,这就触发了粘包问题。

2、什么是粘包和拆包

当客户端不断向服务器发送数据包时,服务器就可能出现两个数据包粘在一起的情况。

而和Tcp同为传输层的Udp则不会发生粘包和拆包问题。因为Udp是基于报文发送的,从Udp帧结构可以看出,Udp首部采用了16bit来显示Udp数据报文长度,因此在应用层可以很好的把不同数据报文分开,避免了粘包和拆包问题。

TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;另外从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段。所以只有Tcp会发生粘包、拆包现象

3、粘包拆包的表现形式

客户端向服务器连续发送两个数据包,packet1、packet2,服务器收到有三种情况。

  1. 正常收到了两个数据包

  2. 只收到一个数据包,由于Tcp不会出现丢包现象,所以这一个数据包包含了两个数据包的信息,称为粘包。

  3. 接收到两个错误的数据报,发生了粘包+拆包

4、粘包拆包的发生原因

  1. 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
  2. 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
  3. 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
  4. 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

    等等。

5、粘包拆包解决方法

1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

等等。

6、构造包头包尾方法

class EncodeTool
{
/// <summary>
/// 构造包 包头+包尾
/// </summary>
public static byte[] EncodePacket(byte[] data)
{
//内存流用完需要close释放,using自动释放。
using (MemoryStream ms = new MemoryStream())
{
//bw用于向ms流中写入内容
using (BinaryWriter bw = new BinaryWriter(ms))
{
//写入包头(数据的长度),把字节数组写入流
bw.Write(data.Length);
//写入包尾(数据)
bw.Write(data); //拿到写入的数据
byte[] packet = new byte[ms.Length];
Buffer.BlockCopy(ms.GetBuffer(), 0, packet, 0, (int) ms.Length); //把内存流中的数据复制到packet中
return packet;
}
}
} /// <summary>
/// 解析包,从缓冲区里取出一个完成的包
/// </summary>
public static byte[] DecodePacket(ref List<byte> cache)
{
if (cache.Count < 4)
{
return null;
} //这种构造实例根据byte类型的字节数组进行初始化
//并且实例的容量大小固定为字节数组的长度
using (MemoryStream ms = new MemoryStream(cache.ToArray()))
{
//从流中读取数据
using (BinaryReader br = new BinaryReader(ms))
{
int length = br.ReadInt32(); //读取前四个字节(包头-数据的长度)
//读取的长度和缓冲区剩余的长度进行比较
int remainLength = (int) ms.Length - (int) ms.Position; //流中剩余的长度
if (length > remainLength)
{
return null;
} byte[] data = br.ReadBytes(length);
//更新数据缓存
cache.Clear();
cache.AddRange(br.ReadBytes(remainLength)); //把剩余的再填进去???
return data;
}
}
} }

C#网络编程学习(5)---Tcp连接中出现的粘包、拆包问题的更多相关文章

  1. python 之网络编程(基于TCP协议Socket通信的粘包问题及解决)

    8.4 粘包问题 粘包问题发生的原因: 1.发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包),这样接收端,就难于分辨出来了,必须提供科学的拆包机制. ...

  2. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V4 -- 粘包拆包

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- new LengthFieldPrepender(2) : 设置数据包 2 字节的特征码 new LengthFieldB ...

  3. 网络编程学习笔记-TCP拥塞控制机制

    为了防止网络的拥塞现象,TCP提出了一系列的拥塞控制机制.最初由V. Jacobson在1988年的论文中提出的TCP的拥塞控制由“慢启动(Slow start)”和“拥塞避免(Congestion ...

  4. Java网络编程系列之TCP连接状态

    1.TCP连接状态 LISTEN:Server端打开一个socket进行监听,状态置为LISTEN SYN_SENT:Client端发送SYN请求给Server端,状态由CLOSED变为SYN_SEN ...

  5. 网络编程之模拟ssh远程执行命令、粘包问题 、解决粘包问题

    目录 模拟ssh远程执行命令 服务端 客户端 粘包问题 什么是粘包 TCP发送数据的四种情况 粘包的两种情况 解决粘包问题 struct模块 解决粘包问题 服务端 客户端 模拟ssh远程执行命令 服务 ...

  6. Linux 网络编程详解四(流协议与粘包)

    TCP/IP协议是一种流协议,流协议是字节流,只有开始和结束,包与包之间没有边界,所以容易产生粘包,但是不会丢包. UDP/IP协议是数据报,有边界,不存在粘包,但是可能丢包. 产生粘包问题的原因 . ...

  7. 网络编程基础【day09】:解决socket粘包之大数据(七)

    本节内容 概述 linux下运行效果 sleep解决粘包 服务端插入交互解决粘包问题 一.概述 刚刚我们在window的操作系统上,很完美的解决了,大数据量的数据传输出现的问题,但是在Linux环境下 ...

  8. Linux网络编程二、tcp连接API

    一.服务端 1.创建套接字: int socket(int domain, int type, int protocol); domain:指定协议族,通常选用AF_INET. type:指定sock ...

  9. 网络编程基础【day09】:socket解决粘包问题之MD5(八)

    本节内容 1.概述 2.代码实现 一.概述 上一篇博客讲到的用MD5来校验还是用的之前解决粘包的方法,就是客户端发送一个请求,等待服务端的确认的这样的一个笨方法.下面我们用另外一种方法:就是客户端已经 ...

随机推荐

  1. Java企业微信开发_07_JSSDK多图上传

    一.本节要点 1.1可信域名 所有的JS接口只能在企业微信应用的可信域名下调用(包括子域名),可在企业微信的管理后台“我的应用”里设置应用可信域名.这个域名必须要通过ICP备案,不然jssdk会配置失 ...

  2. 【LeetCode】001. Two Sum

    题目: Given an array of integers, return indices of the two numbers such that they add up to a specifi ...

  3. Oracle12c多租户如何启动关闭CDB或PDB (PDB自动启动)

    Oracle 数据库 12 c 中介绍了多租户选项允许单个容器数据库 (CDB) 来承载多个单独的可插拔数据库 (PDB).下面我们一起来启动和关闭容器数据库 (CDB) 和可插拔数据库 (PDB). ...

  4. TS学习之函数

    定义函数类型(规定函数参数及函数返回值的类型,若函数没有返回值,则返回类型为null) function add(x: number, y: number): number { return x + ...

  5. idea崩溃导致的svn插件丢失问题, maven dependencies视图丢失问题

    Idea丢失Svn解决办法 今天打开Idea,习惯用ctrl+t来更新svn,杯具出现了,快捷键失效了,我觉得可能是其他的什么软件占用了这个快捷键,于是重启了一下,发现还是不行,svn信息怎么没了,c ...

  6. 安装python Matplotlib 库

    转:使用 python Matplotlib 库 绘图 及 相关问题  使用 python Matplotlib 库绘图      转:http://blog.csdn.net/daniel_ustc ...

  7. R语言最好的IDE——RStudio

    转自http://www.dataguru.cn/article-1602-1.html 看到很多的R语言教材,介绍的编辑器或者IDE都是很简陋的那些,就没有见到有人提到RStudio.对于不使用Em ...

  8. 14、/proc/cpuinfo 文件(查看CPU信息)

    转载http://www.cnblogs.com/itcomputer/p/4888438.html /proc/cpuinfo文件分析 根据以下内容,我们则可以很方便的知道当前系统关于CPU.CPU ...

  9. VCF文件处理工具PyVCF

    vcf格式示例 ##fileformat=VCFv4.1 ##FILTER=<ID=LowQual,Description=”Low quality”> ##FORMAT=<ID=A ...

  10. 9、scala函数式编程-集合操作

    一.集合操作1 1.Scala的集合体系结构 // Scala中的集合体系主要包括:Iterable.Seq.Set.Map.其中Iterable是所有集合trait的根trai.这个结构与Java的 ...