IM聊天室(一):WebSocket

来源:互联网 发布:实变函数和实分析 知乎 编辑:程序博客网 时间:2024/06/06 08:37

1、什么是WebSocket?它和Socket有什么关系?

在网络中,两个程序(进程)需要全双工通信,即双方可以同时向对方发送消息,需要用到的就是Socket,它能够提供端对端通信。

具体的实现过程如下:

  • 客户端:创建一个Socket实例,并且提供服务端的IP和端口,如:192.168.1.1:8081

  • 服务端:创建另一个Socket并绑定本地端口进行监听,如:localhost:8081

  • 两者约定的端口要相同

  • 客户端对服务端进行请求连接,服务端接受后通知客户端,双方就建立了一个TCP连接

  • 至此,客户端和服务端之间可以进行双向通信,并且无客户端和服务端之分,均为端对端通信,但是主流的IM还是采用服务端转发的方式进行消息传送。

WebSocket借鉴了socket的思想,为web应用程序的客户端和服务端之间提供了一种全双工通信机制(注意:在WebSocket中是有客户端和服务端之分的)。

不同于原生Socket的端到端直接通信,WebSocke采取的方式是让所有客户端连接服务端,服务器再将不同客户端发送给自己的消息进行转发或者广播。

2、Websocket的通信原理

虽然WebSocket是一种新应用层协议,但既然是基于Web端的技术,就无法脱离HTTP而单独存在。但是它和HTTP最大的不同是:

1、WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样

2、WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信


所以当我们构建一个WebSocket实例的时候,实际上过程是这样的:

  • 客户端发送一个 http Get 请求报文,告诉服务端:我要将通信协议切换到WebSocket啦!发送的数据格式类似下面的内容:
GET ws://localhost:3000/ws/chat HTTP/1.1Host: localhostUpgrade: websocketConnection: UpgradeOrigin: http://localhost:3000Sec-WebSocket-Key: client-random-stringSec-WebSocket-Version: 13//该请求和普通的HTTP请求有几点不同://GET请求的地址不是类似/path/,而是以ws://开头的地址;//请求头Upgrade: websocket和Connection: Upgrade表示这个连接将要被转换为WebSocket连接;//Sec-WebSocket-Key是用于标识这个连接,并非用于加密数据;//Sec-WebSocket-Version指定了WebSocket的协议版本。
  • 如果服务端支持WebSocket协议,那么服务端就会将自己的通信协议切换为WebSocket,同时回传给客户端一个状态码为101的响应报头,该响应代码101表示本次连接的HTTP协议即将被更改,更改后的协议就是Upgrade: websocket指定的WebSocket协议。
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
  • 以上过程称之为WebSocket协议握手(WebSocket Protocol handshake),有点类似于TCP上次握手,实际上这个WebSocket也确实是基于我们刚才发起的http的TCP连接。

  • 然后就可以通过WebSocket进行服务端和客户端之间的连接啦,其提供两种数据传输方式:文本数据和二进制数据。


WebSocket出现前,Web端的即时通讯方法:
长轮询:客户端首先给服务端发送一个请求,服务端收到该请求之后如果数据没有更新则并不立即返回,服务端阻塞请求的返回,直到数据发生了更新或者发生了连接超时,服务端返回数据之后客户端再次发送同样的请求

基于流式数据传输的长连接:通常的做法是在页面中嵌入一个隐藏的iframe,然后让这个iframe的src属性指向我们请求的一个服务端地址,并且为了数据更新,我们将页面上数据更新操作封装为一个js函数,将函数名当做参数传递到这个地址当中。
服务端收到请求后解析地址取出参数(客户端js函数调用名),每当有数据更新的时候,返回对客户端函数的调用,并且将要跟新的数据以js函数的参数填入到返回内容当中

4、WebScoket基本API

服务端:

// 导入WebSocket模块:const WebSocket = require('ws');// 引用Server类:const WebSocketServer = WebSocket.Server;// 实例化: 在3000端口上打开一个WebSocket Serverconst wss = new WebSocketServer({    port: 3000});//监听connection事件wss.on('connection', function (ws) {    console.log(`[SERVER] connection()`);    ws.on('message', function (message) {        console.log(`[SERVER] Received: ${message}`);        ws.send(`ECHO: ${message}`, (err) => {            if (err) {                console.log(`[SERVER] error: ${err}`);            }        });    })});

客户端:

 var ws = new WebSocket("ws://localhost:3000"); //建立连接  ws.onopen = function(){ws.send(“Test!”); }; //响应收到的信息  ws.onmessage = function(evt){console.log(evt.data);};  //关闭连接 ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; //出错  ws.onerror = function(evt){console.log(“WebSocketError!”);}; //向服务端发送信息 ws.send('xxx');