根据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
指出 .
我想补充几点想法 .
WebSocket
和 HTTP
都只是应用程序级协议 . 通常他们都依赖于 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 回答
其他答案已经有所帮助 . 我想指出你的问题是一个非常好的问题,并希望从涉及
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 A 和 IP:PORT of Machine B 和 the protocol (TCP or UDP)
现在,通常认为套接字对象代表连接 . 但这并非完全正确 . 它们可能代表不同的东西:它们可以是主动的或被动的 . passive/listen 模式中的套接字对象做了一些非常特殊的事情,这对回答你的问题非常重要 . http://linux.die.net/man/2/listen说:
因此,我们可以创建一个监听传入连接请求的 passive 套接字 . 根据定义,这样的套接字永远不能代表连接 . 它只是监听连接请求 .
让我们前往
accept()
(http://linux.die.net/man/2/accept):这就是我们需要知道的所有内容,以便回答您的问题 .
accept()
不会更改之前创建的 passive 套接字的状态 . 它返回一个 active (connected) 套接字(这样的套接字代表上面五条信息状态 - 简单,对吧?) . 通常,这个新创建的活动套接字对象然后被移交给另一个进程或线程,或只是"entity"负责连接 . 在accept()
返回此连接的套接字对象之后,可以在被动套接字上再次调用accept()
,并且一次又一次地调用 accept loop . 但是召唤accept()
需要时间,对吧?它不能错过传入的连接请求吗?刚引用的帮助文本中有更多基本信息:有一个挂起的连接请求队列!它由操作系统的TCP / IP堆栈自动处理 . 这意味着虽然accept()
只能处理传入的连接请求 one-by-one ,但即使它们以高速率或(准)同时传入,也不会丢失传入请求 . 可以说accept()
的行为限制了机器可以处理的传入连接请求的频率 . 然而,这是一个快速的系统调用,并且在实践中,其他限制首先出现 - 通常与处理到目前为止已接受的所有连接相关的限制 .你似乎在这里缺少的相对简单的事情是每个连接到服务器(特别是你的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-4点 . webSockets可以通过现有的HTTP通道 Build ,因此它们通常不需要更改网络基础结构 . 我想补充一点,即不需要新的服务器或服务器进程,因为现有的HTTP服务器可以简单地添加webSocket支持 .
不同的服务器体系结构将以不同方式处理webSocket数据包和HTTP请求之间的划分 . 在某些情况下,webSocket连接甚至可能被转发到新进程 . 在其他情况下,它可能只是在同一进程中的一个不同的事件处理程序,它注册了套接字上的传入数据包流量,现在已经切换到webSocket协议 . 这完全取决于Web服务器体系结构以及它如何选择处理webSocket流量 . 实现webSocket应用程序服务器端的开发人员很可能会选择与其特定Web服务器体系结构兼容的现有webSocket实现,然后编写在该框架内工作的代码 .
在我的例子中,我选择了与node.js一起使用的socket.io库(这是我的服务器架构) . 该库为我提供了一个对象,该对象支持新连接webSockets的事件,然后是一组用于读取传入消息或发送传出消息的其他事件 . 初始webSocket连接的详细信息都由库处理,我不必担心任何问题 . 如果我想在 Build 连接之前要求身份验证,socket.io库可以让我插入它 . 然后我可以从任何客户端接收消息,向任何单个客户端发送消息或向所有客户端发送广播信息 . 我主要用它来播放保持网页中的某些信息“实时”,以便网页显示始终是最新的 . 无论何时服务器上的值发生更改,我都会将新值广播到所有连接的客户端 .
回答你的问题:处理到端口80的同步Websocket和HTTP连接......
与处理端口80的同时HTTP连接完全相同!
这意味着:在满意的TCP握手时,监听serviceip:80的服务继续产生一个新的进程或线程,并将该连接的所有通信切换到它(或者通过执行与该事件关联的回调作为异步来提供请求nodejs,正如jfriend00正确指出的那样) .
然后等待或处理队列中的下一个传入请求 .
如果你想知道HTTP 1.1和UPGRADE请求在所有这些上发挥了什么作用,那么MSDN article就会非常清楚:
只有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,这非常明确,很有启发性你真正想要的是什么 .
这是一个非常简单的概念,所以让我试着用简单的术语来描述它,以防其他一些失去的灵魂想要 grab 它而不必阅读所有这些长篇解释 .
Multiple connections
Web服务器开始侦听连接 . 有时候是这样的:
Web服务器的主进程在端口
80
上的状态listen
中打开被动套接字,例如9.9.9.9:80
(9.9.9.9
是服务器IP,80
是端口) .浏览器发出请求在服务器上端口
80
. 有时候是这样的:操作系统(简称OS)在客户端上分配随机出站端口,例如:
1.1.1.1:6747
(1.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进行 .