tcp/udp套接口缓冲区

来源:互联网 发布:事件提醒软件app 编辑:程序博客网 时间:2024/04/29 20:11

概念:

   MTU:链路层上数据帧中数据的最大值,即IP数据报的整个值。详见TCP/IP第7页。数据进入协议栈的封装过程。
   MSS:TCP报文段中数据的最大值---MSS选项只能出现在SYN报文中。

TCP输出:

每个TCP套接口都有一个发送缓冲区,我们可以用SO_SNDBUF套接口选项来改变这个缓冲区的大小。当应用程序调用write时,内核从应用进程的缓冲区中拷贝所有数据到套接口的发送缓冲区。如果套接口发送缓冲区容不下应用程序所有的数据(或者应用进程的缓冲区大于套接口发送缓冲区,或者是套接口发送缓冲区还有其他数据),应用进程将被挂起,这里假设write是阻塞的。内核将不从write系统调用返回,直到将应用进程缓冲区的所有数据都拷贝到套接口发送缓冲区。因此从写一个TCP套接口的write调用成功返回仅仅代表我们重新使用应用进程的缓冲区。他并不告诉我们对端TCP或者应用进程已经接收到数据。

UDP输出:

这一次我们展示的套接口发送缓冲区用虚框表示,因为它并不存在。UDP套接口有发送缓冲区大小(SO_SNDBUF修改),不过它仅仅是写到套接口的UDP数据报的大小上限。如果应用程序写一个大于套接口发送缓冲区大小的数据报,内核将返回一个EMSGSIZE错误。既然UDP不可靠,他不必保存应用进程的数据拷贝,因此无需真正的发送缓冲区(应用进程的数据在沿协议栈往下传递,以某种形式拷贝到内核缓冲区,然而数据链路层在送出数据之后将丢弃该拷贝)。
根据上图发现,UDP没有MSS的概念,如果某个UDP应用程序发送大数据,那么他比TCP应用程序更容易分片。从UDP套接口write成功返回仅仅表示用户写入的数据报或者所有片段已经加入到数据链路层的输出队列。如果该队列没有足够的空间存放该数据报或者他的某个片段,内核通常返回给应用进程一个ENOBUFS错误(也有的系统不会返回错误)。

TCP和UDP都拥有套接口接收缓冲区。TCP套接口接收缓冲区不可能溢出,因为TCP具有流量控制(窗口).然而对于TCP来说,当接收到的数据报装不进套接口接收缓冲区时,该数据报就丢弃。UDP是没有流量控制的:较快的发送端可以很容易淹没较慢的接收端,导致接收端的UDP丢弃数据报。
我们可以用程序来验证这一点:
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #define NDG 2000  
  2. #define DGLEN 1400  
  3. client()  
  4. {  
  5.     for(int i=0;i<NDG;i++)  
  6.         sendto(sockfd,sendline,DGLEN,0,pservadd,servlen);  
  7. }  

客户端快速发送大数据报,我们在一个慢速的主机(FreeBSD)上的接收端就发现很多丢包现象。UDP套接口接收缓冲区在FreeBSD下面缺省是42080字节,也就是30*1400个字节的容纳空间。如果我们增大接收缓冲区,服务器就期望接收更多的数据报。setsockopt(sockfd,SOL_SOCKET,SO_RECVBUF,&n,sizeof(n)),其中n=220*1024,这个时候如果再次运行就会发现丢包有所改善(但并没实质解决)。

SO_RCVBU和SO_SNDBUF分别设置接收缓冲区和发送缓冲区大小。
0 0