共计 9158 个字符,预计需要花费 23 分钟才能阅读完成。
最近我的项目要用到 websocket 技术了,重温一下当初学习写的 DEMO
1. 为了运行 h5 页面,须要利用 NODE 开启一个 web 服务器,端口号 8888,取名为 web.js , 运行 node web.js
var fs = require(‘fs’);
var events = require(‘events’);
var http = require(‘http’);
var url = require(‘url’);
// 创立服务器
http.createServer(function (request, response) {
// 解析申请,包含文件名
var pathname = url.parse(request.url).pathname;
// 输入申请的文件名
console.log(“Request for ” + pathname + ” received.”, pathname.substr(1));
// 从文件系统中读取申请的文件内容
fs.readFile(pathname.substr(1), function (err, data) {
if (err) {
console.log(err);
// HTTP 状态码: 404 : NOT FOUND
// Content Type: text/plain
response.writeHead(404, { ‘Content-Type’: ‘text/html;charset=utf-8’});
response.write(‘ 页面不存在!’);
} else {
// HTTP 状态码: 200 : OK
// Content Type: text/plain
response.writeHead(200, { ‘Content-Type’: ‘text/html;charset=utf-8’});
// 响应文件内容
response.write(data.toString());
}
// 发送响应数据
response.end();
});
}).listen(8888);
// 控制台会输入以下信息
console.log(‘Server running at http://127.0.0.1:8888/’);
- 而后在 web.js 同文件夹下创立 h5 页面取名 index.html,利用下面创立的 web 服务关上页面,http://127.0.0.1:8888/index.html,为了测试,能够关上两个不同的浏览器,关上同一个地址,但当初还不能通信,须要第三部创立 scoket 服务器,创立实现,点击两个浏览器的运行按钮,而后输出内容发送,另一个页面也实时获取到了你发的音讯
<!DOCTYPE HTML>
<html>
<head>
<meta charset=”utf-8″>
<title>webSocket 测试 </title>
</head>
<body>
<div id=”sse”>
<a href=”javascript:WebSocketTest()”> 运行 ( 连贯服务,等于账号登录) WebSocket
</div>
<input type=”text” id=”inputBox” />
<button id=”submitFunc”> 发送 </button><button onclick=”closeWs()”> 敞开 </button>
<div id=”content”></div>
<script type=”text/javascript”>
var ws = null;
var inputBox = document.getElementById(‘inputBox’);
var submitFunc = document.getElementById(‘submitFunc’);
var content = document.getElementById(‘content’);
function WebSocketTest() {
if (“WebSocket” in window) {
alert(“ 您的浏览器反对 WebSocket!”);
// 关上一个 web socket
ws = new WebSocket(“ws://localhost:8124”);
ws.onopen = function () {
// Web Socket 已连贯上,应用 send() 办法发送数据
ws.send(“ 笑傲江湖 ”);
alert(“ 数据发送中 …”);
submitFunc.onclick = function () {
ws.send(inputBox.value);
alert(“ 数据发送中 …”);
}
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
console.log(‘ 承受的数据 ’, received_msg);
var html = content.innerHTML;
html += received_msg;
content.innerHTML = ‘<p>’ + html + ‘</p>’;
//alert(“ 数据已接管 …”);
};
ws.onclose = function () {
// 敞开 websocket
alert(“ 连贯已敞开 …”);
};
} else {
// 浏览器不反对 WebSocket
alert(“ 您的浏览器不反对 WebSocket!”);
}
}
// 获取信息发送
function closeWs() {
if (ws != null) {
ws.close();
} else {
alert(‘ 你还没开启 ’);
}
}
</script>
</body>
</html>
3. 利用 net 模块创立 socket 服务,在同文件下下创立 server.js , 代码如下,运行 node server 端口号:8124 (端口号随便,只是 index.html 里的地址端口统一就能够)
const crypto = require(‘crypto’);
const net = require(‘net’);
var clientList = [];
var this_client = null;
var options = {
allowHalfOpen: false,
pauseOnConnect: false
}
let tcpServer = net.createServer(options);
// 计算 websocket 校验
function getSecWebSocketAccept(key) {
return crypto.createHash(‘sha1’)
.update(key + ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’)
.digest(‘base64’);
}
// 掩码操作
function unmask(buffer, mask) {
const length = buffer.length;
for (var i = 0; i < length; i++) {
buffer[i] ^= mask[i & 3];
}
console.log(‘ 解码后的数据 ’, buffer.toString(‘utf8’));
}
tcpServer.on(‘listening’, () => {
console.log(‘ 开始监听 ’);
});
tcpServer.on(‘connection’, (socket) => {
console.log(‘ 连贯已建设 ’ + ‘n’, socket.name);
// 启动心跳机制
/*var isOnline = !0;
var keepAliveTimer = socket.timer = setInterval(()=>{
if(!isOnline){
this_client = socket;
quit(socket.nick);
return;
}
if(socket.writable){
isOnline = !1;
socket.write(‘::’);
}else{
this_client = socket;
quit(socket.nick);
}
},3000);
if(socket._handle==null){
isOnline = !0;
return;
}*/
tcpServer.getConnections((err, count) => {
if (err) {
console.warn(err);
} else {
console.log( 以后有 ${count} 个连贯
);
}
});
socket.on(‘data’, (data) => {
this_client = socket;
if (clientList.indexOf(socket) > -1) {
let buffer = data;
let fin = (buffer[0] & 0b10000000) === 0b10000000;
// 取第一个字节的后四位,失去的一个是十进制数
let opcode = buffer[0] & 0b00001111;
// 取第二个字节的第一位是否是 1,判断是否掩码操作
let mask = buffer[1] & 0b100000000 === 0b100000000;
// 载荷数据的长度
let payloadLength = buffer[1] & 0b01111111;
// 掩码键,占 4 个字节
let maskingKey = buffer.slice(2, 6);
// 载荷数据,就是客户端发送的理论数据
let payloadData = buffer.slice(6);
console.log(‘ 客户端发送的理论数据 ’, payloadData.toString(‘utf8’));
// 对数据进行解码解决
unmask(payloadData, maskingKey);
// 向客户端响应数据
let send = Buffer.alloc(2 + payloadData.length);
//0b10000000 示意发送完结
send[0] = opcode | 0b10000000;
// 载荷数据的长度
send[1] = payloadData.length;
payloadData.copy(send, 2);
var now = new Date();
broadcast(send, socket);
/*const buf2 = Buffer.from(‘ 后盾传过来的工夫:’+now, ‘utf8’);
const buf=Buffer.alloc(2+buf2.length);
buf[0]=opcode | 0b10000000;
buf[1]=buf2.length;
buf2.copy(buf,2);*/
/*for(var i=0;i<clientList.length;i++){
let client=clientList[i];
if(client._handle==null){
clientList.splice(clientList.indexOf(client), 1);
i–;
}
}*/
/* if(send==’end’){
this.close();
}
for(var i=0;i<clientList.length;i++){
console.log(‘ 残余个数:’,clientList.length);
let client=clientList[i];
//console.log(‘ 返回数据中 —‘,client);
console.log(send);
client.write(send);
}*/
} else {
data = data.toString();
if (data.match(/Upgrade: websocket/)) {
let rows = data.split(‘rn’);
// 去掉第一行的申请行
// 去掉申请头的尾部两个空行
rows = rows.slice(1, -2);
let headers = {};
rows.forEach(function (value) {
let [k, v] = value.split(‘: ‘);
headers[k] = v;
});
// 判断 websocket 的版本
if (headers[‘Sec-WebSocket-Version’] == 13) {
let secWebSocketKey = headers[‘Sec-WebSocket-Key’];
// 计算 websocket 校验
let secWebSocketAccept = getSecWebSocketAccept(secWebSocketKey);
// 服务端响应的内容
let res =
‘HTTP/1.1 101 Switching Protocols rn’ +
‘Upgrade: websocket rn’ +
‘Sec-WebSocket-Accept: ‘ + secWebSocketAccept + ‘rn’ +
‘Connection: Upgrade rn’ +
‘rn’;
console.log(‘ 发送给客户端协定 ’, res);
// 给客户端发送响应内容
socket.write(res);
//socket.name = socket.remoteAddress + ‘:’ + socket.remotePort;
clientList.push(socket);
}
}
}
});
socket.on(‘disconnect’, function () {// 这里监听 disconnect,就能够晓得谁断开连接了
console.log(‘disconnect: ‘ + socket.id);
});
socket.on(‘error’, (err) => {
console.warn(‘ 谬误 ’, err);
socket.destroy();
});
/*socket.on(‘close’, function(data) {
console.log(‘ 客户端敞开了!’,data);
//clientList.splice(clientList.indexOf(socket), 1);
// socket.remoteAddress + ‘ ‘ + socket.remotePort);
});*/
// 完结
socket.on(‘end’, () => {
console.log(” + socket + ‘-quit’); // 如果某个客户端断开连接,node 控制台就会打印进去
//this.destroy();
clientList.splice(clientList.indexOf(socket), 1);
});
function broadcast(message, client) {
var cleanup = []; // 断开了的客户端们
for (var i = 0; i < clientList.length; i++) {
// 查看 socket 的可写状态
if (clientList[i].writable) {
// 把数据发送给其余客户端
if (message.toString().length > 2) {
clientList[i].write(message);
}
} else {
cleanup.push(clientList[i]);
clientList[i].destroy();
}
}
/ 删除掉服务器的客户端数组中,已断开的客户端 /
for (var i = 0; i < cleanup.length; i++) {
clientList.splice(clientList.indexOf(cleanup[i]), 1);
}
}
});
tcpServer.on(‘close’, () => {
console.log(‘close’);
});
tcpServer.listen(8124, () => {
console.log(“8124 服务器 ok”);
});