无法打开超过1023个插座

时间:2012-03-07 20:52:26

标签: linux sockets network-programming

我正在开发一些模拟网络设备的代码。我需要运行几千个模拟“代理”,每个都需要连接到一个服务。问题是在打开1023连接后,连接开始超时,整个事情都崩溃了。

主要代码在Go中,但是我编写了一个非常简单的python脚本来重现问题。

有一点不寻常的是我们需要在创建时在套接字上设置本地地址。这是因为代理连接的设备期望明显的IP与我们应该的匹配。为此,我配置了10,000个虚拟接口(eth0:1到eth0:10000)。这些在专用网络中分配了唯一的IP地址。

python脚本就是这样(只运行到2000个连接):

import socket

i = 0
for b in range(10, 30):
    for d in range(1, 100):
        i += 1
        ip = "1.%d.1.%d" % (b, d)
        print("Conn %i   %s" % (i, ip))
        s = socket.create_connection(("1.6.1.1", 5060), 10, (ip, 5060))

如果我删除了socket.create_connection的最后一个参数(源地址),那么我可以获得所有2000个连接。

与使用本地地址不同的是,必须在建立连接之前进行绑定,因此在strace下运行的此程序的输出如下所示:

Conn 1023   1.20.1.33
bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("1.20.1.33")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("1.6.1.1")}, 16) = -1 EINPROGRESS (Operation now in progress)

如果我在没有本地地址的情况下运行,AF_INET绑定就会消失,并且可以正常运行。

因此,似乎必须对可以制作的绑定数量进行某种限制。我已经浏览了各种关于Linux上的TCP调优的链接,并且我已经尝试搞乱tcp_tw_reuse / recycle并且我已经减少了fin_timeout,并且我做了其他我不记得的事情。

这是在Ubuntu Linux(11.04,内核2.6.38(64位)上运行。它是VMWare ESX群集上的虚拟机。

在发布之前,我尝试运行python脚本的第二个实例,其中的附加内容从1.30.1.1开始。第一个脚本连接到1023个连接,但第二个脚本甚至无法完成第一个脚本,表明问题与大量虚拟接口有关。某些内部数据结构是否有限?某处有一些最大内存设置?

有人会想到Linux会导致这种局限吗?

更新

今天早上我决定尝试一下。我修改了python脚本,使用“主”接口IP作为源IP,使用10000+范围内的临时端口。该脚本现在看起来像这样:

import socket

i = 0
for i in range(1, 2000):
    print("Conn %i" % i)
    s = socket.create_connection(("1.6.1.1", 5060), 10, ("1.1.1.30", i + 10000))

这个脚本工作正常,所以这增加了我的信念,即问题与大量别名IP地址有关。

3 个答案:

答案 0 :(得分:2)

真是个DOH时刻。我正在使用netstat观察服务器,因为我没有看到大量连接,所以我认为没有问题。但最后我醒过来检查了/var/log/kernel,我发现了这个:

Mar  8 11:03:52 TestServer01 kernel: ipv4: Neighbour table overflow.

这引导我发布这篇文章:http://www.serveradminblog.com/2011/02/neighbour-table-overflow-sysctl-conf-tunning/,它解释了如何增加限制。碰撞thresh3值立即解决了问题。

答案 1 :(得分:0)

您可能希望查看与net.ipv4相关的sysctl设置。

这些设置包括maxconntrack等内容以及您可能希望调整的其他相关设置。

答案 2 :(得分:0)

您是否绝对确定问题不在服务器端连接而不关闭套接字?即服务器进程的lsof -n -p显示什么?服务器进程的plimit -p显示什么?服务器端可能无法接受任何更多连接,而客户端则获得EINPROGRESS结果。

检查ulimit是否有连接两侧打开文件的数量 - 1024太接近ulimit级别是巧合。