为什么改变SO_RCVBUF的值没有效果?

11

我正在编写一个程序,创建一个RAW套接字以便读取所有的流量。在调用socket()和recvfrom()之间(后者在循环中,以获取缓冲区中的所有数据包),我等待5秒。

当我运行程序时,我使用hping3命令发送大约200个数据包到我的程序中的“更快模式”(以尽快填充缓冲区)。一旦5秒钟过去,我的程序从缓冲区中提取大约150个数据包。

我尝试更改接收缓冲区的大小以获得更好的结果:

int a = 65535;
if ( (setsockopt(sockfd, 0, SO_RCVBUF, &a ,sizeof(int)) ) < 0 )
{
    fprintf(stderr, "Error setting sock opts..\n");
}

然而,无论 « a » 的值是 1 还是 10000000,似乎什么也没有改变,我仍然从缓冲区中得到大约150个数据包。

问题出在哪里呢?

编辑:使用 getsockopt 调用验证了 « a » 的值。


你能给我们展示更多的代码吗,包括相关的socket()等调用?告诉我们你使用的操作系统可能也会有所帮助。 - Daniel Roethlisberger
当然,我在 Linux 3.2 64位系统下运行此程序。调用 socket() 函数:sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP) - Flow
2个回答

18

如果仍然无法正常工作,您也可能受到操作系统的限制。请检查以下值:

/proc/sys/net/core/rmem_default
/proc/sys/net/core/rmem_max
如果像你在示例中说的那样是TCP,而不是原始套接字,你还可以检查以下值:
/proc/sys/net/ipv4/tcp_mem

如果你在这些文件上运行cat命令,它们将向你显示当前的设置。 要永久更改它们,请使用sysctl。 在开始更改之前,最好将这些设置写下来。 这里有一个很棒的教程,教你如何进行这些更改: http://fasterdata.es.net/fasterdata/host-tuning/linux/


谢谢你,我已经增加了rmem_max的值,现在它运行得非常好,我可以获取所有的数据包。 - Flow
你有关于Windows的任何想法吗?我们可以在哪里检查这些值? - sreepurna
1
作为特权进程(CAP_NET_ADMIN),您可以使用SO_RCVBUFFORCE而不是SO_RCVBUF来忽略rmem_max限制。 - scai

12

setsockoptlevel参数应该是SOL_SOCKET,而不是0

int a = 65535;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &a, sizeof(int)) == -1) {
    fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno));
}

谢谢,它现在工作得很好,值已经改变。但是接收缓冲区的限制为262142,如果一个数据包大小为50字节,那么内存中应该有大约5200个数据包,而不仅仅是150个? - Flow
1
请注意,缓冲区大小有一个由/proc/sys/net/core/rmem_max定义的上限。如果您需要更大的缓冲区,则需要更改此全局限制,或者作为特权进程(CAP_NET_ADMIN),您可以使用SO_RCVBUFFORCE而不是SO_RCVBUF来忽略rmem_max限制。 - scai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接