WebSocket服务器如何处理多个传入的连接请求?

bn31dyow  于 2023-04-30  发布在  其他
关注(0)|答案(4)|浏览(368)

根据here
HTTP Upgrade头部请求服务器***将应用层协议从HTTP切换到WebSocket协议***。
客户端握手在IE10和服务器之间建立了HTTP-on-TCP连接。在服务器返回其101响应之后,应用层协议从HTTP切换到使用先前建立的TCP连接的WebSockets。

HTTP在这一点上完全不在画面中。使用轻量级的WebSocket有线协议,现在可以在任何时间发送或接收消息。

所以,我的理解是,在第一个客户端完成与服务器的握手后,服务器的80端口将被WebSocket协议*独占。并且HTTP不再在80端口上工作
那么,第二个客户端如何与服务器交换握手呢?毕竟WebSocket握手是HTTP格式的。

添加1

感谢所有的答案到目前为止。他们真的很有帮助。
现在我明白了同一台服务器的80端口被多个TCP连接**共享。这种共享是完全可以的,因为TCP连接是由一个5元素元组标识的,正如Jan-Philip Gehrcke所指出的。
我想补充几点想法。
WebSocketHTTP都只是应用级协议。* 通常 * 它们都依赖TCP协议作为它们的传输。

为什么选择端口80?

WebSocket设计有意选择服务器的端口80用于 * 握手和后续通信 。我认为设计者想让WebSocket通信从传输层的Angular 看起来像普通的HTTP通信。即服务器端口号仍为80)**。但根据jfriend00的回答,这种伎俩并不总是欺骗网络基础设施。

协议从 HTTP 转换到 WebSocket 是如何实现的?

RFC 6455 - WebSocket协议
基本上,考虑到Web的限制,它的目的是尽可能接近于仅向脚本公开原始TCP。它的设计方式也使得它的服务器可以与HTTP服务器共享一个端口,通过使它的握手成为一个有效的HTTP升级请求。从概念上讲,可以使用其他协议来建立客户端-服务器消息传递,但WebSockets的目的是提供一个相对简单的协议,可以与HTTP和已部署的HTTP基础设施共存(例如代理),并且在给定安全考虑的情况下,其与TCP一样接近,以便与这样的基础设施一起使用是安全的,具有针对性的添加以简化使用并使简单的事情简单(例如添加消息语义)。
所以我认为我错了下面的说法:
握手请求 * 模仿 * HTTP请求,但随后的通信不会。握手请求通过端口80到达服务器。因为是80端口,服务器会用HTTP协议处理。这就是为什么WebSocket握手请求必须采用HTTP格式。如果是这样的话,我认为HTTP协议必须被修改/扩展以识别那些WebSocket特定的东西。否则它不会意识到它应该*屈服于*WebSocket协议。
我认为应该这样理解:
WebSocket通信从客户端到服务器的
有效
HTTP请求开始。因此,遵循HTTP协议的服务器来解析握手请求并识别请求协议更改的请求。并且是服务器切换协议。所以HTTP协议不需要改变。HTTP协议甚至不需要知道WebSocket。

WebSocket和Comet

因此WebSocket与Comet技术的不同之处在于WebSoket并不局限于当前的HTTP领域来解决双向通信问题。

添加2

一个相关的问题:How does a browser establish connection with a web server on 80 port? Details?

70gysomp

70gysomp1#

你的问题很棒!
我想试着从涉及系统调用listen()accept()的Angular 来回答它。理解这两个电话的行为,我认为是相当有见地的,足以回答你的问题。

剧透:我们可以通过查看TCP/IP如何工作来回答您的问题:-)

对于问题的核心部分,我们甚至不需要区分“普通”HTTP和WebSockets。共同点是 TCP over IP
发送HTTP请求需要在双方之间建立TCP/IP连接(我已经尝试详细说明了here)。
在简单的Web浏览器/ Web服务器场景中
1.首先,在两者之间建立TCP连接(由客户端发起)
1.然后通过该TCP连接发送HTTP请求(从客户端到服务器)
1.然后通过 * 相同的 * TCP连接发送HTTP响应(在另一个方向,从服务器到客户端)
在此交换之后,不再需要底层TCP连接,并且通常会被破坏/断开连接。在所谓的“HTTP升级请求”的情况下(其可以被认为是:“喂,服务员!请将其升级为WebSocket连接!“),底层TCP连接继续存在,WebSocket通信通过最初创建的同一个TCP连接(上面的步骤(1))。
这很有希望地澄清了WebSocket和HTTP之间的关键区别是高级协议的切换(从HTTP到WebSocket),而不改变底层传输通道(TCP/IP连接)。

如何处理同一socket的多次IP连接尝试?

这是一个我曾经与自己斗争的主题,许多人不理解,因为它有点非直觉。然而,当理解操作系统提供的与套接字相关的基本系统调用是如何工作的时,这个概念实际上是非常简单的。
首先,需要理解的是,IP连接是由五个条信息 * 唯一定义的:

IP:机器A端口IP:机器B端口协议(TCP或UDP)

现在,socket 对象通常被认为代表一个连接。但这并不完全正确。它们可能代表不同的事物:它们可以是主动的或被动的。一个socket对象在passive/listen模式下会做一些非常特别的事情,这对回答你的问题很重要。
http://linux.die.net/man/2/listen说:
listen()将sockfd引用的套接字标记为被动套接字,也就是说,标记为将用于使用accept(2)接受传入连接请求的套接字。
也就是说,我们可以创建一个被动套接字来监听传入的连接请求。根据定义,这样的套接字永远不能表示连接。它只监听连接请求。
让我们来看一下accept()http://linux.die.net/man/2/accept):
accept()系统调用用于基于连接的套接字类型(SOCK_STREAM、SOCK_SEQPACKET)。它提取侦听套接字sockfd的挂起连接队列上的第一个连接请求,创建一个新的已连接套接字,并返回一个引用该套接字的新文件描述符。新创建的套接字未处于侦听状态。原始套接字sockfd不受此调用的影响。
让我们仔细消化一下,我想现在这真的回答了你的问题。
accept()不改变之前创建的passivesocket的状态。它返回一个active(已连接)套接字(这样的套接字表示上面的五个信息状态--很简单,对吧?).
通常,这个新创建的活动套接字对象随后被移交给另一个进程或线程,或者只是负责连接的“实体”。在accept()返回这个连接的套接字对象之后,accept()可以在被动套接字上被 * 再次 * 调用,并且一次又一次-这就是所谓的
接受循环

但是调用accept()需要时间,对吗?它不能错过传入的连接请求吗?在刚刚引用的帮助文本中有更多重要信息:有一个挂起的连接请求队列!它由操作系统的TCP/IP堆栈自动处理。
这意味着虽然accept()只能处理传入的连接请求一个接一个,但即使它们以高速率或(准)同时传入,也不会错过传入的请求。可以说,accept()的行为限制了您的机器能够处理的传入连接请求的频率。然而,这是一个快速的系统调用,在实践中,首先会遇到其他限制-通常是那些与处理所有已接受的连接有关的限制。

mrwjdhj3

mrwjdhj32#

这里你似乎忽略了一件相对简单的事情,那就是每个到服务器的连接(特别是到这里的HTTP服务器)创建它自己的套接字,然后在该套接字上运行。一个套接字上发生的事情***完全独立于***当前连接的任何其他套接字上发生的事情。因此,当一个套接字切换到WebSocket协议时,不会改变其他当前或传入套接字连接的情况。这些人可以自己决定如何处理。
因此,打开的套接字可以使用WebSocket协议,而其他传入的连接可以是常规的HTTP请求或创建新的webSocket连接的请求。
所以,你可以有这样的序列:
1.客户端A通过HTTP请求在端口80上连接到服务器以发起WebSocket连接。此过程在两者之间创建套接字。
1.服务器对升级到WebSocket请求响应yes,客户端和服务器都将协议***仅用于此套接字***切换到webSocket协议。
1.客户端A和服务器开始使用WebSocket协议交换数据包,并在接下来的几个小时内继续这样做。
1.客户端B使用常规HTTP请求连接到端口80上的同一服务器。此过程在两者之间创建一个新套接字。
1.服务器发现传入的请求是正常的HTTP请求,并发送响应。
1.当客户端B接收到响应时,套接字被关闭。
1.客户端C通过HTTP请求连接到端口80上的同一服务器,以升级到WebSocket。
1.服务器对升级到WebSocket请求响应yes,客户端和服务器都将协议***仅用于此套接字***切换到webSocket协议。
1.此时,有两个使用WebSocket协议的开放套接字可以进行通信,并且服务器仍然接受新的连接,这些连接可以是常规HTTP请求,也可以是对webSocket协议的升级请求。
因此,在任何时候,服务器仍然在端口80上接受新的连接,这些新的连接可以是常规HTTP请求,也可以是升级到WebSocket协议的HTTP请求(从而启动webSocket连接)。而且,当所有这些都在进行时,已经建立的WebSocket连接正在使用webSocket协议通过自己的套接字进行通信。
WebSocket连接和通信方案经过精心设计,具有以下特性:
1.不需要新端口。传入端口(最常见的端口80)可用于常规HTTP请求和WebSocket通信。
1.因为不需要新的端口,所以“通常”不需要更改防火墙或其他网络基础设施。事实证明,情况并非总是如此,因为一些期望HTTP流量的代理或缓存可能必须进行修改以处理(或避免)WebSocket协议流量。
1.同一个服务器进程可以轻松地处理HTTP请求和WebSocket请求。

  1. HTTP cookie和/或其他基于HTTP的认证手段可以在设置WebSocket连接期间使用。
    对您进一步问题的答复:
    1)为什么选择80作为默认端口?设计者是否希望从传输层的Angular 看WebSocket通信看起来像普通的HTTP通信?(即服务器端口是好的旧80)。
    是的,请看我上面的1-4点。WebSockets可以通过现有的HTTP通道建立,因此它们通常不需要更改网络基础设施。我想补充一点,不需要新的服务器或服务器进程,因为现有的HTTP服务器可以简单地添加WebSocket支持。
    2)我试图描绘协议转换是如何在服务器上发生的。我想有不同的软件模块来处理HTTP或WebSocket流量。第一个服务器使用HTTP模块来处理正常的HTTP请求。当它发现一个升级请求时,它将切换到使用WebSocket模块。
    不同的服务器架构将以不同的方式处理WebSocket数据包和HTTP请求之间的划分。在某些情况下,WebSocket连接甚至可能被转发到新进程。在其他情况下,它可能只是同一进程中的不同事件处理程序,该进程在套接字上注册了传入的数据包流量,该套接字现在已切换到WebSocket协议。这完全取决于Web服务器架构以及它选择如何处理WebSocket流量。实现WebSocket应用程序服务器端的开发人员很可能会选择与其特定Web服务器架构兼容的现有webSocket实现,然后编写在该框架内工作的代码。

在我的例子中,我选择了 www.example.com 。js(这是我的服务器架构)。这个库给了我一个对象,它支持新连接的webSockets的事件,然后是一组其他事件,用于阅读传入消息或发送传出消息。初始WebSocket连接的细节都由库处理,我不必担心这些。如果我想在建立连接之前要求进行身份验证,请使用www.example www.example.com 。然后,我可以从任何客户端接收消息,向任何单个客户端发送消息或向所有客户端广播信息。我主要是用它来广播,以保持一些信息在网页“活”,使网页显示总是最新的。每当服务器上的值发生变化时,我都会将新值广播到所有连接的客户端。

g6baxovj

g6baxovj3#

回答你的问题:处理到端口80的同时WebSocket和HTTP连接。..

与处理80端口的同时HTTP连接完全相同!

这意味着:在满意的TCP握手后,serviceip:80上侦听的服务继续产生一个新的进程或线程,并将该连接的所有通信移交给它(或者只是通过执行与该事件相关的回调来服务请求,就像异步nodejs所做的那样,正如jfriend 00正确指出的那样)。
然后等待或处理队列中的下一个传入请求。
如果你想知道HTTP 1.1和UPGRADE请求播放所有这些,这个MSDN article在上面留下了非常清晰的信息:
WebSocket协议有两个部分:握手以建立升级的连接,然后是实际的数据传输。首先,客户端通过使用“Upgrade:WebSocket”和“连接:升级”头,沿着一些特定于协议的头,以建立正在使用的版本并设置握手。如果服务器支持协议,则会回复相同的“升级:WebSocket”和“连接:升级”标头并完成握手。一旦握手成功完成,数据传输开始。
只有WebSocket服务通常没有内置到Web服务器中,因此实际上并不打算在端口80中侦听,只是由于Web服务器的透明转发而可以通过它访问。Apache Web服务器使用mod_proxy_wstunnel来实现这一点。
当然,你也可以有一个内置web sockets实现的web服务器:例如Apache Tomcat
这里的主要内容是:WebSocket协议不是HTTP。它有不同的目的。它是一个独立的应用层通信协议,也是建立在TCP之上的(尽管TCP不是必需的,但它是一个符合Websockets应用层协议要求的传输层协议)。
WebSocket服务是与Web服务器服务沿着运行的PARALLEL服务。
它使用WebSocket协议,现代Web浏览器支持该协议,实现界面的客户端部分。
您设置或构建WebSocket服务,以便在Websocket客户端(通常是Web浏览器)和该服务之间建立持久的非HTTP连接。
主要优点是:WebSocket服务可以在需要的时候向客户端发送一条消息(“你们的一个朋友已经连接上了!”“你们队刚进了一球!“),而不必等待客户端的 explicit REQUEST 更新。
您可以使用HTTP 1建立持久连接。1,但是HTTP除了提供一组资源 UPON REQUEST 然后关闭连接之外没有任何意义。
直到最近,在所有主流浏览器都支持Websockets之前,您只有两种选择来实现Web应用程序的真实的更新:

  • 实现 AJAX 长轮询请求,这是一个痛苦而低效的过程。
  • 使用/构建浏览器插件(例如Java applet支持插件),以便能够与您的更新服务建立非HTTP连接,这比长轮询更有效,但更痛苦。

在服务的共享监听端口(可以是任何TCP端口,甚至不需要对互联网开放,因为大多数Web服务器支持透明转发Web Socket连接)方面,它的工作原理与其他TCP服务完全相同:服务仅在其上监听,并且当TCP握手通过时,存在TCP套接字以供服务与客户端通信。
通常,当被分配唯一的client_ip:client_TCP_port对时,到侦听特定TCP套接字(server_ip:service_TCP_port)的服务的所有连接将被区分,client_TCP_port由客户端在其可用TCP端口中随机选择。
如果您仍然对Websocket连接握手时发生的HTTP-〉WebSocket应用程序协议切换以及它与底层TCP连接没有任何关系感到怀疑,我建议您参考Jan-Philip Gehrcke's answer,这是非常明确的指导性内容,可能是您实际正在寻找的内容。

lf5gs5x2

lf5gs5x24#

这是一个相当简单的概念,所以让我试着用简单的术语来描述它,以防其他迷失的灵魂想要理解它,而不必阅读所有这些冗长的解释。

多个连接

  • Web服务器开始侦听连接。发生以下情况:
  • Web服务器的主进程在端口80上打开一个处于listen状态的被动套接字,e。例如9.9.9.9:809.9.9.9是服务器IP,80是端口)。
  • 浏览器向服务器上的端口80发出请求。发生以下情况:
  • 操作系统(简称OS)在客户端上分配一个随机出站端口,例如:1.1.1.1:67471.1.1.1是客户端IP,6747是随机端口)。
  • 操作系统发送一个数据包,其源地址为1.1.1.1:6747,目的地址为9.9.9.9:80。它经过各种路由器和交换机,到达目的服务器。
  • 服务器接收分组。发生以下情况:
  • 服务器OS发现数据包的目的地址是它自己的IP地址之一,并根据目的端口将其传递给与端口80相关联的应用程序。
  • Web服务器的主进程接受连接,创建新的活动套接字。然后,它通常会派生一个新的子进程,该子进程接管活动套接字。被动套接字保持打开状态以接受新的传入连接。

现在,从服务器发送到客户端的每个数据包都将具有这些地址:

  • 来源:9.9.9.9:1553;目的地:1.1.1.1:80

从客户端发送到服务器的每个数据包都将具有这些地址:

  • 来源:1.1.1.1:80;目的地:9.9.9.9:1553
    HTTP -〉WebSocket握手

HTTP是一种基于文本的协议。有关可用命令的列表,请参阅HTTP wiki。浏览器发送其中一个命令,Web服务器相应地响应。
WebSocket不是基于HTTP的。它是一种二进制协议,可以同时在两个方向上发送多个消息流(全双工模式)。因此,如果不引入新的HTTP标准(例如HTTP/2),就不可能直接建立WebSocket连接。但只有在以下情况下才有可能做到:

  1. WebSocket支持的HTTP动词/请求
    1.有一个不同于80的新的专用端口用于WebSocket特定的通信。
    第一个不在协议范围内,第二个将破坏现有的Web基础设施。由于客户端/浏览器可以与同一服务器建立多个HTTP连接,因此将其中一些从HTTP切换到WebSocket是两全其美的-保持相同的端口80,但允许与HTTP不同的协议。切换通过客户端发起的协议握手进行。

相关问题