首页 文章

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

提问于
浏览
46

根据here

HTTP Upgrade标头请求服务器将应用层协议从HTTP切换到WebSocket协议 . 客户端握手在IE10和服务器之间 Build 了HTTP-on-TCP连接 . 在服务器返回其101响应之后,应用层协议从HTTP切换到使用先前 Build 的TCP连接的WebSockets . 此时HTTP完全脱离了图片 . 使用轻量级WebSocket线协议,任何 endpoints 现在都可以随时发送或接收消息 .

所以,我的理解是,在第一个客户端完成与服务器的握手后,服务器的80端口将由WebSocket协议 monopolized . 和 HTTP is no longer working on 80 port .

那么第二个客户端如何与服务器交换握手 . After all the WebSocket handshake is in HTTP format.

ADD 1

谢谢你到目前为止的所有答案 . 他们真的很有帮助 .

现在我明白,多个 TCP 连接的同一服务器的80端口是 shared . 这种共享完全没问题,因为 TCP 连接由一个5元素元组标识为 Jan-Philip Gehrcke 指出 .

我想补充几点想法 .

WebSocketHTTP 都只是应用程序级协议 . 通常他们都依赖于 TCP 协议作为他们的运输 .

为什么选择端口80?

WebSocket设计有意为握手和后续通信选择服务器的端口80 . 我认为设计师希望使WebSocket通信看起来像普通的HTTP通信 from the transport level's perspective (i.e. the server port number is still 80) . 但根据 jfriend00 's answer, this trick doesn'总是欺骗网络基础设施 .

协议如何从HTTP转移到WebSocket?

来自RFC 6455 - WebSocket协议

基本上,考虑到Web的限制,它应该尽可能地将原始TCP暴露给脚本 . 它的设计也使其服务器可以与HTTP服务器共享一个端口,使其握手成为有效的HTTP升级请求 . 可以在概念上使用其他协议来 Build 客户端 - 服务器消息传递,但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 回答

  • 17

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

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

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

    • 首先,在两者之间 Build TCP连接(由客户发起)

    • 然后通过该TCP连接(从客户端到服务器)发送HTTP请求

    • 然后通过相同的TCP连接发送HTTP响应(在另一个方向,从服务器到客户端)

    在此交换之后,不再需要底层TCP连接,并且通常会被破坏/断开连接 . 在HTTP升级请求的情况下,底层TCP连接继续生效,并且WebSocket通信通过最初创建的完全相同的TCP连接(上面的步骤(1)) .

    As you can see, the only difference between WebSocket and standard HTTP is a switch in a high-level protocol (from HTTP to WebSocket), without changing the underlying transport channel (a TCP/IP connection).

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

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

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

    IP:PORT of Machine AIP:PORT of Machine Bthe protocol (TCP or UDP)

    现在,通常认为套接字对象代表连接 . 但这并非完全正确 . 它们可能代表不同的东西:它们可以是主动的或被动的 . passive/listen 模式中的套接字对象做了一些非常特殊的事情,这对回答你的问题非常重要 . http://linux.die.net/man/2/listen说:

    listen()将sockfd引用的套接字标记为被动套接字,即作为套接字使用accept(2)接受传入的连接请求 .

    因此,我们可以创建一个监听传入连接请求的 passive 套接字 . 根据定义,这样的套接字永远不能代表连接 . 它只是监听连接请求 .

    让我们前往 accept()http://linux.die.net/man/2/accept):

    accept()系统调用与基于连接的套接字类型(SOCK_STREAM,SOCK_SEQPACKET)一起使用 . 它在侦听套接字sockfd的挂起连接队列上提取第一个连接请求,创建一个新的连接套接字,并返回一个引用该套接字的新文件描述符 . 新创建的套接字未处于侦听状态 . 原始套接字sockfd不受此调用的影响 .

    这就是我们需要知道的所有内容,以便回答您的问题 . accept() 不会更改之前创建的 passive 套接字的状态 . 它返回一个 active (connected) 套接字(这样的套接字代表上面五条信息状态 - 简单,对吧?) . 通常,这个新创建的活动套接字对象然后被移交给另一个进程或线程,或只是"entity"负责连接 . 在 accept() 返回此连接的套接字对象之后,可以在被动套接字上再次调用 accept() ,并且一次又一次地调用 accept loop . 但是召唤 accept() 需要时间,对吧?它不能错过传入的连接请求吗?刚引用的帮助文本中有更多基本信息:有一个挂起的连接请求队列!它由操作系统的TCP / IP堆栈自动处理 . 这意味着虽然 accept() 只能处理传入的连接请求 one-by-one ,但即使它们以高速率或(准)同时传入,也不会丢失传入请求 . 可以说 accept() 的行为限制了机器可以处理的传入连接请求的频率 . 然而,这是一个快速的系统调用,并且在实践中,其他限制首先出现 - 通常与处理到目前为止已接受的所有连接相关的限制 .

  • 5

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

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

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

    • 客户端A使用HTTP请求连接到端口80上的服务器以启动webSocket连接 . 此过程在两者之间创建套接字 .

    • 服务器响应是,升级到webSocket请求和两个客户端和服务器将协议 for this socket only 切换到webSocket协议 .

    • 客户端A和服务器使用webSocket协议开始交换数据包,并在接下来的几个小时内继续这样做 .

    • 客户端B使用常规HTTP请求连接到端口80上的同一服务器 . 此过程在两者之间创建一个新套接字 .

    • 服务器看到传入请求是正常的HTTP请求并发送响应 .

    • 当客户端B收到响应时,套接字将关闭 .

    • 客户端C使用HTTP请求连接到端口80上的同一服务器以升级到webSocket .

    • 服务器响应是,升级到webSocket请求,客户端和服务器都将协议 for this socket only 切换到webSocket协议 .

    • 此时,有两个使用webSocket协议的开放套接字可以进行通信,服务器仍在接受可以是常规HTTP请求的新连接,也可以是更新webSocket协议的请求 .

    因此,在任何时候,服务器仍然接受端口80上的新连接,并且这些新连接可以是常规HTTP请求,也可以是请求升级到webSocket协议的HTTP请求(从而启动webSocket连接) . 而且,虽然所有这些都在进行,但已经 Build 的webSocket连接正在使用webSocket协议通过它们自己的套接字进行通信 .

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

    • 无需新端口 . 传入端口(最常见的是端口80)可用于常规HTTP请求和webSocket通信 .

    • 因为不需要新端口,所以防火墙或其他网络基础设施的更改不需要"usually" . 事实证明并非总是如此,因为可能必须修改一些期望HTTP流量的代理或缓存来处理(或避免)webSocket协议流量 .

    • 相同的服务器进程可以轻松处理HTTP请求和webSocket请求 .
      在设置webSocket连接期间,可以使用

    • HTTP cookie和/或其他基于HTTP的身份验证方法 .


    您的进一步问题的答案:

    1)为什么选择80作为默认端口?设计人员是否希望从传输级别的角度使WebSocket通信看起来像普通的HTTP通信? (即服务器端口是好旧的80) .

    是的,请看我上面的1-4点 . webSockets可以通过现有的HTTP通道 Build ,因此它们通常不需要更改网络基础结构 . 我想补充一点,即不需要新的服务器或服务器进程,因为现有的HTTP服务器可以简单地添加webSocket支持 .

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

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

    在我的例子中,我选择了与node.js一起使用的socket.io库(这是我的服务器架构) . 该库为我提供了一个对象,该对象支持新连接webSockets的事件,然后是一组用于读取传入消息或发送传出消息的其他事件 . 初始webSocket连接的详细信息都由库处理,我不必担心任何问题 . 如果我想在 Build 连接之前要求身份验证,socket.io库可以让我插入它 . 然后我可以从任何客户端接收消息,向任何单个客户端发送消息或向所有客户端发送广播信息 . 我主要用它来播放保持网页中的某些信息“实时”,以便网页显示始终是最新的 . 无论何时服务器上的值发生更改,我都会将新值广播到所有连接的客户端 .

  • 60

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

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

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

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

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

    WebSocket协议有两部分: Build 升级连接的握手,然后是实际的数据传输 . 首先,客户端通过使用“Upgrade:websocket”和“Connection:Upgrade”标头以及一些特定于协议的标头来请求websocket连接,以 Build 正在使用的版本并设置握手 . 如果服务器支持该协议,则使用相同的“Upgrade:websocket”和“Connection:Upgrade”标头进行回复并完成握手 . 握手成功完成后,数据传输开始 .

    只有Websocket服务通常不会内置到Web服务器中,所以不是真正打算在端口80中侦听,只是通过它可以通过Web服务器的透明转发进行访问 . Apache Web服务器使用mod_proxy_wstunnel执行此操作 .

    当然,您也可以使用内置Web套接字实现的Web服务器:例如Apache Tomcat .

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

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

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

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

    主要优点是:Websocket服务可以在需要时向客户端发送消息("one of you buddies has connected!" "your team just scored a goal!"),而不必等待客户端显式请求更新 .

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

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

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

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

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

    与往常一样,以监听一个特定TCP套接字(SERVER_IP:service_TCP_port)一个服务的所有连接:client_TCP_port对,client_TCP_port被随机地由客户端选择之中其可用的TCP端口)分配一个唯一的CLIENT_IP时,将区分 .

    如果您仍然对Websocket连接握手时发生的HTTP-> Websocket应用程序协议切换有疑问,以及它与底层TCP连接没有任何关系,我建议您使用Jan-Philip Gehrcke's answer,这非常明确,很有启发性你真正想要的是什么 .

  • 1

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

    Multiple connections

    • Web服务器开始侦听连接 . 有时候是这样的:

    • Web服务器的主进程在端口 80 上的状态 listen 中打开被动套接字,例如 9.9.9.9:809.9.9.9 是服务器IP, 80 是端口) .

    • 浏览器发出请求在服务器上端口 80 . 有时候是这样的:

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

    • OS发送一个数据包,其源地址为 1.1.1.1:6747 ,目标地址为 9.9.9.9:80 . 它通过各种路由器和交换机到达目标服务器 .

    • 服务器收到数据包 . 有时候是这样的:

    • 服务器操作系统发现数据包的目标地址是其自己的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 handshake

    HTTP是基于文本的协议 . 有关可用命令的列表,请参阅HTTP wiki . 浏览器发送其中一个命令,Web服务器相应地响应 .

    WebSocket不基于HTTP . 它是一种二进制协议,可以同时在两个方向上发送多个消息流(全双工模式) . 因此,如果不引入新的HTTP标准,就不可能直接 Build WebSocket连接,例如HTTP/2 . 但只有在以下情况下才有可能:

    • 支持WebSocket HTTP verbs/requests

    • 有一个不同于 80 的新专用端口用于特定于WebSocket的通信 .

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

相关问题