简介
介绍WebSocket之前需要先了解一个更基本的协议:超文本传输协议(Hyper Text Transfer Protocol,HTTP),它是一个简单的请求——响应协议,通常运行在TCP之上。
HTTP有一个问题:单向。即只能是客户端(浏览器)向服务器发送请求,服务器返回查询结果。如果服务器状态有连续的变化,就要求客户端进行轮询,这显然是效率很低的。
WebSocket就是用来解决HTTP的这个问题的,它是一种在单个TCP连接上进行全双工通信的协议。
下图是HTTP和WebSocket协议的实现差别:
WebSocket还有以下的特点:
- 建立在TCP协议之上,服务器端的实现比较容易;
- 与HTTP协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用HTTP协议,因此握手时不容易屏蔽,能通过各种HTTP代理服务器;
- 数据格式比较轻量,性能开销小,通信高效;
- 可以发送文本,也可以发送二进制数据;
- 没有同源限制,客户端可以与任意服务器通信;
- 协议标识符是
ws
(如果加密,则为wss
),服务器网址也是URL,下面是一个示例:
ws://example.com:80/some/path
客户端代码接口
WebSocket客户端代码编写比较简单,直接通过JavaScript调用WebSocket接口即可,这里简单介绍。
构造函数
WebSocket(url[, protocols])
该函数返回一个 WebSocket对象。
url
不用多介绍;protocols
是可选的,是一个协议字符串或者一个包含协议字符串的数组,不确定有哪些值可用,不指定就是空字符。
常量
常量名 | 值 |
---|---|
WebSocket.CONNECTING | 0 |
WebSocket.OPEN | 1 |
WebSocket.CLOSING | 2 |
WebSocket.CLOSED | 3 |
属性
属性名 | 作用 |
---|---|
WebSocket.binaryType | 使用二进制的数据类型连接。 |
WebSocket.bufferedAmount | 未发送至服务器的字节数。只读。 |
WebSocket.extensions | 服务器选择的扩展。只读。 |
WebSocket.onclose | 用于指定连接关闭后的回调函数。 |
WebSocket.onerror | 用于指定连接失败后的回调函数。 |
WebSocket.onmessage | 用于指定当从服务器接受到信息时的回调函数。 |
WebSocket.onopen | 用于指定连接成功后的回调函数。 |
WebSocket.protocol | 服务器选择的下属协议。只读。 |
WebSocket.readyState | 当前的链接状态。只读。 |
WebSocket.url | WebSocket 的绝对路径。只读。 |
方法
WebSocket.close([code[, reason]])
关闭当前链接。
WebSocket.send(data)
对要传输的数据进行排队。
事件
使用 addEventListener()
可以监听下面的事件:
事件名 | 作用 |
---|---|
close | 当一个WebSocket连接被关闭时触发。 |
error | 当一个WebSocket连接因错误而关闭时触发,例如无法发送数据时。 |
message | 当通过WebSocket收到数据时触发。 |
open | 当一个WebSocket连接成功时触发。 |
上述事件也可以通过对应的onXXX属性来设置。
下面是一个示例:
// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');
// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
websocketd
服务器端示例
这里首先使用一款简单的WebSocket服务端程序作为WebSocket服务器来与客户端通信,这款程序是websocketd,可以在http://websocketd.com/下载到,Windows下得到的程序如下:
使用websocketd的一个最简单的例子如下:
websocketd.exe --port=8080 xxx
其中xxx是自己编写的程序。这个程序可以用很多的语言来编写,最主要的共同点是:输出即传输的数据。下面是一个c语言编写的例子:
#include <stdio.h>
#include <unistd.h>
int main() {
int i;
// 关闭缓冲
setbuf(stdout, NULL);
for (i = 0; i < 10; i++) {
printf("%d\n", i);
usleep(500000);
}
return 0;
}
注意这里的setbuf(stdout, NULL);
是必不可少的,否则数据不会立即发送给浏览器WebSocket,而是等到程序结束之后才一起发送,在浏览器端就看不到预期的结果了。
如果直接执行该文件,就是每隔0.5秒打印一个从0开始递增的数字,结果如下:
这里将它作为websocketd.exe的参数:
websocketd.exe --port=8080 count.exe
这样就开起了一个WebSocket服务:
客户端编程示例
WebSocket客户端最常见的就是普通的浏览器,这里编写一个HTML网页,其实现中通过JavaScript编写WebSocket代码,示例如下:
<!DOCTYPE html>
<pre id="log"></pre>
<script>
// 显示信息的帮助函数
function log(msg) {
document.getElementById('log').textContent += msg + '\n';
}
// 创建WebSocket
var ws = new WebSocket('ws://localhost:8080/');
// 连接创建时执行
ws.onopen = function() {
log('connected');
};
// 连接关闭时执行
ws.onclose = function() {
log('closed');
};
// 收到数据时执行
ws.onmessage = function(event) {
log('message: ' + event.data);
};
</script>
直接在浏览器中打开该文件,执行结果如下:
这里的message将每隔0.5秒打印一次,结束之后打印closed,此时WebSocket的连接也断开了。
其它
以上是一个最简单的示例,该示例中传输的数据也是普通的字符,通过通用输入输出的拦截来完成传输,跟Web服务器类似。不过WebSocket还支持二进制,这个这里暂时不做演示。
另外,虽然说服务器端程序支持很多种语言,但是Python版本执行会报错:
原因不明。
另外websocketd的源码可以在https://github.com/joewalnes/websocketd下载到,它是Go语言编写的。
pywebsocket3
下载pywebsocket3,下载地址是https://github.com/GoogleChromeLabs/pywebsocket3。
进入对应的目录执行构建、安装和使用:
之后通过浏览器访问:
上述显示来自pywebsocket的示例代码(通过-d .\example\
指定)。
参考
- https://www.ruanyifeng.com/blog/2017/05/websocket.html
- https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
- http://websocketd.com/
- https://github.com/GoogleChromeLabs/pywebsocket3/wiki