怎么在服务器上加websocket协议,从零开始实现一个简单的WebSocket协议

本文介绍了WebSocket协议的基础知识及其在服务器端的实现过程,包括建立连接、数据帧的解析与编码、服务端发送数据的方法。通过自定义WebSocket类,详细阐述了如何监听升级事件、处理客户端数据以及发送服务器端数据,为实现全双工通信提供了清晰的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、WebSocket简介

WebSocket是一种基于TCP连接的全双工通信的协议,其工作在应用层,建立连接的时候通过复用http握手通道,完成http协议的切换升级,即切换到WebSocket协议,协议切换成功后,将不再需要客户端发起请求,服务端就可以直接向客户端发送数据,实现双向通信。

相对于Http协议而言,WebSocket有以下优点:

可以支持双向通信

WebSocket协议可以更好的支持二进制,可以直接传送二进制数据。

同时WebSocket协议的头部非常小,服务器发到客户端的数据包的包头,只有2~10个字节(取决于数据包的长度),客户端发送服务端的包头稍微大一点,因为其要进行掩码加密,所以还要加上4个字节的掩码。总得来说,头部不超过14个字节。

支持扩展,用户可以扩展协议实现自己的子协议。

二、实现一个WebSocket协议

① 设计WebSocket协议

我们使用WebSocket的时候,是通过new一个WebSocket对象,所以Websocket是一个类,同时在创建对象的时候,需要传递一些配置对象作为参数。由于WebSocket可以复用http握手通道,所以我们需要有一个web服务器,才能复用http的握手通道,所以如果我们已经创建好了一个web服务器,那么我们可以把这个web服务器传递给WebSocket,那么WebSocket就不需要再创建自己的web服务器了;当然我们也可以只传递一个端口号,由WebSocket自己创建一个web服务器。当客户端发来了消息,我们还需要能够通知到Websocket对象,所以我们还需要让WebSocket继承EventEmitter,如:

const http = require("http");

const { EventEmitter } = require('events')

class WebSocket extends EventEmitter {

constructor(options) {

super();

if (options.server) {

this.server = options.server; // 使用了传递的web server

} else {

this.server = http.createServer(); // 自己创建一个web server

this.server.listen(options.port || 3000);// 监听端口,默认3000

}

}

}

② 建立连接,切换升级到WebSocket协议

上一步,我们的WebSocket已经拥有web服务器了,接下来我们就是需要客户端通过http请求协议切换升级,当浏览器通过new WebSocket()创建WebSocket客户端的时候,浏览器会自动发起协议升级请求,如:

bVbEMHG

bVbEMHL

Connection: Upgrade 表示要升级协议

Upgrade: websocket 表示要升级到websocket协议

Sec-WebSocket-version 表示websocket的版本。

Sec-WebSocket-Key 浏览器生成的一个字符串,服务器端需要取出该字符串与258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接,然后通过SHA1算法计算出摘要,并转成base64字符串,然后作为Sec-WebSocket-Accept的值放到响应头部返回给客户端,否则会连接失败。

所以建立连接的关键就是要监听upgrade事件,然后根据Sec-WebSocket-Key生成对应Sec-WebSocket-Accept的key值,然后返回给客户端。

const crypto = require('crypto');

const MAGIC_STRING = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; // 固定的字符串

function hashWebSocketKey (key) {

var sha1 = crypto.createHash('sha1'); // 拿到sha1算法

sha1.update(key + MAGIC_STRING, 'ascii');

return sha1.digest('base64');

};

class WebSocket extends EventEmitter {

constructor(options) {

this.server.on("upgrade", (req, socket, upgradeHead) => {

this.socket = socket;

// 处理协议升级请求

var resKey = hashWebSocketKey(req.headers['sec-websocket-key']); // 对浏览器生成的key进行加密

// 构造响应头

var resHeaders = [

'HTTP/1.1 101 Switching Protocols',

'Upgrade: websocket',

'Connection: Upgrade',

'Sec-WebSocket-Accept: ' + resKey

]

.concat('', '')

.join('\r\n');

socket.write(resHeaders); // 返回响应头部

});

}

}

在upgrade事件回调中,我们可以拿到客户端的socket,然后通过客户端socket直接把响应头写入即可。

③ 接收客户端发过来的数据

经过上面,客户端已经可以和服务器端连接成功了,接下来客户端会发送数据到服务器端,服务器可以通过连接时的socket监听客户端发送过来的数据,同样是在监听到upgrade事件的时候,拿到客户端socket进行监听data事件即可,如:

class WebSocket extends EventEmitter {

constructor(options) {

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值