• 每天看一片代码系列(二):WebSocket-Node


    简介

    我们都知道,websocket主要是通过在浏览器和服务端建立长连接,继而实现二者的相互数据通信。不同于HTTP的轮询,它不会有大量无效的HTTP消息交换,从而节省了花销。websocket其实就是双通道的TCP连接。

    很明显地,整个工作分为两个步骤,即创建连接和发送数据。那么连接是怎么建立的呢?其实只需要在浏览器和服务器端做一个握手的动作就可以了。而这个握手其实还是一个HTTP请求,只是接下来的工作就和HTTP没关系了。

    这个HandShake的请求消息大致为:

    GET /chat HTTP/1.1
    Host: example.com:8000
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Sec-WebSocket-Version: 13

    而响应的消息大致为:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

    HTTP里面的upgrade头部代表要从HTTP协议切换到另一个协议,或者是更换一个不同版本的HTTP。而Sec-WebSocket-Key和Sec-WebSocket-Accept是用来进行验证的字段。后者是前者经过一系列操作计算出来的,用来给客户端判断响应和请求是否匹配。

    使用WebSocket-Node

    首先我们体验一下“websocket-node"这个库的用法。

    其实用这个库就是为了创建一个websocket-server,在app.js中,我们创建即可。

    var port = 3001;
    var websocketServer = require('websocket').server;
    var http = require('http');
    
    // 创建httpServer
    var httpServer = http.createServer();
    httpServer.listen(port, function () {
        console.log(new Date() + " Http Server is listening on " + port);
    });
    
    //创建WebSocketServer
    var wsServer = new websocketServer({
        httpServer: httpServer
    });
    
    wsServer.on('request', function (request) {
        console.log(new Date() + " connection from origin: " + request.origin + ' .');
        //建立连接
        var connection = request.accept('example', request.origin);
    
        //向客户端发送消息
        connection.sendUTF("Connection from " + request.origin);
    
        connection.on('close', function () {
            console.log(connection.remoteAddress + " disconnected.");
        })
    
        //收消息
        connection.on('message', function (message) {
            try{
                connection.sendUTF("Server accpected: " + message.utf8Data);
            }catch(e){
    
            }
        })
    })

    在浏览器中,就和这个库没什么关系了,直接用浏览器支持的API创建Websocket客户端,收发消息即可。

    var wsServer = "ws://localhost:3001";
    var ws = new WebSocket(wsServer, 'example');
    
    ws.onopen = function (e) {
        var msg = "hello Server!";
        ws.send(msg) && print(msg);
    }
    
    ws.onclose = function (e) {
        var msg = "closed connection";
        print(msg);
    }
    
    ws.onmessage = function (e) {
        var msg = "received : " + e.data;
        print(msg);
    }

    源码解析

    源码有多个文件,我们只关注WebSocketServer.js,地址

    首先,在传入的配置中必须要绑定一个httpServer用于握手。当客户端建立连接时,首先会进行握手,会触发server的upgrade事件,从而进入到服务端的处理函数中去。在这个函数中,会创建一个wsRequest对象,并将它作为request事件的参数发送出去。接下来根据客户端的Accept情况来进入到handleRequestAccepted,接下来connect事件会被触发。

    var upgradeHandler = this._handlers.upgrade;
    this.config.httpServer.forEach(function(httpServer) {
        httpServer.on('upgrade', upgradeHandler);
    });
    
    handleUpgrade:
    var wsRequest = new WebSocketRequest(socket, request, this.config);
    try {
        wsRequest.readHandshake();
    }
    wsRequest.once('requestAccepted', this._handlers.requestAccepted);
        wsRequest.once('requestResolved', this._handlers.requestResolved);
    if (!this.config.autoAcceptConnections && utils.eventEmitterListenerCount(this, 'request') > 0) {
        this.emit('request', wsRequest);
    }
    
    handleRequestAccepted:
    this.connections.push(connection);
    this.emit('connect', connection);

    另外,WebsocketServer继承了EventEmitter,所以具有事件处理的能力:

    util.inherits(WebSocketServer, EventEmitter);
  • 相关阅读:
    terraform入门操作指南
    linux常用命令
    pssh用法范例
    nginx共享内存使用
    Redis监控指标[转]
    xargs用法笔记
    systemd用法记录一
    esxcli部分常用命令
    lua自定义功能模块table类型转string类型
    curl用法笔记
  • 原文地址:https://www.cnblogs.com/cubika/p/4437901.html
Copyright © 2020-2023  润新知