事先说明这是鄙人看了一点入门文章总结的粗浅的知识, 并不保证理解完全正确,用来给自己知识梳理用。
连接过程
WebSocket 建立连接需要先通过一个 http 请求进行和服务端握手。握手通过后连接就建立并保持了。
浏览器先发送请求:
GET / HTTP/1.1
Host: localhost:8080
Origin: [url=http://127.0.0.1:3000]http://127.0.0.1:3000[/url]
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==
服务端返回一个请求:
HTTP/1.1 101 Switching Protocols
Connection:Upgrade
Upgrade: WebSocket
Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=
这样握手就完成了(具体 http 请求头和返回头各个字段的含义我就懒得写了,网上一搜一大把,譬如http://www.52im.net/thread-1341-1-1.html)。此时这个连接并不会断掉,而浏览器和服务端可以用这个连接相互发消息。(但是这个时候连接就不是 http 连接而是升级成了 WebSocket 连接。浏览器和服务端相互发送的不是 http 请求。这里先说明下,接下来我们来看下 http 长连接是怎么回事)。
http长连接
keep-alive
http1.1 出了新头,如果请求头中包含 keep-alive,那么这个 http 请求发送收到返回之后,底层的 tcp 连接不会立马断掉,如果后续有 http 请求还是会利用。但是这个连接保持一来是没有硬性规定时间的,由浏览器和服务端实现来控制。二来这个连接不断是指底层 tcp 连接,不是说一次 http 请求收到返回之后不会断掉,还能再收服务端的返回(如果服务端对这次 http 请求立马返回,那么这次 http 请求就结束了。http 请求和底层 tcp 连接的关系后面再说)。这种不是应用层面的长连接,其实和模拟 WebSocket 没啥关系。comet
这种技术是一种 hack 技术,即浏览器发送一个 http 请求,但是服务端不是立马返回,服务端一直不返回直到有浏览器需要的内容了在返回。期间这个 http 请求可以连着维持比较长的时间(在服务端返回之前)。这样模拟一种服务端推送机制。因为浏览器请求的时候等于先把连接建立好,等服务端有消息需要返回时再返回给浏览器。
区别
先说 comet 和 WebSocket 表现的区别:
comet 发送 http 请求后服务端如果没有返回则连接是一直连着的,等服务端有东西要“推送”给浏览器时,相当于给之前发送的这个 http 请求回了一个 http 响应。然后这个保持的时间比较长的 http 连接就断了。然后浏览器再次发送一个 http 请求,服务器端再 hold 住不返回,等待有东西需要“推送”给浏览器时,再给这个 http 请求一个响应,然后断开连接。循环往复。一旦浏览器不给服务器发送 http 请求,那么服务器是不能主动给浏览器推送消息的,因为根本没有连着的连接给你推。
WebSocket 则不同,它握手后建立的连接是不会断的(除了意外情况和程序主动掐断)。不需要浏览器在每次收到服务器推送的消息后再发起请求。而且服务器端可以随时给浏览器推送消息,不需要等浏览器发 http 请求,因为 WebSocket 的连接一直在没断。
为什么会有这样的区别
这是协议层面的区别。http 协议规定了 http 连接是一个一来(request)一回(response)的过程。一个请求获得一个响应后必须断掉。而且只有先有请求才会有响应。拿 http1.1 keep-alive 来说,即使底层 tcp 连接没有断,服务端无缘无故给浏览器发一个 http 响应,浏览器是不收的,他找不到收的人啊,因为这个响应没有对应的请求。你看 ajax 必须先发请求才会有一个 onsuccess 回调来响应这个请求。这个 onsuccess 的回调会在你 ajax 不发送的情况下被调用到吗?
而 WebSocket 协议不同,他通过握手之后规定说你连接给我保持着,别断咯。所以浏览器服务器在这种情况下可以相互的发送消息。浏览器端 new 一个 WebSocket 之后注册 onmessage 回调,那么这个 onmessage 可以被反复调用,只要服务器端有消息过来。而不会说是 new 一个 WebSocket onmessage 只会被调用一次,下次还得再 new 一个 websocket。
此连接彼连接
上面说到 http 连接,tcp 连接,websockt 连接到底啥区别。其实这是新人最容易搞不懂的地方。接下来我就要胡诌了,为啥说胡诌,因为我只是看了个皮毛,然后按我自己的理解说下区别。网络5层分层(自下而上):
- 物理层
- 数据链路层
- 网络层
- 传输层
- 应用层
http,websocket都是应用层协议,他们规定的是数据怎么封装,而他们传输的通道是下层提供的。就是说无论是 http 请求,还是 WebSocket 请求,他们用的连接都是传输层提供的,即 tcp 连接(传输层还有 udp 连接)。只是说 http1.0 协议规定,你一个请求获得一个响应后,你要把连接关掉。所以你用 http 协议发送的请求是无法做到一直连着的(如果服务器一直不返回也可以保持相当一段时间,但是也会有超时而被断掉)。而 WebSocket 协议规定说等握手完成后我们的连接不能断哈。虽然 WebSocket 握手用的是 http 请求,但是请求头和响应头里面都有特殊字段,当浏览器或者服务端收到后会做相应的协议转换。所以 http 请求被 hold 住不返回的长连接和 WebSocket 的连接是有本质区别的。
参考资料
- WebSocket 规范:https://tools.ietf.org/html/rfc6455
- 《Http、TCP/IP协议与Socket之间的区别》https://blog.csdn.net/done58/article/details/50996680