![每个主机的 TCP 源端口是否必须是唯一的?](https://linux22.com/image/566036/%E6%AF%8F%E4%B8%AA%E4%B8%BB%E6%9C%BA%E7%9A%84%20TCP%20%E6%BA%90%E7%AB%AF%E5%8F%A3%E6%98%AF%E5%90%A6%E5%BF%85%E9%A1%BB%E6%98%AF%E5%94%AF%E4%B8%80%E7%9A%84%EF%BC%9F.png)
我了解到 TCP 连接由三元组 (源 IP、源端口、目标 IP、目标端口) 标识。理论上,因此应该可以让来自 host1:port1 的客户端连接到 server1:port1,同时另一个客户端 (在 host1 上运行) 从 host1:port1 连接到 server2:port1。
我已经用 Java 进行了一些测试,到目前为止似乎是可行的。
但是,我多次读到,源端口对于主机地址必须是唯一的,这基本上意味着并发传出 TCP 连接数最多为 65536 个。这是真的吗?
更新:这是我的 Java 代码。这似乎有效,并且 netstat -t 清楚地显示二从端口 9990 发起活动传出连接(一个到 9997,一个到 9998)。至少在现代 Linux 上,这似乎是可能的?
Socket s1 = new Socket();
s1.setReuseAddress(true);
SocketAddress saremote = new InetSocketAddress("localhost",9999);
SocketAddress salocal = new InetSocketAddress("localhost",9990);
s1.bind(salocal);
s1.connect(saremote);
Socket s2 = new Socket();
s2.setReuseAddress(true);
SocketAddress saremote2 = new InetSocketAddress("localhost",9998);
SocketAddress salocal2 = new InetSocketAddress("localhost",9990);
s2.bind(salocal2);
s2.connect(saremote2);
netstat -t 输出(截断):
tcp6 0 0 localhost:9990 localhost:9998 CONNECTED
tcp6 0 0 localhost:9990 localhost:9999 CONNECTED
答案1
这不是 TCP 的要求。就 TCP 而言,只有源 IP、源端口、目标 IP 和目标端口的组合才需要唯一。然而,实际上,大多数 TCP API 不提供任何方法来创建具有相同源端口的多个连接,除非它们具有不同的源 IP 地址。
答案2
这是实际的最大值,通常更低。例如,Linux 使用net.ipv4.ip_local_port
内核参数来定义用于出站连接的端口。这通常是这样的
sysctl net.ipv4.ip_local_port_range 32768 to 61000
您可以使用 sysctl 增加可用数量,例如
sysctl -w net.ipv4.ip_local_port_range="10000 64000"
或者你可以用相同的信息编辑 /etc/sysctl.conf
net.ipv4.ip_local_port_range = 10000 65535
我发现的所有例子也都表明最小值也是 1024。
答案3
除了 Iain 的回答(上文)之外,内核可能只允许 10,000 个端口用于传出连接,理论上,适配器上每个 IP 地址至少限制为一组 XX,XXX 端口。由于 127.1 不对外开放,位于本地网络上,因此对于每个其他 IP 地址(外部的)您的 65K 端口范围内有一组传出端口。
因此,实际的传出限制是:
With 1 IP Address: XX,XXX (or 2 x XX,XXX on internal network)
With 2 IP addresses: 2 x XX,XXX (or 3 x XX,XXX on internal network)
With 3 IP addresses: 3 x XX,XXX (or 4 x XX,XXX on internal network)
etc.
为了做到这一点,你需要阅读以下答案此主题。
答案4
尽管系统可能对打开的 TCP 连接数有限制,但通常对使用的端口号没有限制。但是,良好的 TCP 实现必须防止两次使用同一对套接字。(套接字 = IP 地址 + 端口)。但是,将端口分配给进程以防止窃取连接,通常的方法是请求一个空闲端口作为监听端口或传出端口。这可以防止重复的传出套接字,从而防止重复的连接。如果不使用该方法,应用程序本身必须防止创建重复的连接。