TCP Listen 原语:端口失衡、对称性及协议演进

devtools/2025/1/8 1:47:35/

TCP 最初就是作为 server 存在的,参见 RFC675 The TCP as a POST OFFICE,但最初它以一种很奇怪的方式定义这个 C/S 结构:

  • Server 指定 local address 和 foreign address,只有来自该特定 foreign address 的 packet 发往该 local address 被接受;
  • Server 指定 local address 但不指定 foreign address,任何 packet 发往 local address 被接受;

好比你去一个办事机构办事,要么预约专门的业务员,他只接待你,要么直接去大厅,有空闲业务员就为你服务。

现在我们知道,RFC793 将这些操作标准化成了 TCP Listen 原语。随之 server socket 的 bind-listen-accept 三步实现就成了约定俗成,留给 client 的只有一个 connect。

基于以上 TCP 最初的假设,server 和 client 并不对称,但 sport 和 dport 却是对称的,均为 16bit,这就带来了问题。我们知道,由于 server TCP 的 Listen 状态属性,client 数量在概率上一定比 server 更多,因此在概率上 sport 和 dport 的使用明显出现偏斜,client 端口逐渐不够用,server 端口用不完。

此前一篇文章的一个讨论:再谈 TCP 连接的源端口选择:

A:想起来前不久看过的这篇文章:谈谈 Linux 与 LACP 链路聚合,就是讲了因为这个看上去聪明的端口号分配优化,而导致了严重的互操作性问题。确实 16bit 端口号还是太少了,太容易碰撞了
B->A:没有那么容易碰撞,端口选择又不是每次从0蛋开始选择,你看下具体的实现里面有一个hint,标记了历史选择的位置。Eric提出的奇偶算法纯粹为了google内部的大量场景考虑的。不是16位不够用,是用什么算法的问题,算法二选一就行。
我->(A, B):
在持续连接存活时间不超过 MSL/65535 时 16bit 端口号在事实上就是不够用,神仙也救不了,说的就是这个,hint 不 hint 跟够不够用无关,如果端口号空间足够大,hint 就类似于递增一个全局计数器。
而 Google 算法只是针对特殊场景缓解了 bind 和 connect 的互斥热点问题,但它带来的问题是在端口不够用时不能快速失败从而导致了新的热点,还不如原始算法。只要把 port 增加几个 bit,算法就可以极大简化,如果 port 有 64bit,直接无脑递增全局计数器即可,而现代内存和带宽根本不在乎浪费几十个比特的空间,但程序员能掰扯的活儿也少了很多。另外,几乎所有新协议,无论 quic,还是 falcon,在多路复用标识的数位选择上都倾向于使用更多的位,以避免精巧的算法。

如果 TCP 最初标准化 Listen 结构,使用 20bit sport/12bit dport 或许更合理,在现有的实现中,我们依然可以用一种完全不同的算法将针对 sport,dport 的选择问题打偏,劳力往 server 端倾斜,毕竟 Listen socket 太省事了,get_port 四元组唯一性检测工作全都是 client 在做。

我们可以将 dport 的低 8bit 作为 server port,而高 8bit 作为 connection 唯一性标识的一部分(低 10bit,高 6bit 这么分割也 OK):

  • client 将解放 get_port 劳力,使用 24bit sport 消除端口不足以及因其导致的热点问题(比如 Google 的 bind/connect 奇偶分离);
  • server 在 Listen $port 时,实际 Listen 的端口号为 for p in range(0, 65535): lport[i] = p + port.
    server 从 65535 个 lport 中 accept。

这需要分别修改 server 和 client 的实现且无法向前兼容,适用于能自主控制的系统,但如果都能自主控制了,直接改协议不香吗?

但说白了还是端口号空间太小,不够用,你看 Quic 的 short-header,long-header 的多字节 Connection ID 以及 Falcon header 中 24bit ID,都是足足够用的,这让连接唯一性保证更加简单。

更值得一提的是,与 TCP 直接用 dport 解复用不同,Quic 直接在 UDP 层面接收所有报文,在服务自身去维护状态机和连接管理,而 Falcon 用 <Host, PF, VF> 这种具备明确含义的 tuple 编码来解复用,相当于自带了寻址,商品和服务在摆在那里,随到随用,这种自助结构比 TCP Server 的 Listen 结构有了更多弹性。

TCP 需要在服务标识和 dport 之间加一个中间层才能形成类似的结构,这对新协议的设计具有意义。以一个 Http 服务为例,服务发现机制应该返回一个 ‘该 Http 服务标识’,而不是一个 Host:Port 对。针对该服务的 Packet 应该对 ‘该 Http 服务标识’ 寻址,随后 ‘该 Http 服务标识’ 到 port 的映射自然就可以一对多了。就像我上面的新改版,client 通过服务发现机制获取 IP:80 作为 ‘该 Http 服务标识’,而 ‘该 Http 服务标识’ 则映射了 65535 个端口。

回到 TCP 最初,如果没有 Listen 原语,TCP 或可以用另一种更对称的方式打开一个连接,事实上 TCP 一直支持同时打开,参考 RFC793 Figure 8.:

      TCP A                                            TCP B1.  CLOSED                                           CLOSED2.  SYN-SENT     --> <SEQ=100><CTL=SYN>              ...3.  SYN-RECEIVED <-- <SEQ=300><CTL=SYN>              <-- SYN-SENT4.               ... <SEQ=100><CTL=SYN>              --> SYN-RECEIVED5.  SYN-RECEIVED --> <SEQ=100><ACK=301><CTL=SYN,ACK> ...6.  ESTABLISHED  <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED7.               ... <SEQ=101><ACK=301><CTL=ACK>     --> ESTABLISHEDSimultaneous Connection Synchronization

摆脱了 Listen 原语的调用,但却对调用时序的要求更严格。如果为了实现完全的非 Listent 对称被动打开,被动打开方只需收到 SYN 后发 SYN 即可,合并 SYN-SENT,SYN-RECEIVED 状态。

以这种方式打开的 TCP 连接 “更容易” 获得对称性,sport + dport 逐渐就成了类似 Quic,Falcon 等协议中 Connection ID 的含义。这其中就是协议演进本身的过程。

仍以目标 80 端口为例看 TCP server 和 client 的行为:

  • TCP client:自选并填充 sport + dport 高 8bit,dport 低 8bit 固定为 80,发起 SYN;
  • TCP server:dport 低 8bit 80 定位服务,sport + dport 高 8bit 标识连接,发起 SYN;
  • 执行同时打开。

总结,TCP Listen 原语导致了 sport,dport 用量的倾斜,特别在 Web 兴起之后加重了倾斜,而 sport 16bit 空间太小不足以支撑这种倾斜的力量。

浙江温州皮鞋湿,下雨进水不会胖。


http://www.ppmy.cn/devtools/148003.html

相关文章

代码实战:基于InvSR对视频进行超分辨率重建

Diffusion Models专栏文章汇总:入门与实战 前言:上一篇博客《使用Diffusion Models进行图像超分辩重建》中讲解了InvSR的原理,博主实测的效果是非常不错的,和PASD基本持平。这篇博客就讲解如何利用InvSR对视频进行超分辨率重建。 目录 环境准备 代码讲解 环境准备

2024小迪安全信息收集第八课

目录 一、APP应用-公开信息-知识产权&开发者定位 移动安全 逻辑安全问题 二、APP应用-资产信息-抓包&静态提取&动态调试 #公开信息收集 #APP资产提取 一、APP应用-公开信息-知识产权&开发者定位 APP渗透测试的范围应涵盖APP所有功能和组件&#xff0c;包…

面试场景题系列:设计爬虫系统

在本章&#xff0c;我们重点讨论网络爬虫的设计&#xff0c;这也是一个有趣且经典的系统设计面试问题。 网络爬虫&#xff08;Web Crawler&#xff0c;下文简称为“爬虫”&#xff09;也称为机器人(Bot)或者蜘蛛(Spider)&#xff0c;被搜索引擎广泛地用于发现网络上的新内容或…

鸿蒙HarmonyOS开发:基于Swiper组件和自定义指示器实现多图片进度条轮播功能

文章目录 一、概述1、场景介绍2、技术选型 二、实现方案1、图片区域实现2、底部导航点设计3、手动切换 三、所有代码1、设置沉浸式2、外层Tabs效果3、ImageSwiper组件 四、效果展示 一、概述 在短视频平台上&#xff0c;经常可以见到多图片合集。它的特点是&#xff1a;由多张…

解决海康相机SDK导致 `libusb_set_option` 问题的经验总结

在使用海康相机SDK时&#xff0c;可能会遇到以下问题&#xff1a; 问题描述 当编译某些ROS代码时&#xff0c;出现类似错误&#xff1a; /usr/bin/ld: …/…/lib/libpcl_io.so.1.8.0: undefined reference to libusb_set_option’ 原因分析 安装海康相机SDK后&#xff0c;系…

Django REST framework 源码剖析-视图类详解(Views)

Django REST framework视图图解 视图类&#xff08;View&#xff09; ‌视图‌是DRF中处理用户请求的基本单元。它们可以是函数视图&#xff08;FBV&#xff09;或类视图&#xff08;CBV&#xff09;。函数视图使用函数来处理请求&#xff0c;而类视图则使用类来处理请求。类视…

网络安全:路由技术

概述 路由技术到底研究什么内容 研究路由器寻找最佳路径的过程 路由器根据最佳路径转发数据包 知识点&#xff0c;重要OSRF,BGP1.静态路由原理 路由技术分类 静态路由和动态路由技术 静态路由&#xff1a;是第一代路由技术&#xff0c;由网络管理员手工静态写路由/路径告知路…

docker 安装influxdb

docker pull influxdb mkdir -p /root/influxdb/data docker run -d --name influxdb -p 8086:8086 -v /root/influxdb/data:/var/lib/influxdb influxdb:latest#浏览器登录&#xff1a;http://192.168.31.135:8086&#xff0c;首次登录设置用户名密码&#xff1a;admin/admin1…