WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
node.js 用了socket.io
库,原生websocket较为繁琐。
初始化项目
"dependencies": {
"nodemon": "^2.0.2",
"socket.io": "^2.3.0"
}
app.js
const http = require('http')
const io = require('socket.io')
let httpServer = http.createServer((req, res) => {
})
httpServer.listen(8080)
let wsServer = io.listen(httpServer);
let reflect = {}; // name :sid
let socketlist = {}; // sid :socket
let userList = []
wsServer.on('connection', socket => { // 此处socket 是新建socket的实例 ,每个用户都是独一无二的
// 在此也可以跟数据库关联(根据前端数据取关联信息)
// console.log(socket.id + "已经连接完成") // socket.id 是 实例自带的,我一开始以为是前端传递的数据对象,注意一下哦
socket.on('addUser', username => { // 真实环境可以传达一个token,数据库操作
reflect[username] = socket.id;
socketlist[socket.id] = socket;
socket.nickname = username;
userList.push(username)
socket.emit('numbers', userList) //已解决,见文章后面
})
socket.emit('numbers', userList);
socket.on('msg', obj => { // obj 接受前端 emit('msg') message
userList.forEach(s => {
if (s !== obj.nickname) { // 过滤掉自己发送的信息
socketlist[reflect[s]].emit('msg', obj) // 保证是当前非自己当前的soket实例分发
}
})
})
socket.on('disconnect', () => { // 离开,断开连接要删掉
console.log('user ' + socket.id + ' disconnected');
if (reflect.hasOwnProperty(socket.nickname)) {
delete reflect[socket.nickname];
delete socketlist[socket.id];
userList[socket.id] && remove(userList[socket.id]);
socket.emit('numbers', userList);
console.log(socket.id + '删除数据成功')
}
})
})
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test-websocket</title>
<script src="http://localhost:8080/socket.io/socket.io.js" charset="utf-8"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrap {
width: 1200px;
margin-left: 20px;
}
ul,
li {
list-style: none;
}
.wrap {
margin-top: 80px;
}
.wrap-content {
display: flex;
justify-content: space-between;
}
#nickname {
text-align: center;
line-height: 2;
background-color: green;
color: white;
}
#ul1 {
width: 800px;
height: 400px;
border: 1px solid green;
overflow: auto;
}
#ul1 li.me {
color: green;
text-align: right;
}
#ul2 {
width: 400px;
height: 400px;
border: 1px solid green;
overflow: auto;
}
textarea {
width: 100%;
margin-top: 40px;
}
</style>
</head>
<body>
<div class="wrap">
输入用户名:<input type="text" width="400" id="username">
<input type="button" value="登入" id="login">
<div class="wrap-content">
<ul id="ul1">
</ul>
<ul id="ul2"> <--群聊成员-->
</ul>
</div>
<textarea name="" cols="30" rows="10" id="text1"></textarea>
<input type="button" value="发送" id="btn1">
</div>
<script>
let socket = io.connect('ws://localhost:8080');
let oTxt = document.getElementById('text1');
let oBtn = document.getElementById('btn1');
let oUl = document.getElementById('ul1');
let oUl2 = document.getElementById('ul2');
let ologin = document.getElementById('login');
let oUser = document.getElementById('username');
socket.on('connect', function () {
console.log('已连接');
})
socket.on('disconnect', function () { // 服务端失效,还是会发送消息成功,监听状态,便于提示用户
console.log('已断开');
})
socket.on('numbers', (data) => {
if (data.length < 1) {
return;
}
var str = "";
for (var i = 0; i < data.length; i++) {
str += "<li>" + data[i] + "</li>"
}
console.log(str)
oUl2.innerHTML = str;
})
socket.on('msg', obj => {
let oLi = document.createElement('li'); // 接受服务端信息(服务端已经过滤掉自己的信息了)
let oDiv = document.createElement('div');
oDiv.innerHTML = obj.mytext;
oLi.innerHTML = obj.nickname;
oUl.appendChild(oLi);
oLi.appendChild(oDiv)
})
ologin.onclick = function () {
socket.emit('addUser', oUser.value);
}
let message = {
mytext: "",
nickname: "",
}; // 发送给服务器的信息
oBtn.onclick = function () {
message.mytext = oTxt.value;
message.nickname = oUser.value;
socket.emit('msg', message);
let oLi = document.createElement('li'); // 自己发送的信息单独处理(样式)
oLi.innerHTML = oTxt.value;
oLi.classList = 'me';
oUl.appendChild(oLi);
oTxt.value = '';
}
</script>
</body>
</html>
测试
问题已解决
socket.on('addUser', username => {
reflect[username] = socket.id;
socketlist[socket.id] = socket;
socket.nickname = username;
userList.push(username);
for( var key in socketlist ){
socketlist[key].emit('numbers', userList)
}
})