这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题。发现自己不是非常清楚,所以查资料了解记录一下:

一两个简单概念长连接与短连接:

1.长连接

Client方与Server方先建立通讯连接。连接建立后不断开。 然后再进行报文发送和接收。

2.短连接

Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完成后马上断开连接。此种方式经常使用于一点对多点


通讯。比方多个Client连接一个Server.

二 什么时候须要考虑粘包问题?

1:假设利用tcp每次发送数据,就与对方建立连接,然后两方发送完一段数据后,就关闭连接,这样就不会出现粘包问题(由于仅仅有一种包结构,类似于http协议)。

关闭连接主要要两方都发送close连接(參考tcp关闭协议)。如:A须要发送一段字符串给B。那么A与B建立连接,然后发送两方都默认好的协议字符如"hello give me sth abour yourself",然后B收到报文后,就将缓冲区数据接收,然后关闭连接,这样粘包问题不用考虑到,由于大家都知道是发送一段字符。

2:假设发送数据无结构,如文件传输,这样发送方仅仅管发送,接收方仅仅管接收存储就ok。也不用考虑粘包

3:假设两方建立连接,须要在连接后一段时间内发送不同结构数据,如连接后,有好几种结构:

 1)"hello give me sth abour yourself"

 2)"Don't give me sth abour yourself"

   那这种话,假设发送方连续发送这个两个包出去,接收方一次接收可能会是"hello give me sth abour yourselfDon't give me sth abour yourself" 这样接收方就傻了,究竟是要干嘛?不知道,由于协议没有规定这么诡异的字符串,所以要处理把它分包,怎么分也须要两方组织一个比較好的包结构,所以一般可能会在头加一个数据长度之类的包,以确保接收。

三 粘包出现原因:在流传输中出现。UDP不会出现粘包。由于它有消息边界(參考Windows 网络编程)

1 发送端须要等缓冲区满才发送出去,造成粘包

2 接收方不及时接收缓冲区的包。造成多个包接收

解决的方法:

为了避免粘包现象,可採取下面几种措施。

一是对于发送方引起的粘包现象。用户可通过编程设置来避免,TCP提供了强制数据马上传送的操作指令push,TCP软件收到该操作指令后。就马上将本段数据发送出去,而不必等待发送缓冲区满;二是对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象。三是由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这样的手段来避免粘包。

以上提到的三种措施。都有其不足之处。第一种编程设置方法尽管能够避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用。另外一种方法仅仅能降低出现粘包的可能性,但并不能全然避免粘包,当发送频率较高时,或因为网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收。从而导致粘包。

第三种方法尽管避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。

相关文章截取:

一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,如今一般可同意应用层设置8k(NTFS系)的缓冲区,8k的数据由底层分片,而应用看来仅仅是一次发送。windows的缓冲区经验值是4k,Socket本身分为两种。流(TCP)和数据报(UDP),你的问题针对这两种不同使用而结论不一

样。甚至还和你是用堵塞、还是非堵塞Socket来编程有关。

1、通信长度,这个是你自己决定的,没有系统强迫你要发多大的包,实际应该依据需求和网络状况来决定。对于TCP,这个长度能够大点。但要知道,Socket内部默认的收发缓冲区大小大概是8K,你能够用SetSockOpt来改变。但对于UDP,就不要太大。一般在1024至10K。注意一点。你不管发多大的包,IP层和链路层都会把你的包进行分片发送。一般局域网就是1500左右,广域网就仅仅有几十字节。分片后的包将经过不同的路由到达接收方。对于UDP而言。要是当中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包。显然,要是一个UDP发包佷大。它被分片后,链路层丢失分片的几率就佷大。你这个UDP包。就佷easy丢失,可是太小又影响效率。最好能够配置这个值,以依据不同的环境来调整到最佳状态。

send()函数返回了实际发送的长度,在网络不断的情况下,它绝不会返回(发送失败的)错误,最多就是返回0。

对于TCP你能够字节写一个循环发送。

当send函数返回SOCKET_ERROR时,才标志着有错误。但对于UDP,你不要写循环发送。否则将给你的接收带来极大的麻烦。所以UDP须要用SetSockOpt来改变Socket内部Buffer的大小,以能容纳你的发包。

明白一点,TCP作为流,发包是不会整包到达的,而是源源不断的到。那接收方就必须组包。而UDP作为消息或数据报,它一定是整包到达接收方。

2、关于接收,一般的发包都有包边界,首要的就是你这个包的长度要让接收方知道,于是就有个包头信息,对于TCP,接收方先收这个包头信息。然后再收包数据。

一次收齐整个包也能够,可要对结果是否收齐进行验证。这也就完毕了组包过程。UDP,那你仅仅能整包接收了。要是你提供的接收Buffer过小。TCP将返回实际接收的长度,余下的还能够收,而UDP不同的是。余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP。要是你提供的Buffer佷大,那么可能收到的就是多个发包。你必须分离它们。还有就是当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时,密切注意这点。

这些特性就是体现了流和数据包的差别。

相关參考文章:

http://www.cnblogs.com/alon/archive/2009/04/16/1437600.html

TCP Socket 粘包的更多相关文章

  1. golang中tcp socket粘包问题和处理

    转自:http://www.01happy.com/golang-tcp-socket-adhere/ 在用golang开发人工客服系统的时候碰到了粘包问题,那么什么是粘包呢?例如我们和客户端约定数据 ...

  2. C/C++ socket编程教程之九:TCP的粘包问题以及数据的无边界性

    C/C++ socket编程教程之九:TCP的粘包问题以及数据的无边界性 上节我们讲到了socket缓冲区和数据的传递过程,可以看到数据的接收和发送是无关的,read()/recv() 函数不管数据发 ...

  3. Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

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

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

  5. [转]关于Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

  6. python 网络编程之TCP传输&粘包传输

    只有TCP有粘包现象,UDP永远不会粘包. 所谓粘包问题主要还是C/S两端数据传输时 因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的 根本原因:粘包是由TCP协议本身造成的,T ...

  7. python 全栈开发,Day35(TCP协议 粘包现象 和解决方案)

    一.TCP协议 粘包现象 和解决方案 黏包现象让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)执行远程命令的模块 需要用到模块subprocess sub ...

  8. TCP通信粘包问题分析和解决

    转载至https://www.cnblogs.com/kex1n/p/6502002.html 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发 ...

  9. TCP通信粘包问题分析和解决(全)(转)

    TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...

随机推荐

  1. 使用开源库 SDWebImage 异步下载缓存图片(持续更新)

    source  https://github.com/rs/SDWebImage APIdoc  http://hackemist.com/SDWebImage/doc Asynchronous im ...

  2. java 查询oracle数据库所有表DatabaseMetaData的用法

    DatabaseMetaData的用法(转) 一 . 得到这个对象的实例 Connection con ; con = DriverManager.getConnection(url,userName ...

  3. vim/vi 命令详解

    在工作中,要对服务器上的文件进行的修改,可以使用ssh远程登录到服务器上,并且使用vi进行快速的编辑即可,在没有图形界面的环境下,要编辑文件,vi是最佳选择! vi命令是Linux中最经典的文本编辑器 ...

  4. QT学习:c++解析html相关

    原来我做爬虫的时候,对页面进行解析的时候总是用很简单粗暴的方法,直接找规律.后来在网上看到了gumbo,尝试了一下,发现确实很好用,所以向大家推荐一下. 以下转自:http://blog.csdn.n ...

  5. 结合实例详解"pure Virtual function called"

    作者:阿波 链接:http://blog.csdn.net/livelylittlefish/article/details/9750593 (4年前的一篇文章,翻出来共享一下.) 本实例即为经典的讲 ...

  6. Median of Two Sorted Array leetcode java

    题目: There are two sorted arrays A and B of size m and n respectively. Find the median of the two sor ...

  7. AngularJs HTTP响应拦截器实现登陆、权限校验

    $httpAngularJS 的 $http 服务允许我们通过发送 HTTP 请求方式与后台进行通信.在某些情况下,我们希望可以俘获所有的请求,并且在将其发送到服务端之前进行操作.还有一些情况是,我们 ...

  8. nginx 域名绑定 域名, nginx 域名绑定 端口

    一.nginx 域名绑定 域名 nginx绑定多个域名可又把多个域名规则写一个配置文件里,也可又分别建立多个域名配置文件,我一般为了管理方便,每个域名建一个文件,有些同类域名也可又写在一个总的配置文件 ...

  9. 前端要给力之:URL应该有多长?

    URL到底应该有多长?我为什么要提这个问题呢?有许多优化指南里都写着:要尽量减小COOKIE.缩短URL,以及尽可能地使用GET请求等等,以便优化WEB页面的请求和装载.但是,这种所谓“尽可能”.“尽 ...

  10. 关于一道JS面试题的思考

    题目: ; i < ; i++) { setTimeout(function() { console.log(new Date, i); }, ); } console.log(new Date ...