WebSocket入门

2018-10-01

WebSocket入门

[TOC]

1.概念

ws协议,基于TCP连接,随着H5的发展而诞生

允许浏览器和服务器建立持久连接

服务器可以主动给客户端发送信息,双向互通

2.基础组成

基础的组件由/open/close/send/message/error组成并延伸

当然,实际使用时需要有服务器来作为通信支撑,此处以nodejs为例

服务器

首先需要安装nodjs环境

然后使用脚本拉取github的开源服务器model

npm install nodejs-websocket

使用一下方式建立服务器脚本即可(需要与model同层,配置才生效)

wsServer.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var ws = require("nodejs-websocket")
var port=8000; //监听端口
// Scream server example: "hi" -> "HI!!!"
//服务连接事件,连接后才会有内部的事件执行
var server = ws.createServer(function (conn) {
console.log("New connection")
//消息的收发中转
conn.on("text", function (str) {
console.log("Received "+str)
conn.sendText(str.toUpperCase()+"!!!")
})
//关闭连接时的事件
conn.on("close", function (code, reason) {
console.log("Connection closed")
})
//错误时的事件,如果没有该函数,服务器会因消息错误而宕机,相当于java中的异常捕获
conn.on("error",function(err){
console.log(err)
})
}).listen(port)

启动方式:node wsServer.js

客户端

以js为例(java/nodejs等语法稍微有区别,但原理相同)

1
2
//首先需要创建ws协议,才能使用
var websocket=new WebSocket("ws://echo.websocket.org/");

API

onopen/onclose/onmessage/onerror等,如下

2-1.open

建立连接,比如发送按钮事件,可以嵌套在open中,如果websocket没有连接,name发送按钮本身也没有意义

1
2
3
websocket.onopen=function(){
consolet.log("websocket open")
}

2-2.close

关闭连接

1
2
3
websocket.onclose=function(){
consolet.log("websocket close")
}

2-3.send

发送消息

1
websocket.send("这是发送的消息")

2-4.message

接收消息

1
2
3
websocket.onmessage=function(e){
consolet.log(e.data)
}

对于message来说,e.data只是普通的字符串消息接收

但是因为实际的需求,如:用户离开/进入/统计等等

需要将消息分离,那么我们可以用对象的方式来操作信息

2-5.error

错误情况

1
2
3
websocket.onerror=function(err){
consolet.log(err)
}

3.格式化消息改造

通过以上的基础组件,我们可以实现简单的webSocket通信,但是稍微复杂一些的信息格式却难以完成,比如用户离开/进入/统计等

我们可以对消息进行JSON格式化来完成这样的基础实现

3-1.服务器改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var ws = require("nodejs-websocket")
var port = 8000;
var clientCount = 0;

var server = ws.createServer(function (conn) {
console.log("New connection");

clientCount++; //临时区分用户使用
conn.nickname = '用户' + clientCount;

var mes = {}; //封装消息
mes.type = "enter"; //消息类型
mes.data = conn.nickname + "进入房间"; //消息内容
broadcast(JSON.stringify(mes)); //封装消息发送函数

conn.on("text", function (str) {
var mes = {};
mes.type = "message";
mes.data = conn.nickname + "说:" + str;
broadcast(JSON.stringify(mes))
});

conn.on("close", function (code, reason) {
var mes = {};
mes.type = "leave";
mes.data = conn.nickname + "离开房间";
broadcast(JSON.stringify(mes));
});

conn.on("error", function (err) {
console.log(err)
})

}).listen(port);

console.log("WebSocket Start Success:" + port);

function broadcast(msg) {
server.connections.forEach(function (connection) {
connection.sendText(msg);
})
}

如上,将消息封装为一个mes对象,通过定义其属性来完成分类消息的发送

type="enter" 表示进入

type="leave"表示离开

data表示封装的消息

发送时将消息格式化为JSON字符串发送到前段即可

3-2.客户端改造

通过类型的判断,来实现想要的显示方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Websocket</title>
</head>
<body>
<h1>WebSocket</h1>
<input type="text" id="sendText" />
<button id="sendBtn">发送</button>
<script>
var webSocket=new WebSocket("ws://localhost:8000/");
var sendBtn = document.getElementById("sendBtn");
function showMessage(data,type){
var div= document.createElement(div);
div.innerHTML="<br/>"+data;
if (type=="enter"){
div.style.color="blue";
}
if (type=="leave"){
div.style.color="red";
}
document.body.appendChild(div);
}
webSocket.onopen=function () {
sendBtn.onclick=function () {
var sendText = document.getElementById("sendText").value;
if (sendText){
webSocket.send(sendText);
}
}
};
webSocket.onclose=function () {
};
webSocket.onmessage=function (e) {
var mes=JSON.parse(e.data);
showMessage(mes.data,mes.type);
}
</script>
</body>
</html>

以上是原生的WebSocket,如果需要更为丰富的通信,可以使用Socket.IO框架来实现

4.Socket.IO框架

支持包括java/python/c++等多语言框架(底部连接)

NodeJs案例

通过以下指令安装socket.io模块

(需要nodejs环境和c编译器环境)

4-1.服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var server = require('http').createServer();
var io = require('socket.io')(server);

io.on('connection', function (socket) { //socket 与客户端的连接
/**
* emit发送指定格式消息,on接收指定格式消息
* 当emit为io.emit时,表示广播形式
* 自定义KV,可以发送对象,简化了消息格式化的过程
* 自定义on的K,简化了自定义消息分类的过程
*/
socket.on('Dony15',function (data) {
console.log(data)
socket.emit('Dony15',data);
})
});
/**
* 监听3000端口,此处演示为监听时可执行函数功能,也可不执行
* server.listen(3000)
*/
server.listen(3000, function () {
console.log('listen on *:3000');
});
注意emit

当其为io中的函数socket.emit时,代表的是发送

当io.emit时,代表的是广播

4-2.客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocketIO</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
</head>
<body>
<script>
var socket=io('ws://localhost:3000');
socket.on('Dony15',function (data) {
console.log(data);
})
socket.emit('Dony15',{name:'长贵',age:30});
</script>
</body>
</html>

4-3.Socket.IO服务端改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var server = require('http').createServer(); //创建http服务
var io=require('socket.io')(server); //将服务包装为io的形式

var PORT = 3000;
var clientCount = 0;

io.on('connection',function (socket) { //通过io建立连接
clientCount++;
socket.nickname = '用户' + clientCount;
io.emit('enter',socket.nickname+'进入'); //广播

socket.on('message',function (str) { //以message类型发消息
io.emit('message',socket.nickname+'说:'+str)
});

socket.on('disconnect',function () { //特殊:disconnect类型表示断开
io.emit('leave',socket.nickname+'离开');
});
});
server.listen(PORT);

4-4.Socket.IO客户端改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocketIO</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>//引入在线Socket.IO.js,开发建立离线使用
</head>
<body>
<h1>WebSocket</h1>
<input type="text" id="sendText"/>
<button id="sendBtn">发送</button>
<script>
var socket = io("ws://localhost:3000/");
var sendBtn = document.getElementById("sendBtn");

//判断输出样式
function showMessage(data, type) {
var div = document.createElement(div);
div.innerHTML = "<br/>" + data;
if (type == "enter") {
div.style.color = "blue";
}
if (type == "leave") {
div.style.color = "red";
}
document.body.appendChild(div);
}
//点击发送消息
sendBtn.onclick = function () {
var sendText = document.getElementById("sendText").value;
if (sendText) {
socket.emit('message', sendText);
}
};

//Socket.IO监听消息
socket.on('enter',function (data) { //进入房间
showMessage(data,'enter');
});
socket.on('leave',function (data) { //离开房间
showMessage(data,'leave');
});
socket.on('message',function (data) { //发送消息
showMessage(data,'message');
})
</script>
</body>
</html>

4-5.示例截图

5.传送门

慕课网WebSocket入门教程

https://www.imooc.com/learn/861

Socket.IO官网文档

https://socket.io/get-started/chat/

多语言GitHub服务器示例社区维护