server.js
const http = require('http');
const crypto = require('crypto');
const server = http.createServer(function (req,res) {
res.writeHead(200,{'Content-type':'text/plain'});
res.end('hello world');
});
server.listen(80);
server.on('upgrade',function (req,socket,upgradeHead) {
const head = new Buffer(upgradeHead.length);
upgradeHead.copy(head);
let key = req.headers['sec-websocket-key'];
let shasum = crypto.createHash('sha1');
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; //协议中规定的校验用GUID,这是算法中要用到的固定字符串
key = shasum.update(`${key}${GUID}`).digest('base64');
let headers = [
'HTTP/1.1 101 Web Socket Protocol Handshake',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-Websocket-Accept: '+key,
];
socket.setNoDelay(true);
socket.write(headers.concat('','').join('\r\n'));
socket.on('data',(e)=>{
//接收数据
console.log(decodeDataFrame(e));
});
})
//数据帧的解码
function decodeDataFrame(e){
var i=0,j,s,frame={
//解析前两个字节的基本数据
FIN:e[i]>>7,Opcode:e[i++]&15,Mask:e[i]>>7,
PayloadLength:e[i++]&0x7F
};
//处理特殊长度126和127
if(frame.PayloadLength==126)
frame.length=(e[i++]<<8)+e[i++];
if(frame.PayloadLength==127)
i+=4, //长度一般用四字节的整型,前四个字节通常为长整形留空的
frame.length=(e[i++]<<24)+(e[i++]<<16)+(e[i++]<<8)+e[i++];
//判断是否使用掩码
if(frame.Mask){
//获取掩码实体
frame.MaskingKey=[e[i++],e[i++],e[i++],e[i++]];
//对数据和掩码做异或运算
for(j=0,s=[];j<frame.PayloadLength;j++)
s.push(e[i+j]^frame.MaskingKey[j%4]);
}else s=e.slice(i,frame.PayloadLength); //否则直接使用数据
//数组转换成缓冲区来使用
s=new Buffer(s);
//如果有必要则把缓冲区转换成字符串来使用
if(frame.Opcode==1)s=s.toString();
//设置上数据部分
frame.PayloadData=s;
//返回数据帧
return frame;
}
//数据帧的编码
function encodeDataFrame(e){
var s=[],o=new Buffer(e.PayloadData),l=o.length;
//输入第一个字节
s.push((e.FIN<<7)+e.Opcode);
//输入第二个字节,判断它的长度并放入相应的后续长度消息
//永远不使用掩码
if(l<126) s.push(l);
else if(l<0x10000) s.push(126,(l&0xFF00)>>2,l&0xFF);
else s.push(
127, 0,0,0,0, //8字节数据,前4字节一般没用留空
(l&0xFF000000)>>6,(l&0xFF0000)>>4,(l&0xFF00)>>2,l&0xFF
);
//返回头部分和数据部分的合并缓冲区
return Buffer.concat([new Buffer(s),o]);
}
html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript">
// 打开一个 web socket
var ws = new WebSocket("ws://localhost");
ws.onopen = function()
{
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send('胜多负少');
console.log("数据发送中...");
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
console.log("数据已接收...");
};
ws.onclose = function()
{
// 关闭 websocket
console.log("连接已关闭...");
};
</script>
</head>
<body>
</body>
</html>