websocket
websocket
websocket协议
WebSocket是一种网络通信协议,很多高级功能都需要它,例如浏览器与服务器之间的实时通信。
WebSocket协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
WebSocket协议和HTTP协议都是应用层协议,都基于TCP协议。但是,WebSocket协议是一种双向通信协议,在建立连接后,WebSocket服务器和Browser/Client Agent都能主动向对方发送或接收数据,就像Socket一样;而HTTP协议是一种单向通信协议,只能由Client Agent向WebSocket服务器发送请求,WebSocket服务器不能主动向Client Agent发送数据,但是WebSocket服务器可以向Client Agent发送HTTP响应。
它的最大特点就是:服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
WebSocket协议在建立握手时,数据是通过HTTP传输的,但是建立之后,在真正进行数据传输时,是不需要HTTP协议的,因此,WebSocket是一个独立的协议。
websocket的优势
WebSocket协议相比传统的HTTP协议有如下优势:
- 支持双向通信,实时性更强;
- 较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部;
- 支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议(例如支持自定义压缩算法等);
- 更好的压缩效果。相比HTTP协议,Websocket协议中包头的数据量小很多;
- 支持更多类型的数据。WebSocket定义了二进制帧,相比HTTP协议传输数据类型更多样化。
websocket的缺点
- 需要服务器支持。因为需要服务器进行协议升级处理,所以需要服务器支持WebSocket协议;
- 连接不能穿透防火墙。因为使用的是TCP协议,所以连接不能穿透防火墙;
- 数据包头部比较大。每次通信都需要携带完整的头部,带宽占用较多。
websocket的应用场景
- 聊天室
- 网络游戏
- 在线教育
- 在线客服
- 实时数据推送
- 在线视频/音频会议
- 在线多人协作开发
- 在线多人实时协作办公
websocket的使用
建立连接
WebSocket协议本质上是一个基于TCP的协议,WebSocket连接在建立时需要借助HTTP协议,连接建立好后,底层的TCP连接就与HTTP无关了。
WebSocket连接的建立过程如下:
客户端向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的HTTP请求,服务器端解析这些附加头信息,如果同意协议升级,则返回101状态码表示成功,表示协议已经升级,这时候TCP连接就升级为WebSocket连接了,后续的数据交换都按照WebSocket协议来进行,如果不同意协议升级,则返回4xx或5xx的状态码,表示协议升级失败,连接会按照HTTP协议来进行;
客户端和服务器端都可以在任意时刻发送数据,数据以帧(Frame)为单位传输,每个帧包含一定的数据以及标识信息,如数据是否被加密过、是否为控制帧等。
数据帧
WebSocket的不同类型的帧负责不同的功能,帧的类型如下:
- 0x0:表示附加数据帧;
- 0x1:表示文本数据帧;
- 0x2:表示二进制数据帧;
- 0x3-7:保留的数据帧类型;
- 0x8:表示连接关闭;
- 0x9:表示ping;
- 0xA:表示pong;
- 0xB-F:保留的控制帧类型。
数据帧的格式
WebSocket协议定义了数据帧的格式,如下图所示:
数据帧的格式如下:
- FIN:1位,表示这是消息的最后一个数据帧;
- RSV1, RSV2, RSV3:各1位,保留字段,暂时不使用;
- Opcode:4位,表示数据帧的类型,如果是0x0表示附加数据帧,如果是0x1表示文本数据帧,如果是0x2表示二进制数据帧,如果是0x8表示连接关闭,如果是0x9表示ping,如果是0xA表示pong;
- Mask:1位,表示是否要对数据进行掩码处理,从客户端向服务器端发送数据时,需要对数据进行掩码处理,从服务器端向客户端发送数据时,不需要对数据进行掩码处理;
- Payload length:7位,表示数据的长度,如果是0~125,表示数据的长度,如果是126,表示后面2个字节表示数据的长度,如果是127,表示后面8个字节表示数据的长度;
- Masking-key:4字节,如果Mask为1,表示掩码,否则为0;
- Payload data:数据,长度等于Payload length。
WebSocket的使用
WebSocket的使用非常简单,只需要通过JavaScript的WebSocket对象即可,WebSocket对象的使用如下所示:
// 创建WebSocket对象
var ws = new WebSocket("ws://localhost:8080");
// 监听WebSocket的打开事件
ws.onopen = function() {
console.log("WebSocket已经打开");
};
// 监听WebSocket的关闭事件
ws.onclose = function() {
console.log("WebSocket已经关闭");
};
// 监听WebSocket的错误事件
ws.onerror = function() {
console.log("WebSocket发生错误");
};
// 监听WebSocket的消息事件
ws.onmessage = function(event) {
console.log("WebSocket接收到消息:" + event.data);
};
// 向WebSocket发送消息
ws.send("Hello WebSocket");
WebSocket的实现
WebSocket的实现非常简单,只需要使用Java的ServerSocket即可,ServerSocket的使用如下所示:
// 创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(8080);
// 监听客户端的连接
Socket socket = serverSocket.accept();
// 获取输入流
InputStream inputStream = socket.getInputStream();
// 获取输出流
OutputStream outputStream = socket.getOutputStream();
// 读取数据
byte[] buffer = new byte[1024];
int length = inputStream.read(buffer);
String data = new String(buffer, 0, length);
System.out.println("接收到数据:" + data);
// 发送数据
outputStream.write("Hello WebSocket".getBytes());
// 关闭连接
socket.close();