Websoket学习 | 青训营笔记

103 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1天

简介

WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议。

双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端)。

应用在浏览器的 Socket (是 Socket 模型接口的实现),Socket 是一个网络[通信接口] 协议端口80,SSL协议端口是443。

Socket是TCP/IP协议的网络数据通讯接口(一种底层的通讯的方式)。

Socket是IP地址和端口号的组合。例如:192.168.1.100:8080。 WebSocket可以实现客户端与服务器间双向、基于消息的文本或二进制数据传输。是浏览器中最靠近套接字的API,但WebSocket连接远远不是一个网络套接字,因为浏览器在这个简单的API之后隐藏了所有的复杂性,而且还提供了更多服务:

连接协商和同源策略

与既有HTTP基础设施的互操作

基于消息的通信和高效消息分帧

子协议协商及可扩展能力

WebSocket是浏览器中最通用最灵活的一个传输机制,其极简的API可以让我们在客户端和服务器之间以数据流的形式实现各种应用数据交换(包括JSON及自定义的二进制消息格式),而且两端都可以向另一端发送数据。

优点

较少的控制开销,连接建立后,客户端和服务器之间交换数据时,用于协议控制的数据包头部相对较小,相对于HTTP每次请求都要携带完整的头部,此项开销显著减少了

更强的实时性,由于协议是全双工的,服务器可以随时主动给客户端下发数据。相对于HTTP请求需要客户端发送请求服务端才能响应,延迟明显减少

长连接保持连接状态,与HTTP不同的是,WebSocket需要先创建连接,这使得它成为一种有状态的协议,之后通信就可以忽略状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)

双向通信、更好的二进制支持。与HTTP协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用HTTP协议,因此握手时不容易被屏蔽,能通过各种HTTP代理服务器

状态码

连接成功状态码

101:HTTP协议切换为WebSocket协议。

连接关闭状态码

1000:正常断开连接。

1001:服务器断开连接。

1002:websocket协议错误。

1003:客户端接受了不支持数据格式(只允许接受文本消息,不允许接受[二进制数据],是客户端限制不接受二进制数据,而不是websocket协议不支持二进制数据)。

1006:异常关闭。

1007:客户端接受了无效数据格式(文本消息编码不是utf-8)。

1009:传输数据量过大。

1010:客户端终止连接。

1011:服务器终止连接。

1012:服务端正在重新启动。

1013:服务端临时终止。

1014:通过网关或代理请求服务器,服务器无法及时响应。

1015:TLS握手失败。

连接关闭状态码是WebSocket对象的onclose属性返回的。

握手规则

websocket是基于应用层的传输控制协议,而socket是基于传输层的传输控制协议。它们都是全双工的(可以同时接收和发送),传输层意味着数据都是以16进制传输,而传输层以二进制传输。

websocket的握手分为客户端请求和服务器端回应。

客户端的请求如下:

GET / HTTP/1.1 // 这个请求必须是GET请求,并且HTTP的协议必须是1.1 Connection:Upgrade // 表示客户端希望连接升级 Upgrade:websocket // 这个值必须是websocket,表示请求升级为websocket协议 Host:xxxx // 请求的主机名称 Origin:xxxx // 打开这个socket的页面 Sec-Websocket-Key:sN9cRrP/n9NdMgdcy2VJFQ== // 随机生成的字符串,客户端通过GUID来验证这个参数是不是一个有效请求 Sec-WebSocket-Version:13 // websocket使用的协议,RFC6455规定这个值必须万为13 Sec-WebSocket-Protocol:xxx // 客户端可以指定应用程序支持的协议,服务器选择其中的一个做为双方通信的协议 Sec-webSocket-Extension:xxxx // 客户端指定某些扩展协议,服务器选择其中一个 服务器端的回应如下:

HTTP/1.1 101 Switching Protocols // 服务器端同意客户端的握手请求
Connection: Upgrade // 同意这个连接升级
Sec-WebSocket-Accept: IIRiohCjop4iJrmvySrFcwcXpHo= // 通过GUID计算出来的值
Sec-WebSocket-Version: 13 // websocket的版本
Upgrade: websocket // 同意升级为websocket协议

如果HTTP的状态不是101客户端应该断开这个连接,如果Sec-WebSocket-Protocol规定了其中的子协议则服务器必须响应其中一个,否则客户端必须断开这个连接。

Sec-WebSocket-Accept的值以php计算如下:

$client_key = 'xxxxx';
$guid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
$join = $client_key . $guid;
$sha1 = sha1($join,true);
$accept = base64_encode($sha1);

也就是客户端的Sec-WebSocket-Key的值加上GUID后,哈希为20个字符串后,再使用base64编码即可得到服务器的Sec-WebSocket-Accept的值