有关socket通信包大小的问题总结(UDP传输模式)

来源:互联网 发布:光伏智能软件 编辑:程序博客网 时间:2024/04/30 08:37

最近刚接触linux的编程,在pc机上编了两个socket通信的程序做测试,一个采用TCP的方式,另一个采用UDP的方式。不断增大传输数据包的大小,到180k大小时,UDP通信收不到包,阻塞在recvfrom(),而TCP方式仍然能正常工作。

对于用SOCK_DGRAM创建的socket来发送UDP包,假如发送的数据过大,linux kernel 下面的TCP/IP stack 会重新分成小包发送的,对于应用程序来说,不需要关心数据大小。

问题在于发送的数据大小超过了内核缓冲区的最大限制,这个限制好象是65535(默认情况下是64K)
通过使用函数setsockopt(ip_socket->socket.fd, SOL_SOCKET, SO_RCVBUF, &size, &len) ,改变接收缓冲区大小的属性。同理,setsockopt(ip_socket->socket.fd, SOL_SOCKET, SO_SNDBUF, &size, &len) 也可以改变发送缓冲区的大小。

#define RMEM_MAX (1024*200){   /* dma: 内核默认设置接收BUF为64K,工作在0!14MB/S的低速情况下,当速度大于19MB/S时LINUX就就会丢包   可以更改   /proc/sys/net/core/rmem_max 这个文件.可使用如下命令进行更改echo 200000 > /proc/sys/net/core/rmem_max.   */   FILE *f;   char buf[80];   int   rmax;   f = fopen("/proc/sys/net/core/rmem_max", "rw");   if (f) {    fread(buf, 1, sizeof(buf), f);    sscanf(buf, "%d", &rmax);     //从rmax中读取一个int赋值给buf    fclose(f);    if (rmax == 65535) {     sprintf(buf, "%d", RMEM_MAX);    //将NEW_RMEM_MAX以%d的方式输出到buf中     f = fopen("/proc/sys/net/core/rmem_max", "w");     fwrite(buf, 1, strlen(buf)+1, f);     fclose(f);     new_rmem_max = RMEM_MAX;    } else     new_rmem_max = rmax;   }}

结合以上信息总结:

1.UDP方式传输一段完整数据的大小时受内核缓冲区限制的,比如在默认情况下缓冲区大小是64K,所以对于该情况下的socket接收或者发送方,最大可以一次性发送一个64K的数据。而对于socket底层的具体实现是将64K的数据拆分成N个小数据包,内部提供机制保证数据的可靠性,例如每个包的大小为1K,则分成64个包,从服务器端发送到客户端,客户端在本地缓冲区重新组成完整的数据提交给用户。底层的实现方式应该各不相同,但是对于上层结果都是一样的。如果超过了缓冲区大小则无法完成组包出现丢包等等现象。同理,对于200K则可以发送接收200K大小的数据。