code
const net = require('net');
const {
dealwithResData,
dealwithReqData,
createPongFrame,
dealwithSocketHeader,
} = require('./utils');
const server = net.createServer((socket) => {
const onClose = () => {
console.log('close');
};
const onMsg = (frame) => {
const req = dealwithReqData(frame);
console.log(req, '??????');
const resText = dealwithResData('收到');
socket.write(resText);
};
let skip = false;
const hartbeat = () => {
setInterval(() => {
if (skip) {
skip = false;
}
const pongFrame = createPongFrame();
console.log('send');
socket.write(pongFrame);
socket.write(dealwithResData('auto send'));
}, 3000);
};
socket.once('data', (buffer) => {
const headers = buffer
.toString()
.split('\r\n')
.reduce((acc, current) => {
const [key, value] = current.split(': ');
acc[key] = value;
return acc;
}, {});
if (headers['Sec-WebSocket-Key']) {
socket.write(dealwithSocketHeader(headers));
socket.on('data', (frame) => {
const isFinalFrame = frame[0] & 0x80;
const opCode = frame[0] & 0x0f;
console.log(frame[0], frame[1]);
switch (opCode) {
case 0x0:
break;
case 0x1:
onMsg(frame);
break;
case 0x2:
break;
case 0x8:
onClose();
break;
case 0x9:
break;
case 0xa:
break;
}
});
}
});
socket.on('end', () => {
console.log('Client disconnected');
});
});
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
utils
const crypto = require('crypto');
function dealwithResData(text) {
const firstByte = 0x81;
const buffer = Buffer.from(text, 'utf8');
let payloadLength = buffer.length;
let secondByte = payloadLength;
let payloadLengthBytes = [];
if (payloadLength > 65535) {
secondByte = 127;
payloadLengthBytes.push((payloadLength >> 56) & 255);
payloadLengthBytes.push((payloadLength >> 48) & 255);
payloadLengthBytes.push((payloadLength >> 40) & 255);
payloadLengthBytes.push((payloadLength >> 32) & 255);
payloadLengthBytes.push((payloadLength >> 24) & 255);
payloadLengthBytes.push((payloadLength >> 16) & 255);
payloadLengthBytes.push((payloadLength >> 8) & 255);
payloadLengthBytes.push(payloadLength & 255);
} else if (payloadLength > 125) {
secondByte = 126;
payloadLengthBytes.push((payloadLength >> 8) & 255);
payloadLengthBytes.push(payloadLength & 255);
}
const frame = Buffer.concat([
Buffer.from([firstByte, secondByte]),
Buffer.from(payloadLengthBytes),
buffer,
]);
return frame;
}
const dealwithReqData = (frame) => {
const isMasked = frame[1] & 0x80;
let currentOffset = 2;
let mask;
if (isMasked) {
mask = frame.slice(currentOffset, currentOffset + 4);
currentOffset += 4;
}
const data = frame.slice(currentOffset);
if (isMasked) {
for (let i = 0; i < data.length; i++) {
data[i] ^= mask[i % 4];
}
}
const text = data.toString('utf8');
return text;
};
function createPongFrame() {
const pongFrame = Buffer.alloc(2);
pongFrame[0] = 0b10001010;
pongFrame[1] = 0;
return pongFrame;
}
const dealwithSocketHeader = (headers) => {
const SEC_WEBSOCKET_ACCEPT = crypto
.createHash('sha1')
.update(headers['Sec-WebSocket-Key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
.digest('base64');
return (
'HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
'Upgrade: websocket\r\n' +
'Connection: Upgrade\r\n' +
'Sec-WebSocket-Accept: ' +
SEC_WEBSOCKET_ACCEPT +
'\r\n' +
'\r\n'
);
};
module.exports = {
dealwithResData,
dealwithReqData,
createPongFrame,
dealwithSocketHeader,
};