在UDP协议中,一个socket由源IP和源端口唯一标识。
在TCP协议中,socket由源IP、源端口、目的IP和目的端口唯一标识。为什么TCP协议需要两条额外的信息
NB 对于 TCP 术语,套接字是地址-端口对;一对套接字定义了连接。(根据RFC 793 p5)
恐怕您对 UDP 有误解,尽管它实际上并没有“套接字”——即使伯克利套接字库这样称呼它们,而且调用地址-端口对是合理的——多路复用本质上与TCP相同的方式。
您可以看到这种情况的典型情况是从一台主机到同一个 DNS 服务器同时进行多个 DNS 解析,其中显然只有源端口号必然不同。您可以看到这与从一个客户端到单个 Web 服务器的多个并发 TCP 连接完全相同。
UDP 具有无连接数据报。主机 A 从地址-端口对发送数据报,定向到 B 的地址-端口对,通常但不总是以镜像方式回复。更宽松地谈论“通信”,它在与 TCP 连接完全相同的 4 元组上运行。
有时您会看到对(协议、源地址、源端口、目标地址、目标端口)的 5 元组的引用,其中协议为 17 表示 UDP,6 表示 TCP 等。这是大多数防火墙、路由器等使用的NAT 和类似的操作来识别这个通信对。
即使服务器已经在不同的端口上专门为该会话建立了一个 TCP 套接字
恐怕您对 TCP 也有误解,可能是因为 TCP 协议 (RFC 793) 的定义与其最常见的实际实现,即 Unix 中使用的 Berkeley Sockets Library 之间的术语冲突,并且一切都来自它。
如果您专注于协议,那就更清楚了:没有“不同的端口”。例如,Web 服务器仅侦听 1.1.1.1 端口 80。客户端仅从2.2.2.2 端口 56789 发送。每个数据包将是 1.1.1.1:80 到 2.2.2.2:56789,反之亦然; 通过使用 tcpdump/wireshark/etc 查看数据包可以轻松验证。
(要非常简要地离题的伯克利实现中,TCP连接用一个整数通常但容易混淆称为表示sockfd
;一个TCP套接字由a表示struct sockaddr
的。accept()
系统调用很容易混淆讲制作一个“新连接的套接字”,它指的的新连接连接状态下的结构。这个结果的元组在我们的例子中是 (1.1.1.1, 80, 2.2.2.2, 56789)。关于 UDP,该库允许您将 UDP 视为已连接,这是描述两个进程之间的 UDP 数据报交换的一种方便如果完全错误的方式,只是意味着结构记住了远地址-端口对,这在编程术语中使 UDP “连接”看起来就像一个 TCP 连接。请记住,Berkeley 库不仅适用于 IP,而且对几种不同的底层网络系统进行了概括。如果你想跟进这些网络编程术语,我建议 Stack Overflow,它有很多非常称职的网络程序员。)