linux下TCP编程
tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下,send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但 在非阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,如果缓存区可用空间不够,则尽能力的拷贝,返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN. linux下可用sysctl -a | grep net.ipv4.tcp_wmem查看系统默认的发送缓存大小: net.ipv4.tcp_wmem = 4096 16384 81920 这有三个值,第一个值是socket的发送缓存区分配的最少字节数,第二个值是默认值(该值会被net.core.wmem_default覆盖),缓存区在系统负载不重的情况下可以增长到这个值,第三个值是发送缓存区空间的最大字节数(该值会被net.core.wmem_max覆盖). 根据实际测试,如果手工更改了net.ipv4.tcp_wmem的值,则会按更改的值来运行,否则在默认情况下,协议栈通常是按net.core.wmem_default和net.core.wmem_max的值来分配内存的. 应用程序应该根据应用的特性在程序中更改发送缓存大小: socklen_t sendbuflen = 0; socklen_t len = sizeof(sendbuflen); getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len); printf("default,sendbuf:%dn", sendbuflen); sendbuflen = 10240; setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, len); getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len); printf("now,sendbuf:%dn", sendbuflen); 需要注意的是,虽然将发送缓存设置成了10k,但实际上,协议栈会将其扩大1倍,设为20k. -------------------实例分析---------------------- 在实际应用中,如果发送端是非阻塞发送, A. 发送应用程序认为send完了10k数据,关闭了socket: 发送主机作为tcp的主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对方的ack),并且,发送缓存中的8k数据并不清除,依然会发送给对端.如果接收应用程序依然在recv,那么它会收到余下的8k数据(这个前题是,接收端会在发送端FIN_WAIT1状态超时前收到余下的8k数据.),然后得到一个对端socket被关闭的消息(recv返回0).这时,应该进行关闭. B. 发送应用程序再次调用send发送8k的数据: 假如发送缓存的空间为20k,那么发送缓存可用空间为20-8=12k,大于请求发送的8k, 假如发送缓存的空间为12k,那么此时发送缓存可用空间还有12-8=4k,send()会返回4096,应用程序发现返回的值小于请求发送的大小值后,可以认为缓存区已满,这时 C. 接收应用程序在处理完1k数据后,关闭了socket: 接收主机 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |