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

时间:2015-02-14 15:10:00

标签: http websocket spring-websocket

根据here

  

HTTP Upgrade标头请求服务器 切换   从HTTP到WebSocket协议的应用层协议

     

客户端握手在IE10之间建立了HTTP-on-TCP连接   和服务器。服务器返回101响应后,   应用层协议从HTTP切换到使用的WebSockets   先前建立的TCP连接。

     此时

HTTP完全不在图片中 。使用   轻量级WebSocket线协议,现在可以发送消息或   任何一个终端都可以随时收到。

所以,我的理解是,在第一个客户端与服务器完成握手后,服务器的80端口将被WebSocket协议 垄断 。并且 HTTP不再使用80端口

那么第二个客户端如何与服务器交换握手。 所有WebSocket握手都是HTTP格式。

ADD 1

感谢目前为止的所有答案。他们真的很有帮助。

现在,我了解多个TCP连接相同的服务器80端口 共享 。这种共享是完全正常的,因为TCP连接由5个元素的元组标识为Jan-Philip Gehrcke指出。

我想补充一些想法。

WebSocketHTTP都只是应用程序级协议。 通常他们都依赖TCP协议作为传输。

为什么选择端口80?

WebSocket设计有意选择服务器端口80进行握手和后续通信。我认为设计人员希望从传输级别的角度(即服务器端口号仍为80)使WebSocket通信看起来像正常的HTTP通信 即可。但根据jfriend00的答案,这个技巧并不总是欺骗网络基础设施。

协议如何从 HTTP 转移到 WebSocket

来自RFC 6455 - WebSocket协议

  

基本上它旨在尽可能地暴露原始TCP   考虑到Web的约束,尽可能使用脚本。这也是   以这样的方式设计,使其服务器可以与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领域以解决双向通信问题。

ADD 2

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

4 个答案:

答案 0 :(得分:65)

其他答案已经有所帮助。我想指出您的问题非常好,并希望从涉及listen()accept()的观点回答这个问题。这两个系统调用的行为应足以回答您的问题。

您对TCP / IP的工作原理感兴趣!

对于问题的核心部分,根据HTTP或WebSocket确实没有区别:共同点是TCP over IP,这足以回答你的问题。仍然,你应该得到WebSocket如何与TCP相关的答案(我试图详细说明here):发送HTTP请求需要在双方之间建立TCP / IP连接。如果是简单的Web浏览器/ Web服务器场景

  1. 首先,在两者之间建立TCP连接(由客户端发起)
  2. 然后通过 TCP连接(从客户端到服务器)发送HTTP请求
  3. 然后通过相同的 TCP连接(在另一个方向,从服务器到客户端)发送HTTP响应
  4. 在此交换之后,不再需要底层TCP连接,并且通常会被破坏/断开连接。在HTTP升级请求的情况下,底层TCP连接只能继续生效,WebSocket通信将通过最初创建的TCP连接(上面的步骤(1))。

    正如您所看到的,WebSocket和标准HTTP之间的唯一区别是高级协议(从HTTP到WebSocket)中的切换,而不更改底层传输通道(TCP / IP连接)。 /强>

    通过同一个套接字处理多个IP连接尝试,怎么做?

    这是我曾经与自己斗争过的话题,很多人都不理解。但是,当人们理解操作系统提供的基本套接字相关系统调用是如何工作时,这个概念实际上非常简单。

    首先,需要了解IP连接是由五个信息唯一定义的

    IP:机器A的PORT IP:机器B的PORT 协议(TCP或UDP)

    现在, socket 对象通常被认为代表了一种连接。但这并非完全正确。它们可能代表不同的东西:它们可以是主动的或被动的。 被动/倾听模式下的套接字对象会做一些非常特殊的事情,这对回答您的问题非常重要。 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()不会更改之前创建的被动套接字的状态。它返回一个活动(已连接)套接字(这样的套接字代表上面五条信息状态 - 简单,对吧?)。通常,这个新创建的活动套接字对象然后被切换到另一个进程或线程或只是负责连接的“实体”。在accept()返回此连接的套接字对象后,accept()可以在被动套接字上再次调用 ,并且一次又一次地被称为接受循环即可。但是调用accept()需要时间,对吗?它不能错过传入的连接请求吗?刚引用的帮助文本中有更多基本信息:有一个挂起的连接请求队列!它由操作系统的TCP / IP堆栈自动处理。这意味着虽然accept()只能处理传入的连接请求逐个,但即使它们以高速率传入或(准)同时也不会丢失传入请求。可以说accept()的行为限制了机器可以处理的传入连接请求的频率。但是,这是一个快速的系统调用,在实践中,其他限制首先出现 - 通常是那些与处理目前已接受的所有连接相关的限制

答案 1 :(得分:18)

这里你似乎缺少的相对简单的事情是每个与服务器的连接(特别是你的HTTP服务器) 创建它自己的套接字 然后在该套接字上运行。在一个套接字上发生的事情是 完全独立 当前连接的任何其他套接字上发生的事情。因此,当一个套接字切换到webSocket协议时,这不会改变其他当前或传入套接字连接发生的情况。那些人可以自己决定如何处理它们。

因此,开放套接字可以使用webSocket协议,而其他传入连接可以是常规HTTP请求或创建新webSocket连接的请求。

所以,你可以有这种类型的序列:

  1. 客户端A使用HTTP请求连接到端口80上的服务器以启动webSocket连接。此过程在两者之间创建一个套接字。
  2. 服务器响应是,升级到webSocket请求,客户端和服务器都将协议 仅针对此套接字 切换到webSocket协议。
  3. 客户端A和服务器开始使用webSocket协议交换数据包,并在接下来的几个小时内继续这样做。
  4. 客户端B使用常规HTTP请求连接到端口80上的同一服务器。此过程在两者之间创建一个新套接字。
  5. 服务器看到传入的请求是正常的HTTP请求并发送响应。
  6. 当客户端B收到响应时,套接字将关闭。
  7. 客户端C使用HTTP请求连接到端口80上的同一服务器以升级到webSocket。
  8. 服务器响应是,升级到webSocket请求,客户端和服务器都将协议 仅针对此套接字 切换到webSocket协议。
  9. 此时,有两个使用webSocket协议的开放套接字可以进行通信,服务器仍然接受可以是常规HTTP请求的新连接,也可以是更新webSocket协议的请求。
  10. 因此,在任何时候,服务器仍然接受端口80上的新连接,并且这些新连接可以是常规HTTP请求,也可以是请求升级到webSocket协议的HTTP请求(从而启动webSocket连接)。而且,虽然所有这些都在进行,但已经建立的webSocket连接正在使用webSocket协议通过它们自己的套接字进行通信。

    webSocket连接和通信方案经过精心设计,具有以下特点:

    1. 无需新端口。传入端口(最常见的端口80)可用于常规HTTP请求和webSocket通信。
    2. 由于不需要新端口,防火墙或其他网络基础设施的变化通常是#34;不需要。事实证明,情况并非总是如此,因为可能必须修改一些期望HTTP流量的代理或缓存来处理(或避免)webSocket协议流量。
    3. 同一服务器进程可以轻松处理HTTP请求和webSocket请求。
    4. 在设置webSocket连接时可以使用HTTP cookie和/或其他基于HTTP的身份验证方法。

    5. 您的进一步问题的答案:

        

      1)为什么选择80作为默认端口?设计师是否想要制作   WebSocket通信看起来像普通的HTTP通信   运输水平的观点? (即服务器端口是旧的   80)。

      是的,请看上面的1-4点。 webSockets可以通过现有的HTTP通道建立,因此它们通常不需要更改网络基础结构。我补充说,由于现有的HTTP服务器只能添加webSocket支持,因此不需要新的服务器或服务器进程。

        

      2)我试图描述服务器上协议转换的情况。一世   图像那里有不同的软件模块来处理HTTP或   WebSocket流量。第一台服务器使用HTTP模块来处理   正常的HTTP请求。当它找到升级请求时,它将切换   使用WebSocket模块。

      不同的服务器体系结构将以不同方式处理webSocket数据包和HTTP请求之间的划分。在某些情况下,webSocket连接甚至可能被转发到新进程。在其他情况下,它可能只是同一进程中的不同事件处理程序,它在套接字上注册了传入的数据包流量,现在已经切换到webSocket协议。这完全取决于Web服务器体系结构以及它如何选择处理webSocket流量。实现webSocket应用程序服务器端的开发人员很可能会选择与其特定Web服务器体系结构兼容的现有webSocket实现,然后编写在该框架内工作的代码。

      就我而言,我选择了与node.js一起使用的socket.io库(这是我的服务器架构)。该库为我提供了一个对象,该对象支持新连接webSockets的事件,然后是一组用于读取传入消息或发送传出消息的其他事件。初始webSocket连接的详细信息都由图书馆处理,我不必担心任何问题。如果我想在建立连接之前要求身份验证,socket.io库可以让我插入它。然后我可以从任何客户端接收消息,向任何单个客户端发送消息或向所有客户端发送广播信息。我主要使用它进行广播,以便在网页中保留一些信息" live"这样网页显示总是最新的。只要服务器上的值发生变化,我就会将新值广播给所有连接的客户端。

答案 2 :(得分:5)

回答你的问题:处理到端口80的同步Websocket和HTTP连接......

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

这意味着:在满意的TCP握手时,监听serviceip:80的服务继续产生一个新的进程或线程并将该连接的所有通信切换到它(或者通过执行与该事件相关的回调来提供请求正如异步nodejs那样,正如jfriend00正确指出的那样)。

然后等待或处理队列中的下一个传入请求。

如果你想知道HTTP 1.1和UPGRADE请求在所有这些方面发挥了什么作用,那么这个MSDN article就会非常清楚:

  

WebSocket协议有两个部分:建立握手   升级连接,然后实际数据传输。首先是客户   通过使用"升级:websocket"来请求websocket连接。和   "连接:升级"标题,以及一些特定于协议的标题   标头以建立正在使用的版本并设置握手。   服务器,如果它支持协议,则回复相同的   "升级:websocket"和"连接:升级"标题并完成   握手。一旦握手成功完成,数据   转移开始。

只有Websocket服务通常没有内置到Web服务器中,所以不是真正打算在端口80中监听,只是通过它可以访问,这要归功于Web服务器的透明转发。 Apache Web服务器使用mod_proxy_wstunnel执行此操作。

当然,您也可以拥有一个内置Web套接字实现的Web服务器:例如Apache Tomcat

这里的主要内容是:Websocket协议不是HTTP。它有不同的用途。它是一个独立的应用层通信协议,也建立在TCP之上(虽然TCP不是必需的,但是符合Websockets应用层协议要求的传输层协议)。

Websocket服务是与Web服务器服务一起运行的PARALLEL服务。

它使用Websocket协议,现代Web浏览器支持该协议,实现接口的客户端部分。

您可以设置或构建Websocket服务,以便在Websocket客户端(通常是Web浏览器)和该服务之间建立持久的非HTTP连接。

主要优点是:Websocket服务可以随时向客户发送消息("你们其中一个好友已经连接了!""你的团队刚刚进球!"),而不必等待客户的显式请求进行更新。

您可以使用HTTP 1.1建立持久连接,但HTTP不是用于提供一组资源 UPON REQUEST 以外的其他任何连接,然后关闭连接。

直到最近,在Websockets'之前在所有主流浏览器中都提供了支持,您只有两种方法可以在Web应用程序上实现实时更新:

  • 实施AJAX长轮询请求,这是一个痛苦而低效的过程。

  • 使用/构建浏览器插件(例如Java applet支持插件),以便能够与您更新服务建立非HTTP连接,这比长轮询更有效但更痛苦。

就服务的共享侦听端口而言(可以是任何TCP端口,它甚至不必对互联网开放,因为大多数Web服务器都支持透明转发Web套接字连接),它与任何其他TCP服务完全一样:服务只是监听它,当TCP握手结束时,存在服务器与客户端通信的TCP套接字。

与往常一样,当分配了唯一的client_ip:client_TCP_port对时,将区分对侦听特定TCP套接字(server_ip:service_TCP_port)的服务的所有连接,客户端在其可用的TCP端口中随机选择client_TCP_port。 / p>

如果您仍然对Websocket连接握手时发生的HTTP-> Websocket应用程序协议切换有疑问,以及它与底层TCP连接有什么关系,我建议您{{3} },这是一个非常明确的指导,可能是你真正想要的。

答案 3 :(得分:1)

这是一个非常简单的概念,所以让我试着用简单的术语来描述它,以防其他失落的灵魂想要掌握它而不必阅读所有这些长篇解释。

多个连接

  1. Web服务器开始侦听连接。发生这种情况:

    • Web服务器的主要进程在端口listen上的状态80中打开被动套接字,例如9.9.9.9:809.9.9.9是服务器IP,80是端口。)
  2. 浏览器向服务器端口80发出请求。发生这种情况:

    • 操作系统(简称OS)在客户端上分配一个随机出站端口,例如:1.1.1.1:67471.1.1.1是客户端IP,6747是随机端口)。

    • 操作系统发送的数据包的源地址为1.1.1.1:6747,目的地址为9.9.9.9:80。它通过各种路由器和交换机到达目标服务器。

  3. 服务器接收数据包。发生这种情况:

    • 服务器操作系统发现数据包的目标地址是其自己的IP地址之一,并且基于目标端口将其传递给与端口80关联的应用程序。

    • Web服务器的主进程接受创建新活动套接字的连接。然后它通常会分叉一个新的子进程,它接管活动套接字。被动套接字保持打开状态以接受新的传入连接。

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

    • 来源: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标准,就不可能直接建立WebSocket连接,例如HTTP/2。但这只有在以下情况下才有可能:

    1. 支持WebSocket HTTP verbs/requests

    2. 对于特定于WebSocket的通信,有一个不同于80的新专用端口。

    3. 第一个没有协议的范围,第二个会破坏现有的Web基础设施。因为客户端/浏览器可以与同一服务器建立多个HTTP连接,所以将它们中的一些从HTTP切换到WebSocket是两全其美的 - 保持相同的端口80但允许与HTTP不同的协议。切换通过客户端发起的protocol handshake进行。