TCP中的端口号实际上是如何工作的?

32

理解端口:多个浏览器选项卡如何同时通信?

应用程序如何使用端口80 / HTTP而不与浏览器冲突?

多个客户端如何同时连接到服务器上的一个端口,比如说80?

我已经阅读了上述问题,但答案似乎是不一致的。

我想知道什么确切地定义了套接字连接,是:

(sockid, 源IP, 源端口, 目标IP, 目标端口)

还是只有:

(源IP,源端口,目标IP,目标端口)

两个不同的进程(例如,两个不同的浏览器)能否在同一个源端口上与Web服务器通信?(默认情况下,目标端口相同)

在同一浏览器的不同选项卡中会发生什么?

此外,正如某个答案中所提到的,单个网页可以同时连接到多个服务器(例如广告服务器)。连接到多个服务器时,Web浏览器(例如Chrome,Firefox)是否使用相同的端口连接到每个服务器,还是为每个服务器使用不同的端口?


我没有阅读裁判的问题,但序列号对于识别连接也有重要作用。 - rekire
3个回答

97

我知道这有点晚了,但由于这个主题仍然在互联网上存在,并且因为这是一个常见的问题,在网络上几乎没有权威的答案,所以它需要更完整、更简洁的解释,以便那些可能在此之后找到它的人。

  1. 你打开浏览器来访问一个网站,比如google.com。在指定网站的过程中,你的计算机将会随机选择一个端口号作为“源端口”。这个数字将会在49152以上(即“动态、私有或短暂端口”开始的地方),但低于65535(最高可用端口号)。所选的端口号与该浏览器“实例”相关联。

  2. 只是为了好玩,你在浏览器上打开了一个新标签,并在url行上也输入了“google.com”。你的目标是有两个不同的google.com实例在运行,因为你在寻找不同的东西。你的计算机会为该会话选择第二个端口号,与它用于第一次会话的“源”端口不同。事实上,你可以做很多次这样的操作,每个会话都会有一个唯一的“源”端口与每个实例相关联。

  3. 你的数据包发送到google.com,每个实例的目标端口号都将是端口80。Web服务器在端口80上“侦听”传入的连接请求。对于你打开的与google.com的每个会话,从计算机的角度来看,它们的目标端口始终是端口80,但是对于浏览器或浏览器上的每个选项卡的每个连接实例,源端口将唯一标识一个特定的选项卡和浏览器实例,以使它们可以在你的计算机上区分开来。

  • google.com接收到你的第一个请求。它的回复将指定端口80作为其源端口。这里有一点有趣。你从google.com收到的每个查询都将被视为一个“socket”,这是你的IP地址和与联系google.com的进程相关联的特定端口号的组合。例如,我们假设你的IP地址是165.40.30.12,并且你的计算机在与四个不同选项卡打开google.com的通信中使用的源端口号分别为61235、62421、58392和53925。这四个“套接字”将是165.40.30.12:61235、165.40.30.12:62421、165.40.30.12:58392和165.40.30.12:53925。每个“IP地址:源端口号”的组合都是唯一的,google.com将把每个实例视为唯一的。google.com响应并与“套接字”通信,即IP地址和端口的组合。

  • 你的计算机从google.com获取其响应,并通过解析端口号对它们进行分类,将来自google.com的响应分配给适当的浏览器窗口或选项卡。对于你来说没有问题,因为你每次都能在正确的窗口中看到正确的响应。

  • “但是,”你可能会想,“如果其他人意外使用与我用于源号码的相同端口号 - 比如61235怎么办?这会不会让google.com困惑?”一点都不,因为google.com正在跟踪IP地址和端口号的组合,即“套接字”。自然而然,我们真诚地希望别人使用与你使用的不同IP地址,假设152.126.11.27,并且IP地址和端口号的组合是唯一的- 152.126.11.27:61235 - 即使端口号相同也通过它们不同的IP地址进行区分。

  • 即使google.com从1000个用户获得了1000个查询,它们使用的目标端口号都是80(google.com用于接收通信的端口号),这并不重要,因为这1000个用户每个人都有唯一的IP地址。google.com通过客户端的唯一"套接字"号码来跟踪其客户端 - 它们始终必须是唯一的,对吧?这个号码由IP地址和"源"端口号码组成。即使这1000个客户端中的每一个都设法使用相同的"源"端口号码(非常不可能),它们仍然具有不同的IP地址,使它们的源"套接字"在所有其他套接字中是唯一的。

  • 当你看到它以这种方式解释时,这一切都相当简单。它清楚地表明Web服务器可以始终侦听一个端口(80)并仍然与各种客户端区分开来。它不仅仅查看在查询中接收到的IP地址 - 一开始你可能认为它们应该全部是唯一的,直到意识到你可以在该Web服务器上打开多个网页 - 但是查看源端口号码,这些元素结合起来使每个查询都是唯一的。我希望这很清楚。一旦你理解了它,这是一个优雅的系统,也很简单。


  • 本地端口应小于或等于65535,而不是小于65535。浏览器无法保证在同一网站的新选项卡中使用新连接。查询并非套接字。您忽略了HTTP keepalive。您把一些相对简单的东西变得非常复杂,使用8个点而只需要两个就足够了。 - user207421
    2
    @paul1307 - 如果能提供更多关于服务器端如何处理多个请求的信息,将使这个答案更加完整和有教育意义。 - Saurabh Goyal
    3
    如果您有两台电脑在同一个局域网中,并且浏览器恰好将PC-A上的一个Google.com实例和PC-B上的另一个Google.com实例分配了相同的端口号,那该怎么办? - Aleksandr Hovhannisyan
    在NAT场景中,有两个“源端口”在起作用。一个是原始计算机设置的源端口,另一个是路由器上的外部源端口。后者是由路由器选择的,而不是主机。由于每个主机在内部具有不同的IP地址,所以不会发生冲突。这段话是从与相关问题的回答中复制粘贴的评论:https://dev59.com/_nA75IYBdhLWcg3wYH3I#3329672 。也就是说,作为同一局域网中的主机,PC-A和PC-B将选择自己的端口,但当它们的数据包转发到路由器时,路由器还会翻译端口号,以确保端口+IP的唯一性。 - hasManyStupidQuestions
    即使路由器将IP地址转换为非唯一的地址,组合在外部网络中仍将保持唯一。因此,当远程服务器看到数据包时,它将看到相同的IP地址但两个不同的端口号(这些端口号再次由路由器选择)。"NAT [网络地址转换]术语...遵循常见的IT实践,尽管NAT设备的实际作用是地址转换和端口地址转换(PAT)",摘自https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat.html。 - hasManyStupidQuestions
    显示剩余2条评论

    10

    按照顺序回答您的问题:

    连接由以下内容定义:

    { 协议,本地IP,本地端口,远程IP,远程端口 }

    (最好使用本地和远程,而不是源和目标,因为当您发送时,本地端口是来源,但当您接收时,它是目标。)

    sockid只是用户进程中的描述符,将映射到内核中的连接,就像文件描述符将映射到已打开的磁盘文件一样。

    两个不同的进程不能绑定到相同的本地端口。但是,两个进程可以使用相同的连接--套接字描述符可以从父进程继承到子进程,或者可以使用进程间通信在进程之间传递描述符。这两个进程将使用相同的端口,因为它们实际上共享同一个连接。

    虽然协议允许在连接到不同的远程服务器或端口时使用相同的本地端口,但大多数TCP堆栈不会允许这样做。绑定本地端口的API对于出站连接或入站连接的侦听使用相同的端口,直到绑定了端口后才指定意图。由于只有一个套接字能够侦听特定端口,API只是拒绝允许多个套接字绑定到一个端口(虽然有一个特殊的例外,但这与本讨论无关)。因此,所有出站连接都将使用不同的本地端口。所以当浏览器打开多个连接(无论是到相同的还是不同的Web服务器),它们将具有不同的本地端口。


    我有一个关于你的答案的问题。假设我在两个不同的选项卡中打开了两个连接到stackoverflow.com(为了这个问题的方便,让我们假设我连接到同一台服务器)。假设第一个套接字(Socket)位于本地端口1和远程端口80,第二个套接字位于本地:2和远程:80。从服务器的角度来看,它是否在local: 80和remote: 1上与socket 1通信,在local: 80和remote: 2上与socket 2通信?还是对于socket 1,它是local: 1和remote: 80,而对于socket 2,它是local: 2和remote: 80?如果是前者,那么服务器如何使用相同的本地端口维护2个开放的连接呢? - Hart Simha
    1
    这是第一种方式。服务器上的本地端口是客户端上的远程端口,反之亦然。它能够做到这一点是因为连接由两个端口和IP定义,只要远程端口和/或IP不同,就可以使用相同的本地端口建立多个连接而不会出现问题。 - Barmar

    -2
    我已经阅读了相关论坛上的问题,但我猜那里的人们也不太同意。
    在你提到的事项中,我没有看到任何不一致之处。
    我想知道什么确切地定义了套接字连接(sockid,源IP,源端口,目标IP,目标端口),还是只有(源IP,源端口,目标IP,目标端口)。
    后者。前者是想象出来的。在你引用的任何线程中都没有提到它。
    我想问的是,两个不同的进程(如两个不同的浏览器)是否可以在同一个源端口上与Web服务器通信。(默认情况下,目标端口相同)
    如果它们在同一个源IP上,就不行。这将违反上述身份定义。
    如果是同一浏览器中的不同选项卡,则可以,因为存在连接池。如果您正在谈论单独的连接,则答案仍然是否定的。
    正如其中一個答案所提到的,單個網頁嘗試連接許多不同的伺服器,例如廣告伺服器等。那麼Chrome或Firefox是否會與不同的伺服器使用相同的端口號進行連接,還是只使用一個端口呢?
    你必須解釋清楚這個問題。在“相同的端口”和“單個端口”之間有什麼區別?這不是一個真正的問題。

    如果它们位于相同的源IP,则不行。这将违反上述身份定义。肯定会使用不同的临时源/本地端口(它们的“退出”端口),从而使您具有唯一的身份:“{本地IP,本地端口,远程IP,远程端口}”-即示例并不现实。 - Joe
    @Joe 他问是否可以使用相同的源端口和目标端口。你的意见是什么? - user207421
    只是拥有某些东西来管理使用相同的源和目的地端口似乎很牵强。通常您会为自己分配出口端口,我想知道这是否是混淆的关键所在。定义出口端口并不是典型的做法,对吗? - Joe
    @Joe 当然不是,但这并不否定我在这里所说的任何内容。在我看来,你的评论应该放在他的问题下面,而不是我的回答下面。 - user207421

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接