尽管已经解除了系统对用户同时打开文件数的限制,但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接。
原因一: 本地端口号范围有限制
问题出在connect()调用返回失败,查看系统错误提示消息是 “Can’t assign requestedaddress”。同时,如果在此时用
tcpdump
工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况说明问题在于本地Linux系统内核中有限制。其实,问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如间)。当系统中某一时刻同时存在太多的TCP客户端连接时,由于每个TCP客户端连接都要占用一个唯一的本地端,内核限制本地端口号的范围为1024~32768之中),如果现有的TCP客户端连接已将所有的本地端口号占满,则此时就无法为新的TCP客户端连接分配一个本地端口号了,因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设为“Can’t assignrequested address”。有关这些控制逻辑可以查看Linux内核源代码,以linux2.6内核为例,可以查看tcp_ipv4.c文件中如下函数:
static int tcp_v4_hash_connect(struct sock *sk)
请注意上述函数中对变量 sysctl_local_port_range
的访问控制。变量 sysctl_local_port_range
的初始化则是在 tcp.c 文件中的如下函数中设置:
void __init tcp_init(void)
解决方案:
vim /etc/sysctl.conf
net.ipv4.ip_local_port_range = 1024 65000 # 端口范围的最大值则应小于或等于65535,理论上单独一个进程最多可以同时建立60000多个TCP客户端连接
sysctl -p
原因二:Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制。
此时程序会表现为在 connect()调用中阻塞,如同死机,如果用 tcpdump 工具监视网络,也会发现根本没有 TCP 连接时客户端发 SYN 包的网络流量。
由于 IP_TABLE防火墙在内核中会对每个TCP连接的状态进行跟踪,跟踪信息将会放在位于内核内存中的conntrackdatabase中,
这个数据库的大小有限,当系统中存在过多的TCP连接时,数据库容量不足,IP_TABLE无法为新的TCP连接建立跟踪信息,于是表现为在connect()调用中阻塞。
此时就必须修改内核对最大跟踪的TCP连接数的限制,方法同修改内核对本地端口号范围的限制是类似的:
vim /etc/sysctl.conf
net.ipv4.ip_conntrack_max = 10240 # 系统对最大跟踪的TCP连接数限制设置为10240,此限制值要尽量小,以节省对内核内存的占用。理论上单独一个进程最多可以同时建立10000多个TCP客户端连接
$ sysctl -p