关于SOCKET的阻塞非阻塞recv和send

对于recv和send函数的返回完成,实际上并不是将缓冲区数据成功送入网络链路,而只是成功发送到系统缓冲区或者是系统缓冲区有数据了!这个系统缓冲区应该是驱动里分配的缓冲区,NTFS默认大小8k,一般WINDOWS 4K。

在发包时候,因为TCP提供的是流服务,导致WINSOCK接口会根据缓冲区和数据包的实际情况自由的对数据包进行组合和分割发送,也就是当客户端连续多次发送包时(<100ms),多个数据包可能会组合在一起进行了发送,也就是出现了"粘连"情况,这样客户一次收数据时可能会收到其他包的数据,也可能会发生单个数据包被分割的情况,这样接受到的只是包的一部分,需要重复接受多次才能得到一个完整的包。但不管怎样,包的内容是按发送的先后顺序到达目的端,并且保证包的完整性,只是接收数据的时候需要进行处理!

对于单线程和多线程发包阻塞情况:

send单线程:如果发送数据大于系统缓冲区长度,或者SOCKET断开则返回SOCKET_ERROR,否则函数总是在将指定大小的数据包发送完到系统缓冲区才会返回。send先检查协议是否正在发送系统缓冲区的数据,如果是就等待协议把数据发送完。

1. 系统缓冲区中没有数据,即每个send间的间隔比较长在每个send后系统一会就发送系统缓冲区中的数据了第二次发送时系统缓冲区就是空的,就保证了每次能发送一个完整的数据包!

2。协议还没有开始发送系统缓冲区中的数据即在COPY完客户缓冲区数据到系统缓冲区后到系统开始发送系统缓冲区中的数据的时间间隔内如果再发送一次包,如果这时包的长度小于剩余系统缓冲区的长度则直接再COPY,这时就发生了"粘包"现象,如果大于了系统缓冲区剩余大小则等待发送缓冲区数据全部发完再COPY进空的系统缓冲区。

send多线程:在COPY客户缓冲区数据到系统缓冲区时,每个线程在COPY过程中不会交叉,因为当一个线程COPY时会锁定系统缓冲区,等到全部COPY完另一个线程才能继续COPY。也就保证了多线程发包时每个包的完整性不会产生数据交叉。也可能会产生粘包现象。

所以不管怎样 能保证每一个定义的包的完整性!可以在接受时将定义的包从粘连包里分出来。

单线程收包和多线程收包:

recv:调用recv函数时,recv先等待系统发送缓冲中的数据被协议传送完毕,如果协议在传送系统发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,如果系统的发送缓冲中没有数 据或者数据被协议成功发送完毕后,recv先检查套接字系统的接收缓冲区,如果系统接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,只到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把系统的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把系统的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy的字节数。

多线程时必须同步取数据,否则会数据会被不同线程获得。

也可能产生多次发送包后,系统接受缓冲区有几个包的数据,可以分批接受也可以一次接受完毕

你可能感兴趣的:(多线程,windows,网络,socket,tcp)