如何让客户端和服务器端能够进行双向通信呢?以前我们可能会使用短轮询啊,长轮询,但这其实并不是真正意义上的双向通信,而是我们在不断的向服务器发送请求,那后来HTML5提供了一个新的API WebSocket,这也让我们的服务器端能够主动给客户端发送消息成为可能。
短轮询:
每隔一段时间比如 1s 钟 向服务器发送一次请求,问服务器是否有人给我们发送信息
弊端: 如果没有人发送消息,还是在不断的轮询,浪费用户流量
长轮询:
只是相对于短轮询,减少了请求次数
比如: 设置请求的超时时间为 5 分钟,那 5 分钟中内如果有消息发送给我们,
那就响应给我们,连接断掉,等我们处理完数据之后再重新发送请求
如果 5 分钟内还没有人发送消息给我们,那就请求超时,连接断掉,我再重新发
websocket:
跟服务器建立连接,打开了一个通信通道,除非客户端或者服务端主动关,否则连接不会关掉
有的浏览器可能不支持 websocket ,就使用 window.websocket 判断有没有 这个类,没有的话就使用 长轮询
那接下来我们使用 websocket 来实现一个简单的聊天室,这里我们使用 ws 插件,它对 websocket 进行了封装,我们使用更加方便
服务器端下载 ws
npm install ws
服务器端:
构建websocket通信服务器
const WebSocket = require('ws');
const server = new WebSocket.Server({
port: 8000
});
监听客户端的连接
server.on('connection', (socket)=>{
console.log('有人上线了');
......
})
监听客户端发送的信息
socket.on('message', (data)=>{
console.log(data);
......
// 告诉其他的客户端该客户端发了什么信息
})
客户端:
连接 websocket 服务器
var websocket = new WebSocket('ws://localhost:8000');
成功连接时
websocket .on('open', function open() {
console.log('connected');
});
断线时
websocket.onerror = ()=>{
console.log('断线了');
}
连接关闭时
websocket.onclose = ()=>{
console.log('下线了');
}
接收到消息时
websocket.onmessage = (ev)=>{
console.log('接收到了信息:', ev.data);
// 这个时候可以对接收到的消息做一定处理,比如展示到页面上等
}
效果如下
代码实现:
client.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>聊天室</title>
<style>
*{
margin: 0;
padding: 0;
}
html, body{
width: 100%;
height: 100%;
}
.panel{
width: 100%;
position: absolute;
top: 0;
left: 0;
bottom: 150px;
border-bottom: 2px solid #ddd;
padding: 20px;
box-sizing: border-box;
overflow: auto;
}
.handle{
width: 100%;
height: 150px;
position: absolute;
bottom: 0;
left: 0;
}
textarea{
width: 100%;
height: 100px;
outline: none;
}
button{
float: right;
height: 50px;
line-height: 50px;
padding: 0 20px;
}
.row{
clear: both;
max-width: 70%;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
}
.left{
float: left;
background: lemonchiffon;
}
.right{
float: right;
background: lavender;
}
</style>
</head>
<body>
<div class="panel">
<div class="row left">
<h3>张三:</h3>
<p>你好</p>
</div>
<div class="row right">
<h3>我:</h3>
<p>你好</p>
</div>
</div>
<div class="handle">
<textarea></textarea>
<button id="send">发送</button>
</div>
<script>
var websocket = new WebSocket('ws://localhost:8000');
websocket.onopen = ()=>{
console.log('上线了');
}
websocket.onerror = ()=>{
console.log('断线了');
}
websocket.onclose = ()=>{
console.log('下线了');
}
websocket.onmessage = (ev)=>{
console.log('接收到了信息:', ev.data);
// 页面布局
document.querySelector('.panel').innerHTML += `
<div class="row left">
<h3>别人:</h3>
<p>${ev.data}</p>
</div>
`;
}
// 发送的点击事件
document.querySelector('#send').onclick = ()=>{
// 获得用户输入
let value = document.querySelector('textarea').value;
if(!value){
alert('输入不能为空');
}
else{
// 发送给服务器
websocket.send(value);
// 页面布局
document.querySelector('.panel').innerHTML += `
<div class="row right">
<h3>我:</h3>
<p>${value}</p>
</div>
`;
// 情空输入框
document.querySelector('textarea').value = '';
}
}
</script>
</body>
</html>
server.js 服务器端的代码
// websocket
const WebSocket = require('ws');
// 构建websocket通信服务器
const server = new WebSocket.Server({
port: 8000
});
const arr = []; // 存放连接的客户端
// 监听客户端的连接
server.on('connection', (socket)=>{
console.log('有人上线了');
arr.push(socket);
socket.on('message', (data)=>{
//客户端发送的信息
console.log(data);
// 告诉其他的客户端该客户端发了什么信息
arr.forEach(item=>{
item !== socket && item.send(data);
})
})
})
see you ~