这两天看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. Extjs gridPanel 动态指定表头

    var colMArray = new Array(); colMArray = [{header : "产品代码", dataIndex : "cpdm", ...

  2. pytest文档27-pytest分布式执行(pytest-xdist)

    前言 平常我们手工测试用例非常多时,比如有1千条用例,假设每个用例执行需要1分钟.如果一个测试人员执行需要1000分钟才能执行完,当项目非常紧急的时候, 我们会用测试人力成本换取时间成本,这个时候多找 ...

  3. Apache2.2.16+PHP5.3.3+MySQL5.1.49的配置方法

    第一步:下载安装的文件 1. MySQL:下载地址mysql-5.1.49-win32.msi: 2. Apache: 下载地址httpd-2.2.16-win32-x86-openssl-0.9.8 ...

  4. CRFPP/CRF++编译安装与部署

    CRFPP/CRF++编译安装与部署 下载CRF++ https://taku910.github.io/crfpp/#download 说明:在上面网站中下载CRF++ 0.58 解压 tar zx ...

  5. DP 换硬币问题

    设有n种不同面值的硬币,现要用这些面值的硬币来找开待凑钱数m,可以使用的各种面值的硬币个数不限.    找出最少需要的硬币个数,并输出其币值. package DP; import java.util ...

  6. go语言基础之map赋值、遍历、删除 、做函数参数

    1.map赋值 示例: package main //必须有个main包 import "fmt" func main() { m1 := map[int]string{1: &q ...

  7. Word Break II leetcode java

    题目: Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where e ...

  8. IE6的3像素神奇bug:缘起与解决方案

    在我们这样一个神奇的国度,到了2014年了,居然还是有很多人的电脑上用着XP,安装的是IE6,他们没有想过要升级,我们就得想着兼容他们.... 一. 6爷我喝高了,最后一行有重影.那什么是IE6 的3 ...

  9. PS使用技巧

    1. 3.缩放工具:工具栏上放大镜图标:<1>上面图标栏可以选择激活放大还是缩小.<2>按住alt键可以切换,可以点击,也可以滚动滚轮<3>ctrl加"+ ...

  10. matlab中,怎样把矩阵中所有的0改为2

    一句话搞定:>> a(find(a==0))=[2]:把矩阵中所有的0改为2