2010-07-16

经典的”服务器最多65536个连接”误解

Views: 42114 | 9 Comments

"因为TCP端口号是16位无符号整数, 最大65535, 所以一台服务器最多支持65536个TCP socket连接." - 一个非常经典的误解! 即使是有多年网络编程经验的人, 也会持有这个错误结论.

要戳破这个错误结论, 可以从理论和实践两方面来.

理论

系统通过一个四元组来唯一标识一条TCP连接. 这个四元组的结构是{local_ip, local_port, remote_ip, remote_port}, 对于IPv4, 系统理论上最多可以管理2^(32+16+32+16), 2的96次方个连接.

因为对于同一台服务器来说, 一般只有一个 local_ip, 那么, 同一台服务器可以管理 2^(16+32+16) 个连接. 而一个服务(进程, 如 Nginx 进程)一般只监听一个 local_port, 那么, 同一台服务就可以管理 2^(32+16) 个连接. 而如果从一台远端机器(所谓的 client)来连接这台服务器上的一个服务, 那么 local_ip, local_port, remote_ip 这3个变量是固定的, 那么, 就只能建立 2^16=65536 个连接了. 这就是经典的误解的来源!

如果不仅仅考虑TCP, 则是一个五元组, 加上协议号(TCP, UDP或者其它).

实践

服务器绑定一个ip:port, 然后accept连接, 所有accept的连接使用的本地地址也是同样的ip:port.

扩展内容

如果某个客户端向同一个TCP端点(ip:port)发起主动连接, 那么每一条连接都必须使用不同的本地TCP端点, 如果客户端只有一个IP则是使用不同的本地端口, 该端口的范围在*nix系统上的一个例子是32768到61000, 可以通过如下命令查看:

[root@benegg.com ~]# cat /proc/sys/net/ipv4/ip_local_port_range 
32768   61000

也就是说, 一个客户端连接同一个服务器的同一个ip:port(比如进行压力测试), 最多可以发起30000个左右的连接.

TCP客户端(TCP的主动发起者)可以在同一ip:port上向不同的服务器发起主动连接, 只需在bind之前对socket设置SO_REUSEADDR选项.

系统支持的最大打开文件描述符数(包括socket连接):

[root@benegg.com ~]# cat /proc/sys/fs/file-max
580382

单个进程所能打开的最大文件描述符数:

[root@benegg.com ~]# ulimit -n
1024

结论

无论是对于服务器还是客户端, 认为"一台机器最多建立65536个TCP连接"是没有根据的, 理论上远远超过这个值.

另外, 对于client端, 操作系统会自动根据不同的远端 ip:port, 决定是否重用本地端口.

Related posts:

  1. 连连看游戏开发实践(1) – 算法
  2. 对P2P应用不友好的NAT
  3. Tomcat网站server.xml设置
  4. P2P穿透NAT的思路
  5. SSDB 的双主和多主配置
Posted by ideawu at 2010-07-16 16:44:50

9 Responses to "经典的”服务器最多65536个连接”误解"

  • 能使用netstat 一an查看到建立的连接数量超过65535?应该考虑的是并发连接数量 Reply
  • @ideawu 是我记错了。
    1、看了下《TCP/IP详解卷1:协议》18.11.1 和18.11.2节,所有accepted连接服务器端都是使用的监听端口
    2、登上我的vps,从多个ip浏览网站,然后用netstat -an查看了一下,的却所有accepted的连接服务器段都用的80端口,而最初的80端口仍然在监听状态。
    这说明服务器是一直使用监听的ip:port来接受连接,那么理论上可以接受的客户端连接数量是很大的,主要受限于服务器的软硬件处理能力。 Reply
    @proguru: 服务器要为这个连接分配一个新的tcp sock(套接字控制块),这个tcp sock继承listen tcp sock,所以目标IP和Port就与listen socket一样的。 Reply
  • "服务器绑定一个ip:port, 然后accept连接, 所有accept的连接使用的本地地址也是同样的ip:port."
    服务器绑定一个ip:port对,然后会一直在这个地址对上listen,但是当一个新的连接到来时,服务器要为这个连接分配一个新的端口号,建立与客户端的连接,然后继续在原来的地址对上监听。所以一个ip如果不重用端口的话,应该智能建立65536个TCP连接,也就是受端口号限制。但如果服务器端的一个端口可以对不同的客户重用,那么理论上一个服务器端口就可以连接65536个不同的客户,那么一个ip就可以建立65536*65536个连接了,这与五元组不冲突。服务端是不是用这个选项SO_REUSEADDR就可以呢? Reply
    回复proguru: 经实践, 不需要对socket/listen/accept设置特殊的参数, 即可使accept的连接都使用监听ip:port. 不知道你是实践得知"服务器要为这个连接分配一个新的端口号"呢, 还是有理论依据? Reply
  • 一个ip最多建立65536个对外的TCP连接 Reply
    @afe: 文章中介绍了,客户端连接不同的ip:port也会重用端口,没有65536限制。你的说法是错的。 Reply
    @afe: 说到点子上了,没人赞呢 Reply
    @Rming: 你可以转一下. Reply

Leave a Comment