# Socket 通讯
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。所以建立网络通信连接至少要一对socket。
socket 是做长连接的,连接通道建立之后,消耗较少的资源就可以实现客户端与服务器的数据通信了,而ajax实现长连接,消耗的资源太大。
ajax的过程只能是客户端主动向服务器发数据;而socket即可以客户端主动向服务器发数据,也可以服务器主动向客户端发数据。
# net 模块
socket 的核心对象是 net
var net = require("net");
net.createServer( function(){} );
1
2
2
我们使用net模块操作socket有些繁琐,所以我们会选择网络上别人写好的socket框架来完成我们的项目,这些框架的底层代码其实还是net模块,只不过做了一层封装,提供了一些功能,方便我们的使用。
这类的socket框架有很多,比如 websocket、socket.io 等等,学会一个即可。
# WebSocket
# 服务器
// cnpm i ws -S
// 获取 websocket 的 server 对象
var WebSocketServer = require('ws').Server;
// 创建 websocket 服务,监听了8181端口
var wss = new WebSocketServer({port:8181});
// 用一个变量来保存所有的socket端(即把所有的访客记录下来)
var clients = [];
// 每次有人连接到服务器时,都会自动触发connection事件
wss.on('connection', ws=>{
// ws 就是这个访问者的socket对象
// 如果想获取该访问者的IP,使用 ws._socket.remoteAddress
// 把每一个连接到服务器的客户端,追加保存在数组中
clients.push(ws);
// 客户端向服务器发数据时,服务器的message事件会自动触发,msg指客户端传过来的数据。
ws.on('message', msg=>{ // 服务器得到客户端发过来的数据时
// 比如聊天室中有10个人,这10个人的socket都保存到数组 clients 中
// 其中1个人说话了,服务器的message事件就会被触发
// 然后循环clients,把这个人说的内容发送给每一个人
for( var c of clients ){ // 通过循环,广播给每一个连接的客户端
if( c.readyState==1 ){ // 如果连接状态是正常的
c.send( msg ); // 则向客户端发送数据(只能发送字符串)
}
}
});
});
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
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
# 客户端
<input type="text" id="text1" />
<script>
// 原生js中提供了WebSocket方法,可以直接连接到服务器。
// http对应的协议是ws,如果做数据加密,https则对应wss。
var ws = new WebSocket("ws://localhost:8181");
// 建立通道后,客户端使用send可以向服务器端发数据,服务器端也可以使用send向客户端发数据。
// 客户端向服务器端发送数据
text1.onblur = function() {
ws.send( this.value ); // 只能发送字符串
}
// 客户端接收服务器端传回来的数据
ws.onmessage = function(e){
console.log( e.data );
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 事件
// 当websocket创建成功时,即会触发onopen事件
ws.onopen = function() {};
// 当客户端收到服务端发来的消息时,会触发onmessage事件,参数evt.data中包含server传输过来的数据
ws.onmessage = function(evt) { console.log(evt.data) };
// 当客户端收到服务端发送的关闭连接的请求时,触发onclose事件
ws.onclose = function(evt) {};
// 如果出现连接,处理,接收,发送数据失败的时候就会触发onerror事件
ws.onerror = function(evt) {};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# ws.readyState 状态
状态码 | 状态 | 描述 |
---|---|---|
0 | CONNECTING | 连接尚未建立 |
1 | OPEN | WebSocket的链接已经建立 |
2 | CLOSING | 连接正在关闭 |
3 | CLOSED | 连接已经关闭或不可用 |
# 断开后重新连接的策略
如果两个socket断开了,前端会自动触发 onclose 事件,如果想重新连接,那么在这个事件中,重新发起socket连接即可。
# 心跳机制
两个socket之间,如果长时间没有数据交互,服务器及客户端都有安全策略,会自动断开连接,为了保证连接,所以我们可以每隔一定的时间,发送一些数据给对方,这个数据唯一的作用就是告诉对方“我还活着,别把我断了”,这就是心跳机制。前后端都可以实现,用setTimeout每隔一段时间,发数据即可。
# Socket.io
socket.io由两部分组成,分别是服务器端和客户端。
# 服务器端
下载该模块
npm install socket.io
1
编写 socket 服务
var socketio = require("socket.io"); // npm install socket.io
var io = socketio.listen(8080);
io.on("connection", socket=>{
var ip = socket.request.connection.remoteAddress.substr(7);
console.log(ip, " 有客户端连接到服务器了..");
// 监听来自客户端的数据
socket.on("a", data=>{
console.log(ip, " 说 ", data);
// 给自己广播
//socket.emit("b", data);
// 给所有的客户端广播
io.sockets.emit("b", data);
});
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 客户端
引入该文件
socket.io-1.4.5.js
http://socket.io/download/
https://cdnjs.com/libraries/socket.io
编写客户端代码:
<script src="socket.io-1.4.5.js"></script>
<div id="div1"></div>
<input id="input1" type="text" />
<script>
//建立长连接
var socket=io.connect('http://localhost:8080');
//接收由服务器传递给客户端的data
socket.on('b', function (data) {
div1.innerHTML=""+data.x.replace(/\n/,"<br>")+"<hr>";
});
//对按钮绑定事件
input1.onblur=function(){
var str=this.value;//获取按钮内容
//由客户端向服务器端发送数据(数据名叫做AAA,值为一个对象)
socket.emit('a', {
'str':str
});
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
← Node服务