为什么WebSocket在“握手”之后可以与HTTP共享80端口?

9
据我所知:
端口指的是服务器上的一个程序。
当我们说“共享一个端口”时,实际上是指“由同一个在该端口上监听的程序处理请求”。
WebSocket握手过程类似于HTTP格式,因此能够被处理HTTP协议的服务器程序理解。因此,将握手请求发送到端口80是可以的。
但是,握手之后,WebSocket数据格式与HTTP格式完全不同,它怎么还能被发送到端口80呢?例如通过以下URL:
ws://somehost:80/chat
这是如何实现的?
我的猜测是:
HTTP程序看到端口80上的传入请求“不能被处理为HTTP”,然后将其传递给WebSocket程序进行处理。如果有其他想要共享端口80的协议,比如WebSocket2,HTTP程序怎么知道要传递哪个协议,如果没有一种方式来识别正在使用的协议。

根据 jfriend00 的回复,我画了以下的图示:

因此,在同一浏览器中的 WebSocket 和 HTTP 流量实际上是通过 不同 的 socket 连接进行的。尽管它们都是从连接到服务器的 80 端口开始。

我认为,如果单词 WebSocket 中没有包含 socket,那么将其理解为 TCP 协议上的另一种应用级协议会更容易。

enter image description here

添加 2

根据 jfriend00 的进一步评论,我将上述图表改进为以下形式。我想展示的是在浏览器中 WebSocket 通信和 HTTP 通信与同一服务器 共存 的方式。

enter image description here

添加3

阅读完本主题后,我想起当服务器接受连接时,服务器端口不会改变:当TCP连接被服务器接受时,端口是否会改变?

因此,图表应该是这样的:

HTTP的TCP连接和WebSocket的TCP连接应该使用不同的客户端端口

enter image description here

2个回答

15
当服务器监听特定端口时,它正在监听传入的连接。当新的传入连接到达时,它会获得自己的套接字来运行。该套接字提供了两个端点之间的连接。从那时起,该套接字完全独立于可能也连接的所有其他套接字运行。

因此,一个传入的HTTP请求可以指定“升级”标头并升级为WebSocket,然后双方同意从此以后使用WebSocket协议进行通信。同时,没有该升级标头的其他传入HTTP请求仅视为普通的HTTP请求。

如果您不太理解WebSocket协议的工作原理,您可以在此处查看如何连接。

以下是主要步骤:

  1. 客户端请求webSocket连接,向端口80上的服务器发送HTTP请求。
  2. 该HTTP请求是合法的HTTP请求,但它包含一个标题 Upgrade:websocket
  3. 如果服务器支持WebSocket协议,则会响应一个带有101状态代码的合法HTTP响应,其中包括一个标题 Connection:Upgrade
  4. 此时,双方切换到WebSocket协议,并且该套接字上的所有未来通信都是使用WebSocket帧的数据格式进行的。

不含upgrade请求标头的任何其他传入HTTP请求都将被视为普通的HTTP请求。

HTTP程序会看到无法处理端口80上的传入请求作为HTTP,然后将其传递给WebSocket程序以处理吗?

不,第一个请求是合法的HTTP请求(只是其中包含特殊的标头),并且发送回来的响应是合法的HTTP响应。但是,在该响应之后,双方切换到WebSocket协议。因此,使用自定义标头告诉Web服务器,这个传入的HTTP请求旨在成为建立WebSocket连接的第一步。

如果有其他协议想要共享80端口,例如WebSocket2,HTTP程序如何知道应该传递哪个协议,如果没有一种方法来识别正在使用的协议。

可以通过指定不同的协议名称Upgrade: someOtherProtocol来使用此upgrade机制来支持其他协议,但我不知道是否有其他已经标准化的协议。


1
@smwikipedia - 我不太明白你在图表中试图展示什么。WebSocket连接是它自己的套接字。它最初是作为一种使用HTTP协议的TCP套接字开始运行。在解析传入的升级标头并返回101状态之后,它将成为使用WebSocket协议的相同TCP套接字。随后到来的HTTP连接将是它们自己的TCP套接字,并且可以自行决定要使用哪种协议。 - jfriend00
1
@smwikipedia - 端口80有点像大公司的中央电话号码。许多来电可以到达该号码,但是每个连接后,它们都成为独立的通话,每个通话的两端的人可以协商使用任何语言。此外,每个来电都与其他通话完全独立 - 除了它们最初必须使用一种共同的语言与接待员交流之外,它们彼此没有任何关联。之后,它们可以被转接到其他地方,并同意使用任何语言。 - jfriend00
2
@smwikipedia - 图表中似乎有一个错误,即一旦整个过程从原始HTTP连接开始,底层TCP套接字连接已经存在。没有为webSocket创建“新”的套接字。给定连接的套接字已经存在,您只需让双方同意使用webSocket协议而不是HTTP协议即可。这就像您打电话给您妈妈的家,用英语接电话,然后双方同意用西班牙语交谈一样。这是相同的电话连接,不同的语言。 - jfriend00
我想展示的是在浏览器中WebSocket通信如何与HTTP通信共存。当我建立一个WebSocket连接时,我通常使用与访问网页相同的端口的URL,例如ws://myserver:80(我的图表中的步骤(1))。然后服务器为实际通信创建另一个专用套接字(步骤(2))。根据是否存在upgrade头,此新套接字将会使用WebSocket或不使用。随后的通信将相应地进行(步骤(3))。 - smwikipedia
1
@smwikipedia - 所有的webSocket连接都是通过向服务器建立TCP套接字连接并在该TCP套接字上发送HTTP格式消息开始的。然后,在服务器处理升级标头后,双方同意采用该确切的套接字并将协议切换到webSocket协议。对于webSocket,不会创建新的套接字。使用的是已经存在的(它们刚刚在HTTP上交谈的)相同套接字。没有“新”的套接字来讲述webSocket。套接字是一个TCP级别的东西,在任何协议之前就已经存在了。 - jfriend00
显示剩余3条评论

0
因为浏览器使用一个新的端口连接并发送/接收消息到/从服务器。

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