V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
3dwelcome
V2EX  ›  问与答

为什么 TCP 允许多个程序绑定同一个 IP 和端口?

  •  
  •   3dwelcome · 2021-04-07 14:48:36 +08:00 · 1016 次点击
    这是一个创建于 1086 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在 Windows 上,这显然是不允许的,你可以用多个 IP 分别绑定同一个 PORT,但是不允许同一个 IP+PORT 被多次绑定。

    在 Linux 上,以前也是不允许,但后来修改了内核,从 3.9 开始,TCP 变得和 UDP 一样,可以多个程序同时监听同一个 IP+端口。

    这样的话,只要你有服务器 ROOT 权限,开一个和 nginx 一样的 80 端口程序,就可以开心和他抢数据了。

    10 条回复    2021-04-08 17:43:02 +08:00
    hxndg
        1
    hxndg  
       2021-04-07 14:57:19 +08:00
    为啥不允许呢? TCP 五元组啊,只要能在 TCP 上层区分开到底该交给谁,为啥不能绑定同一个端口呢?
    我司复杂均衡,自己实现 2-7 层,我们自己维护 PCB,实现的时候完全可以共享端口。
    当然前提是 PCB 自己维护,也就是筛选数据包给谁自己维护
    3dwelcome
        2
    3dwelcome  
    OP
       2021-04-07 15:16:05 +08:00
    @hxndg UDP 我能理解,包是单独的,最终给谁都能直接处理。
    可 TCP 是流式数据,怎么切分成小包,是底层决定的,又不是由程序决定的。
    比如 HTTP 你程序负载均衡,只拿到用户 HTTP 请求中间那么一小段,也没办法处理啊。
    hxndg
        3
    hxndg  
       2021-04-07 16:12:27 +08:00
    @3dwelcome
    首先,负载均衡可以坐在四层也可以坐在七层
    其次,你可以自己维护负载均衡,也可以让系统底层维护负载均衡。还是那句话五元组可以区分开具体该交给哪个线程了。
    lwn.net 上的介绍 https://lwn.net/Articles/542629/
    hxndg
        4
    hxndg  
       2021-04-07 16:15:28 +08:00
    你搞混了两个概念,一个是 TCP 的分包,一个是负载均衡。两个是完全不同的概念
    直接看这个网址吧,说的够简单了 https://medium.com/uckey/so-reuseport-addr-2-2-how-packets-forwarded-to-multiple-sockets-ce4b83cd0fd2
    3dwelcome
        5
    3dwelcome  
    OP
       2021-04-08 01:02:49 +08:00
    @hxndg "还是那句话,TCP 五元组可以区分开具体该交给哪个线程了。"
    不对啊。
    我百度搜了一下,五元祖就是源 IP+源端口+目标 IP+目标端口,可并不是唯一的,很容易就被中间 NAT 修改了( https://www.liangzl.com/get-article-detail-227271.html)

    那么很有可能,到具体线程里,两条不同 TCP 通道,源 IP+源端口+目标 IP+目标端口是一样的。
    首先 SO_REUSEPORT 会确保在多条 TCP 通道里,本机 IP 和本地绑定端口是一致的。
    其次 NAT 下面多条 TCP 通道里,发起 IP 和发起的端口是有可能冲突的(端口只有双字节上限,而 NAT 下面可以扩展很多电脑,每台电脑对相同服务器端口发出请求,总有电脑总连接数超过 65535,就必然会造成 TCP 五元组冲突)
    hxndg
        6
    hxndg  
       2021-04-08 07:47:31 +08:00 via Android
    算了,你说的都对,你开心就好
    3dwelcome
        7
    3dwelcome  
    OP
       2021-04-08 09:49:04 +08:00
    @hxndg 我只是好奇讨论一下。
    一般情况,一台 PC 确实只有 2 万多个客户端连接端口可用(默认 net.ipv4.ip_local_port_range = 32768 61000)。就算不用 IPV4,改用 IPV6,协议也没增加任何端口上限,还是 16bit 给写死了。
    所以如果这台 PC,刚巧是 NAT 出口,就会遇到本机端口耗尽的情况。TCP 五元祖冲突应该不会,就是 TCP 连接直接失败。
    julyclyde
        8
    julyclyde  
       2021-04-08 12:15:35 +08:00
    能理解你的提问的人都不太多
    建议你还是把“3.9 开始”那个功能的原文发上来
    SmartKeyerror
        9
    SmartKeyerror  
       2021-04-08 17:23:54 +08:00
    @hxndg 我寻思着 TCP 包里面只包含源端口号+目的端口号,IP 包里面才是源 IP 地址 + 目的 IP 地址,TCP 区分接收程序难道不是通过端口号区分的? TCP 上层是个什么东西?
    hxndg
        10
    hxndg  
       2021-04-08 17:43:02 +08:00
    @SmartKeyerror
    四层负载均衡和七层负载均衡的区别,自定协议和非自定协议而已
    而且协议栈如果自己写,想干什么干什么,为什么不能拿到五元组呢?
    如果只能利用端口号区分,那么多的负载均衡公司都是在扯淡吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3330 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:43 · PVG 21:43 · LAX 06:43 · JFK 09:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.