第一个需要讨论的大概就是粘包问题了。因为这个是TCP的个性问题,UDP通信时不存在这个问题的。首先看一下什么叫粘包:

客户端采取与服务器的长连接方式建立通信(Open-Write/Read-Write/Read-……-Write/Read-Close)。即建立连接之后进行多次读写操作,最后才关闭。而且不是文件传输,而是数据结构的传输(文件传输发生粘包与没发生粘包都不会影响结果,反正都是字节流的按顺序写入本地文件)。举个例子来说明一下吧:

两种数据结构:{give me something} {don't give me anything}则粘包是则是接受到{give me something don't give me anything} 这个算是让服务器傻眼了,没见过这么诡异的数据结构,不知道怎么处理了。

上面的例子是转的网上的

来分析一下之所以发生粘包的原因吧,其实也就是为什么TCP会发生,但是UDP却不会发生的原因:TCP是面向连接流式无边界的传输方式。当传输通道建立之后,则数据流就像水一样流过来,其中没有数据边界的概念,包随便多大,因而会出现多个包最后粘成一个大包。当然这个是TCP的原因,还有就是缓冲区机制的问题,发送端在默认状况下是需要等到发送去满才发送出去,故而适当使用push刷缓冲区也可减少粘包的现象,还有就是接受缓冲区处理不及时,没有做到来一个包立马处理完这个包。

所以解决的思路大约如下:

  1. 对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满。此种方法关闭了优化算法,降低了网络发送效率,影响应用程序的性能。而且并不能保证100%不发生粘包现象。
  2. 对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象。该种思路对于接收方的程序算法结构要求较高,而且可靠性不高,因为网络通信中的并发等现象大量存在,很难真的能完全即使处理接受缓冲区而不发生粘包。
  3. 由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。该思路的问题就更大了,应用程序效率被降低太多。而且我实在不认为这个真能不发生粘包,虽然包变小了,但是并发情况的存在并不能保证接收方有足够的间隙去处理包。
  4. 预定义数据结构,单线程。字节流前面先加上包头标志位,包头中包含该包的数据长度,这样在读取的时候可按字节读取。这样可有效控制粘包问题。并可以成功避免残包的问题,且不会发生连锁反应,一个坏包的出现不会影响下一个包的正常读取。如{##Length##DataStram}。该中解决方案的优点是可以保证通信的100%准确,缺点是影响程序性能,因为按字节读取包,必定会影响程序的效率。
  5. 改进:预定义数据结构,单线程。但是不是按字节。查看头标志位,读取包长度,查看缓冲区内包长度,两者相等,则直接读取。如果缓冲区内可读字节数大于标志位描述的包长度,则按照标志位描述的包长度读取数据,如果缓冲区内刻度字节数小于标志位描述的包长度,则线程睡眠,等下一个数据包的到来。
  6. 预定义数据结构,多线程。服务器端与客户端都是多线程工作,客户端为三个主要线程:发送线程、读取线程与解析线程。服务器端为四个主要线程:监听主线程、接收、读取、解析。按照第五种的思路,拿到数据包之后直接扔给解析线程,解析线程负责数据解析以及最终结果的回调。此处比第五种多的思路就是一个多线程,从而可以很大幅度提升程序的性能。                                                                       

    预定义数据结构示意图:

    标志位

    长度

    数据

    参考链接:

http://blog.csdn.net/laoyang360/article/details/8675922

http://www.cnblogs.com/BLoodMaster/archive/2010/07/02/1770067.html

TCP连接,传输数据时的粘包问题讨论的更多相关文章

  1. C#网络编程学习(5)---Tcp连接中出现的粘包、拆包问题

    本文参考于CSDN博客wxy941011 1.疑问 我们使用第四个博客中的项目. 修改客户端为:连接成功后循环向服务器发送从1-100的数字.看看服务器会不会正常的接收100次数据. 可是我们发现服务 ...

  2. Socket 编程中,TCP 流的结束标志与粘包问题

    因为 TCP 本身是无边界的协议,因此它并没有结束标志,也无法分包. socket和文件不一样,从文件中读,读到末尾就到达流的结尾了,所以会返回-1或null,循环结束,但是socket是连接两个主机 ...

  3. UNIX网络编程——tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

  4. tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

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

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

  6. Go语言网络通信---tcp上传大文件(粘包问题还需优雅解决)

    server端: package main import ( "bufio" "encoding/binary" "fmt" "n ...

  7. tcp协议传输中的粘包问题

    什么是粘包问题 tcp是流体协议. 其nagle算法会将数据量较小. 并且发送间隔时间较短的多个数据包合并为一个发送. 网络传输的时候是一段一段字节流的发送. 在接收方看来根本不知道字节流从何开始. ...

  8. TCP 远程执行CMD (解决粘包问题) 代码

    服务端 from socket import * import subprocess,json,struct server= socket(AF_INET,SOCK_STREAM) server.bi ...

  9. TCP粘包问题

    1.什么是粘包? 粘包指的是数据与数据之间没有明确的分界线,导致不能正确的读取数据.换句话说就是接收方不知道发送方一次到底发送了多少数据.只有TCP才会出现粘包现象,UDP不会出现粘包现象,因为TCP ...

随机推荐

  1. 初学者学习javascript语言应注意的那几点

    javascript在书写时应注意得那四点: 1)大小写敏感: 2)javascript是弱类型语言,声明变量是应全部使用var(因为javascript是弱类型语言): 3)字符串在定义时使用单引号 ...

  2. 【阿里云产品公测】在Laravel4框架中使用阿里云OCS缓存

    作者:阿里云用户 supechina Laravel 是我最近用得非常多而且越用就越喜欢的一款PHP框架,由于没有向下兼容的历史包袱,完全面向对象的风格,借助 Facades 优雅的 IoC Cont ...

  3. uva 10252 - Common Permutation 字符串水题

    题意:給定兩個小寫的字串a與b,請印出皆出現在兩字串中的字母,出現的字母由a~z的順序印出,若同字母出現不只一次,請重複印出但不能超過任一字串中出現的次數.(from Ruby兔) 很水,直接比较输出 ...

  4. svn配置

    svn配置 subverson.conf <Location /svn> DAV svn SVNListParentPath on SVNParentPath /var/repo Auth ...

  5. virsh default启动失败原因分析及解决

    启动default时出现如下错误提示:[root@node1 ~]# virsh net-start defaulterror: Failed to start network defaulterro ...

  6. ios深拷贝,浅拷贝,拷贝自定义对象的简单介绍(转)

    copy语法的目的:改变副本的时候,不会影响到源对象: 深拷贝:内容拷贝,会产生新的对象.新对象计数器置为1,源对象计数器不变. 浅拷贝:指针拷贝,不会产生新的对象.源对象计数器+1. 拷贝有下面两个 ...

  7. asp.net zip 压缩传输

    在实际生产中,比如使用xml json 等传输大量数据的时候,有时候会出现等待时间过长,这里分享一个压缩传输的方法 首先到网上去下载一个 ICSharpCode.SharpZipLib.dll 的dl ...

  8. MySQL分区表的使用

    MySQL使用分区表的好处: 1,可以把一些归类的数据放在一个分区中,可以减少服务器检查数据的数量加快查询. 2,方便维护,通过删除分区来删除老的数据. 3,分区数据可以被分布到不同的物理位置,可以做 ...

  9. JavaScript--变量、作用域及内存(12)

    // JS变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已; // 由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内 ...

  10. Ubuntu 15.04 无损扩展分区(目录)容量的方法 (无需格式化, 文件不丢失)

    源 起 用了一段时间Ubuntu,碰到了UBuntu磁盘空间不足的问题, 最初我只给Ubuntu分配了30个G的空间, 昨天试用了一下VirtualBox安装了一个xp虚拟系统,用以解决Ubuntu下 ...