概述
刚看到WeSocket的时候,我以为是HTTP相关,但是在前两天搭了一个简单的Client之后, 我发现这不就是TCP长连接么? 建立连接->通信->断开连接. 直到今天, 我在调试的时候, 发现发出了HTTP请求, 我想, 事情可能不是我想的那样.
先来简单描述一下当时的情况
我用Python代码简单打了一个WebSocket
客户端, 想着试一试, 代码很简单, 就是这:
import websocket
import threading
import timeclass Status:INIT = 'init'OPENED = 'opened'CLOSED = 'closed'class WSTest:def __init__(self):self.thread = Noneself.ping_thread = Noneself.ws = Noneself.status = Status.INITdef send_message(self, message) -> bool:if self.status != Status.OPENED:return Falseself.ws.send(message)return Truedef close(self):self.ws.close()# 等待关闭for i in range(200):time.sleep(0.02)if self.status == Status.CLOSED:breakif self.status != Status.CLOSED:returnif self.ping_thread and self.ping_thread.is_alive():self.ping_thread.join()def run(self):def on_message(ws, message):print(message)def on_error(ws, error):print(error)def on_close(ws):print('关闭连接')self.status = Status.CLOSEDdef on_open(ws):self.status = Status.OPENEDself.ws = websocket.WebSocketApp("ws://echo.websocket.org",on_open=on_open,on_message=on_message,on_close=on_close,on_error=on_error)self.ping_thread = threading.Thread(target=self.ws.run_forever, args=(None, None, 2, 5))self.ping_thread.start()if __name__ == "__main__":ws = WSTest()ws.run()while True:s = input()if s == 'close':breakws.send_message(s)ws.close()
上面的ws://echo.websocket.org
是一个测试用的域名,你发送什么过去,他就会返回什么. 到这里我简单运行了一下,还可以.本来我想简单搭一个,能调通就得了呗,但是,手贱的我打开了wireshark
. 我想看一下它的网络连接.
wireshark抓包查看
首先,找到域名的IP
找到IP后就可以直接对IP进行过滤,找到接收和发送的数据包.直接过滤所有DNS解析请求,查找指定域名.
然后,针对地址对请求进行过滤
来来来,看到了什么?前面三个TCP请求是三次握手的请求,在三次握手之后的第一个请求是什么,HTTP???
看一下它的请求内容:
看到第一个Upgrade
之后,我仿佛懂了.这个字段的含义是要将协议升级.后面跟着的就是websocket
了,再看一下服务器的response
.(后面那个TCP请求可以跳过,就是服务器告诉你它收到了).
响应内容虽然有不明白的地方,但是大概看来,是同意升级协议的意思了.再然后才是websocket
通信内容,以及最后的挥手告别.
也就是说,websocket
虽然能够实现双向通信,但是它的连接建立是从HTTP开始,然后升级协议来的??
所以websocket
的通信流程是:
- 三次握手建立TCP通信
- 发起HTTP请求,升级为
websokcet
协议 - 开始websocket通信
- 断开连接
如果把中间的websocket
去掉,那就完全是HTTP协议了. 没想到websocket
与HTTP
是兄弟俩.
思考
既然WebSocket
是基于HTTP
协议建立的, 那么他的出现就一定是在HTTP
之后, 这就说明它一定是为了解决HTTP
的某些问题而出现的. 很显然: HTTP的单向通信限制, 服务器不能主动联系客户端
HTTP
协议本身就是基于TCP
的, 而TCP
本身就是全双工通信的. 这感觉就像是他们借用了一下HTTP, 然后说咱们接下来就都用WebSocket
吧.
那么问题来了, 既然要实现这种长连接, 为什么还要借助HTTP
之手, 直接TCP
建立连接不行么? 查了一下, 发现是为了兼容. 因为WebSocket
就是为了解决HTTP
协议问题, 也就是说主要运行在之前HTTP
的场景中, 而为了兼容现有浏览器的握手规范, 所以借助了HTTP
协议来完成握手.
WebSocket
协议是: ws
和 wss
. 其区别与 http
和 https
相同. wss
就是在 ws
的通信过程中再套一层TLS/SSL
协议.
那么WebSocket
有哪些应用场景呢?
可以这么说, 在原来使用HTTP协议进行轮训的场景, 都可以使用WebSocket
替换.
- 在线聊天
- 直播
- 在线多人游戏
- 等等…
最后, 记一下建立连接的HTTP
请求的头信息
request
- connection: Upgrade 升级协议
- Upgrade: websocket 指定升级为
WebSocket
协议 - Sec-WebSocket-Key: 用于判断客户端是否有权升级协议
- Sec-WebSocket-Version:指定
WebSocket
版本
response
- Upgrade: websocket 成功升级协议
- Sec-WebSocket-Accept: 通过
Sec-WebSocket-Key
计算得来