网络通信中TCP出现的黏包以及解决方法 socket 模拟黏包

粘包问题概述

1.1  描述背景

采用TCP协议进行网络数据传送的软件设计中,普遍存在粘包问题。这主要是由于现代操作系统的网络传输机制所产生的。我们知道,网络通信采用的套接字(socket)技术,其实现实际是由系统内核提供一片连续缓存(流缓冲)来实现应用层程序与网卡接口之间的中转功能。多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使数据包的边界发生错位,导致读出错误的数据分包,进而曲解原始数据含义。

1.2  粘包的概念

粘包问题的本质就是数据读取边界错误所致,通过下图可以形象地理解其现象。

如图1所示,当前的socket缓存中已经有6个数据分组到达,其大小如图中数字。而应用程序在对数据进行收取时(如图2),采用了300字节的要求去读取,则会误将pkg1和pkg2一起收走当做一个包来处理。而实际上,很可能pkg1是一个文本文件的内容,而pkg2则可能是一个音频内容,这风马牛不相及的两个数据包却被揉进一个包进行处理,显然有失妥当。严重时可能因为丢了pkg2而导致软件陷入异常分支产生乌龙事件。

因此,粘包问题必须引起所有软件设计者(项目经理)的高度重视!

那么,或许会有读者发问,为何不让接收程序按照100字节来读取呢?我想如果您了解一些TCP编程的话就不会有这样的问题。网络通信程序中,数据包通常是不能确定大小的,尤其在软件设计阶段无法真的做到确定为一个固定值。比如聊天软件客户端若采用TCP传输一个用户名和密码到服务端进行验证登陆,我想这个数据包不过是几十字节,至多几百字节即可发送完毕,而有时候要传输一个很大的视频文件,即使分包发送也应该一个包在几千字节吧。(据说,某国电信平台的MW中见到过一次发送1.5万字节的电话数据)这种情况下,发送数据的分包大小无法固定,接收端也就无法固定。所以一般采用一个较为合理的预估值进行轮询接收。(网卡的MTU都是1500字节,因此这个预估值一般为MTU的1~3倍)。

粘包现象

  

  说粘包之前,我们先说两个内容,1.缓冲区、2.windows下cmd窗口调用系统指令

  9.1 缓冲区(下面粘包现象的图里面还有关于缓冲区的解释)

    

每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。

write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。

TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。

read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。

这些I/O缓冲区特性可整理如下:

1.I/O缓冲区在每个TCP套接字中单独存在;
2.I/O缓冲区在创建套接字时自动生成;
3.即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
4.关闭套接字将丢失输入缓冲区中的数据。

输入输出缓冲区的默认大小一般都是 8K,可以通过 getsockopt() 函数获取:

1.unsigned optVal;
2.int optLen = sizeof(int);
3.getsockopt(servSock, SOL_SOCKET, SO_SNDBUF,(char*)&optVal, &optLen);
4.printf("Buffer length: %d\n", optVal);

socket缓冲区解释

9.2 windows下cmd窗口调用系统指令(linux下没有写出来,大家仿照windows的去摸索一下吧)

    a.首先ctrl+r,弹出左下角的下图,输入cmd指令,确定

      

    b.在打开的cmd窗口中输入dir(dir:查看当前文件夹下的所有文件和文件夹),你会看到下面的输出结果。

      

      另外还有ipconfig(查看当前电脑的网络信息),在windows没有ls这个指令(ls在linux下是查看当前文件夹下所有文件和文件夹的指令,和windows下的dir是类似的),那么没有这个指令就会报下面这个错误

      

linux shell中一个运行多个命令,命令间用;隔开即可

windows的命令提示符中运行多条命令用的是:&&、||、&

aa && bb
就是执行aa,成功后再执行bb

aa || bb
先执行aa,若执行成功则不再执行bb,若失败则执行bb

a & b
表示执行a再执行b,无论a是否成功

“执行成功”的意思是返回的errorlevel=0

windows下执行多条指令

windows下执行多条指令

原文地址:https://www.cnblogs.com/H1050676808/p/10226438.html

时间: 2024-07-31 23:55:26

网络通信中TCP出现的黏包以及解决方法 socket 模拟黏包的相关文章

sun.misc.BASE64Encoder找不到包,解决方法

右键项目->属性->java bulid path->jre System Library->access rules->resolution选择accessible,下面填上** 点击确定即可 Jun-1: sun.misc.BASE64Encoder找不到jar包的解决方法 1.右键项目->属性->java bulid path->jre System Library->access rules->resolution选择accessible

3D商城服务器开发过程中遇到的问题,原因以及解决方法。。。

问题:???? 前端场景多出来一个或者几个"死人"(这个问题在中央服务器和好友服务器中可能同样存在,只是场景服务器的表现比较明显) 玩家进入场景的包流向如下:玩家客户端-->连接服务器-->中央服务器-->连接服务器--场景服务器 玩家离开场景的包流向如下:玩家客户端-->连接服务器-->场景服务器 原因:???? 1.客户端向服务器发送了两次进入场景的包 2.玩家刚发出进入场景的包之后立即断开与连接服务器的连接,此时进入场景服务器的包还停留在中央服务器,

为什么default package包里面的方法不能被其他包调用

为什么defalut package 包里面的方法不能被其他包调用呢? 原因是defalut是默认的意思: default package是缺省包.也就是defalut package 是没有名字的包.其它的包如果要调用缺省包中的类,必须插入包名.但是缺省包却无名,所以不能够直接调用! 原文地址:https://www.cnblogs.com/ccq-190203/p/10393541.html

Ubuntu中找不到pip3命令的解决方法

Ubuntu中找不到pip3命令的解决方法 Ubuntu 有 python2 和 python3. 今天使用 Ubuntu 中的 python3 时,想要安装第三方库却发现 pip 指向的是 python2 . 因为记得 Ubuntu 系统默认将 python3 的 pip 命令改成了 pip3 ,于是执行 pip3 -V ,报命令不存在. Round One 在网上搜原因,因为没有安装,遂安装: sudo apt-get install python3-pip 结果还是命令不存在. Round

【原创】关于flexviewer中引入图表时报的TypeError #1009解决方法

在自定义的widget中引入图表后,运行时出现TypeError #1009错误.本人网上查找了很多资料,其中大部分都是关于Flash中的动画效果问题,与这里的问题关系型不太大.故把问题的解决方法写在这里,与人方便,与己方便. 方法一: 1.在自定义的widget中添加如下两个方法: private function copyStyleFromParent(selector:String):void { var chartBaseStyle:CSSStyleDeclaration = style

jquery-easyui的datagrid在checkbox多选时,行选中不对应,去除高亮的解决方法

jquery-easyui的datagrid在checkbox多选时,行选中不对应,去除高亮的解决方法 工作中用到一个具有多选功能的easyui-datagrid在处理cell的点击事件时,不允许被选中行的需求. 如下图,点击"查看"时,只是为了查看详细信息,并不是需要选择行. 完成这个需求,其实只需要将datagrid的checkOnSelect属性设置为false就可以了. 然而,当设置该属性后,新的问题就随之出现了. 目前的办法是使用以下代码去除高亮:  (本来是打算处理成c

ASP.NET MVC中对Model进行分步验证的解决方法

原文:ASP.NET MVC中对Model进行分步验证的解决方法 在我之前的文章:ASP.NET MVC2.0结合WF4.0实现用户多步注册流程中将一个用户的注册分成了四步,而这四个步骤都是在完善一个Model的信息,但是又分页面填写信息的,当时我加上ModelState.IsValid这句验证代码的时候,根本没法通过验证,因为在注册的前面三步,注册用户的Model信息都没填写完整,而ModelState.IsValid是对一个实体的所有属性进行判断验证的.当时很纠结,因为刚接触Asp.net

Myeclipse中文件已经上传到服务器目录下,文件也没有被占用,但是页面中无法读取和使用问题的解决方法

这个问题是由于Myeclipse中文件不同步引起的.在Myeclipse中,工程文件是由Myeclipse自动扫描添加的,如果在外部修改了工程目录中的文件但又关闭了自动刷新功能,则会引起文件不同步.此外,在外部没有修改Myeclipse工程中的文件也有可能引起该问题. 解决方法: 有两种解决方法: 1)手动刷新.即在Myeclipse的工程目录中,右键refresh(或者按下F5). 2)配置Myeclipse的选项: a)Myeclipse启动时,刷新workspace,即勾选:window-

Win7中右下角“小喇叭”声音图标消失的解决方法?(已解决)

1.打开任务管理器. 2.右键explorer.exe选择右键结束. 3.在按ctrl+shift+Esc,或者用alter+tab切换到任务管理器. 4.文件--新建任务,输入explorer.exe,这就恢复了. Win7中右下角"小喇叭"声音图标消失的解决方法?(已解决)