socket io简介
简而言之,socket.io就是基于websocket封装的一个库,主要特点是能够进行实时的双向通讯,主要应用场景有实时的聊天,数据实时分析,数据传输,文件协同合作。
当然作为聊天室
对于这种实时通讯手段,比较运用广泛的就是来创建聊天室,通过利用boardcast功能,当一个用户输入信息,并且输出的时候,就会向其他用户广播这个消息,达到实时通讯的目的。于此同时,可以利用socket.io的命名空间(namespaces)功能,来创建独立的聊天室的功能。将每个聊天区域划分开来。
用作前端和后端的交互手段
通常而言,一般前端和后端的交互手段是通过发送http或者https请求来达到的,可以理解为前后端利用AJAX的方式来对信息进行请求,这种请求的特点是单向的,客户端请求了之后,服务端才可以返回数据过来
传统http或者https请求.png
这种方式,服务器永远都是被动的,如果客户端没有请求传递过来的话,服务器是不可能主动往客户端发送消息的。在一些情况下,比如商场的秒杀活动,更需要客户端和服务端的实时通讯。
在这种情况下使用socket.io来作为客户端和服务端之间的通讯的话,会更灵巧得多,这种情况下,服务端和客户端的通信是双向通信了,而非单向通信,服务器在准备好的时候可以直接向客户端发送相应消息,而不需要等待客户端来问询。
socket.io连接.png
相比ajax,socket.io的信息传输速度更快,因为socket.io一直保持着连接通道处于打开状态,这意味着没有服务端和客户端的握手。
对于ajax,需要使用promise/response,需要有响应时间,反应上比较迟缓,而对于Socket.io,只需要事件的发送,即EventEmitter和事件的接收,也就是事件的监听,并且相比于ajax,发送者和接收者不需要知道彼此的存在,不需要很强的耦合性。
更重要的是,由于socket.io在客户端和服务端之间维持一条持久化的连接,意味着在多并发连接的情况下能够充分利用服务端的资源。
一般情况下,当利用socket.io时候,分为以下两步,首先是先连接到http server上去加载page的html文件,之后再通过websocket打开一个实时的连接通道。
Socket.io不仅仅局限于聊天室构建这方面,在某些方面比ajax更有优势。
Socket.io登陆验证方面的应用
首先,对于socket.io在登陆验证这方面,如果用户通过了应用程序的验证,并不代表也会通过socket流的验证,因为这两个是完全不同的频道,比如下图所示
image.png
目前而言,有两种方法来解决这种问题,第一种是基于cookie的传统解决方案,以及基于token的解决方案,如下图所示
Cookies.png
Tokens.png
对于利用cookies来做验证登陆目前存在的问题就是,耦合性太高,需要将验证机制和socket服务端的验证绑定在一起,在一些情况下这种方式也许行得通,但是在其他意外情况下,在不了解内部情况下,非常难获得session cookie的访问权限。
目前就针对Token验证方法。
首先针对用户名和密码进行发送给服务端,利用EventEmitter,密码肯定经过加密之后再进行发送,在服务端验证成功之后,生成token之后,再返回给客户端,下次客户端再次发起请求时候,就附带上这个token当作验证信息。但是第一次连接时候,还是通过http请求来发送相应信息,并且通过http响应来返回相关token,之后的连接建立才是真正通过socket.io来建立通信通道。
但是这种方式还是存在其局限性,毕竟是将token附带在url上发送出去的,还有一种解决方案是在连接建立的时候,但是还没emit以及监听任何数据时候,强制进行token验证,如果验证成功,socket.io通讯通道建立,否则,通讯通道关闭
实时数据分析(Real-Time analytics)
可以利用socket.io通道传输数据的实时性,可以用来进行实时数据分析。比如统计一个网站目前的在线人数,不可能通过去经过数据库查找,然后再将在线人数返回过来。由于在线人数变动非常频繁,需要立马得出准确的数据,在页面上表现出来。可以换一种思路,每一个独立的用户都相当于一个计数器,一个页面作为统计作用,如下图
image.png
每一个登陆的时候,emit一个事件,Real-Time statics则通过监听这些事件,来统计数据,然后再通过一个统计的页面来监听socket.io server里面的事件,获取数据。
<<<华丽的分割线>>>
但是有一个缺点就是,其他跨域都可以连接到我们的服务器上,来向我们的服务器推送消息,或者监听服务器推送的消息。目前的解决方法是socket.io上做授权。具体操作方法有两种,第一种是全局授权,第二种是通过socket.io的命名空间来进行授权。再以上两种方法中,均是通过握手来交换数据,handshakeData包含着头文件,IP地址,xdomin等信息,服务器根据这些信息来判断是否允许用户进行连接。
如下所示,可以利用中间件来对要连接的用户进行授权
const express = require('express');
const app = new express();
const http = require('http').Server(app)
const io = require('socket.io')(http);
io.use((socket, next)=>{
let handshake = socket.handshake.xdomain;
console.log(handshake)
if(handshake){
next(new Error('Authentication error'))
};
next();
});
其中,这只是一个思想,通过中间件的形式,来检查handshake数据中的xdomain,如果为跨域,则传递一个Error的对象来终止连接。
对于socket.io的中间件,和Express中间件有一些区别,socket.io的中间件接受socket.io的握手协议的数据当作参数,但是由于大多数握手协议的数据和request的数据对象很相似,因此也可以非常简单的将Express的中间件运用到socket.io上。
实时协作(Real-Time Collaboration)
实时协作要求实时通信,比如多人在线游戏,基本的要求就是实时,而socket.io能够很好的满足这点,比如地图相关信息,一般的通讯思路如下
image.png
用户1号当每开始移动相应距离,就会发送一个事件,此时,socket.io服务端就会监听这个事件,当监听到事件之后,就会将更新后的数据发送给其他用户,其他用户就能实时的显示玩家1号在地图上的具体位置。
这个不仅仅局限于游戏,熟悉的打车软件也可以充分利用这个具体应用场景。
用作消息推送
通过socket.io建立的实时通讯通道,可以用来建立消息推送机制,此时,可以利用socket.io提供的命名空间(namespace)来区分Clinet 1和Clinet 2。就是利用io的of方法,比如创建一个命名空间
//创建名为client-1的命名空间
var client1 = io.of('/client-1');
client1.on('connect', function(){
console.log('connect')
})
此时就只会连接client1时候才会打印出connect的信息。很好的将client1和client2区分开来。比如此时在大三方页面上,即时是通过ftp协议访问的,可以收到消息,在第三方页面的绑定方式为
//仅仅针对本地3000端口做举例
io.on('http://localhost:3000/client-1')
网友评论