1、两个简单概念长链接与短链接:
一、长链接 算法
Client方与Server方先创建通信链接,链接创建后不断开, 而后再进行报文发送和接收。编程
二、短链接 网络
Client方与Server每进行一次报文收发交易时才进行通信链接,交易完毕后当即断开链接。此种方式经常使用于一点对多点 通信,好比多个Client链接一个Server。tcp
二 、何时须要考虑粘包问题?函数
若是利用tcp每次发送数据,就与对方创建链接,而后双方发送完一段数据后,就关闭链接,这样就不会出现粘包问题(由于只有一种包结构,相似于http协议)。关闭链接主要要双方都发送close链接(参考tcp关闭协议)。如:A须要发送一段字符串给B,那么A与B创建链接,而后发送双方都默认好的协议字符如"hello give me sth abour yourself",而后B收到报文后,就将缓冲区数据接收,而后关闭链接,这样粘包问题不用考虑到,由于你们都知道是发送一段字符。
性能
若是发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包。
优化
若是双方创建链接,须要在链接后一段时间内发送不一样结构数据,如链接后,有好几种结构:
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" 这样接收方就傻了,究竟是要干吗?不知道,由于协议没有规定这么诡异的字符串,因此要处理把它分包,怎么分也须要双方组织一个比较好的包结构,因此通常可能会在头加一个数据长度之类的包,以确保接收。
spa
3、 粘包出现缘由:设计
在TCP传输中会出现粘包,UDP不会出现粘包,由于它有消息边界。
进程
4、解决办法:
为了不粘包现象,可采起如下三种措施:
以上提到的三种措施,都有其不足之处:
第一种编程设置方法虽然能够避免发送方引发的粘包,但它关闭了优化算法,下降了网络发送效率,影响应用程序的性能,通常不建议使用。
第二种方法只能减小出现粘包的可能性,但并不能彻底避免粘包,当发送频率较高时,或因为网络突发可能使某个时间段数据包到达接收方较快,接收方仍是有可能来不及接收,从而致使粘包。
第三种方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。
一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,如今通常可容许应用层设置8k(NTFS系)的缓冲区,8k的数据由底层分片,而应用看来只是一次发送。Socket自己分为两种,流(TCP)和数据报(UDP),你的问题针对这两种不一样使用而结论不同。甚至还和你是用阻塞、仍是非阻塞Socket来编程有关。
一、通讯长度,这个是你本身决定的,没有系统强迫你要发多大的包,实际应该根据需求和网络情况来决定。对于TCP,这个长度能够大点,但要知道,Socket内部默认的收发缓冲区大小大概是8K,你能够用setsockopt来改变。但对于UDP,就不要太大,通常在1024至10K。注意一点,你不管发多大的包,IP层和链路层都会把你的包进行分片发送,通常局域网就是1500左右,广域网就只有几十字节。分片后的包将通过不一样的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就造成丢包。显然,要是一个UDP发包佷大,它被分片后,链路层丢失分片的概率就佷大,你这个UDP包,就佷容易丢失,可是过小又影响效率。最好能够配置这个值,以根据不一样的环境来调整到最佳状态。
send()函数返回了实际发送的长度,在网络不断的状况下,它毫不会返回(发送失败的)错误,最多就是返回0。对于TCP你能够字节写一个循环发送。当send函数返回SOCKET_ERROR时,才标志着有错误。但对于UDP,你不要写循环发送,不然将给你的接收带来极大的麻烦。因此UDP须要用setsockopt来改变Socket内部Buffer的大小,以能容纳你的发包。明确一点,TCP做为流,发包是不会整包到达的,而是源源不断的到,那接收方就必须组包。而UDP做为消息或数据报,它必定是整包到达接收方。
二、关于接收,通常的发包都有包边界,首要的就是你这个包的长度要让接收方知道,因而就有个包头信息,对于TCP,接收方先收这个包头信息,而后再收包数据。一次收齐整个包也能够,可要对结果是否收齐进行验证。这也就完成了组包过程。UDP,那你只能整包接收了。要是你提供的接收Buffer太小,TCP将返回实际接收的长度,余下的还能够收,而UDP不一样的是,余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多个发包,你必须分离它们,还有就是当Buffer过小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时,密切注意这点。这些特性就是体现了流和数据包的区别。