如何编写一个 websocket 客户端

Posted

技术标签:

【中文标题】如何编写一个 websocket 客户端【英文标题】:How to write a websocket client 【发布时间】:2010-12-12 13:42:23 【问题描述】:

我正在尝试在 node.js 上对我的 websocket 进行单元测试,并想模拟一个 websocket 客户端。我可以创建一个仅连接到我的服务器的 html 文件,但我无法在服务器上运行单个测试。

我将如何(使用http.Clientnet.Stream)创建一个websocket 客户端并让它与我的服务器交互。

我的目标是 websocket 规范的(即将失效的)草案 76。

我使用的服务器端实现是this

【问题讨论】:

【参考方案1】:

由于您已经知道所有当前的 WebSocket 版本很快就会过时,并且您正在使用支持旧 75 草案的 WebSocket 服务器,如果您已经有一些服务器代码,那么制作一个相当简单,所以没有需要 76 中的“安全”标题内容。

免责声明:这个东西只有 5 分钟左右的测试,但它应该可以正常工作。

史诗般的代码墙

var net = require('net');

function WebSocket(host, port, encoder, decoder) 
    this.encoder = encoder || function(data)return data.toString();
    this.decoder = decoder || function(data)return data;
    this.socket = net.createConnection(port, host);

    this.connected = false;
    this.header = 0;
    this.bytesSend = 0;
    this.dataFrames = [];
    this.dataState = 0;

    var that = this;
    process.nextTick(function() 
        that.init(host, port);
    );



// Prototype -------------------------------------------------------------------
WebSocket.prototype = 
    onConnect: function() console.log('connect');,
    onClose: function() console.log('close');,
    onData: function(data) console.log(data),

    init: function(host, port) 
        var that = this;
        this.socket.addListener('connect', function() 
            var data ='GET / HTTP/1.1\r\n'
                  + 'Host: ' + host + ':' + port + '\r\n'
                  + 'Origin: websocket.node.js\r\n'
                  + 'Connection: Upgrade\r\n'
                  + 'Upgrade: WebSocket\r\n\r\n';

            that.socket.write(data, 'ascii');
            that.socket.flush();
        );
        this.socket.addListener('data', function(data) that.read(data););
        this.socket.addListener('end', function() that.onClose(););
        this.socket.addListener('error', function(e) console.log(e.message);that.close(););
    ,

    send: function(data, encoded) 
        if (this.connected) 
            return this.write(encoded ? data : this.encoder(data));

         else 
            return 0;
        
    ,

    close: function() 
        if (this.connected) 
            this.connected = false;
            this.write(null);
            this.socket.end();
            this.socket.destroy();
        
    ,

    read: function read(data) 
        for(var i = 0, l = data.length; i < l; i++) 
            var b = data[i];
            if (this.header < 4) 
                if ((this.header === 0 || this.header === 2) && b === 0x0d) 
                    this.header++;

                 else if ((this.header === 1 || this.header === 3) && b === 0x0a) 
                    this.header++;

                 else 
                    this.header = 0;
                

                if (this.header === 4) 
                    this.connected = true;
                    this.onConnect();
                    this.header = 5;
                

             else 
                if (this.dataState === 0) 
                    this.dataState = b & 0x80 === 0x80 ? 2 : 1;

                // Low bit frame
                 else if (this.dataState === 1) 
                    if (b === 0xff) 
                        var buffer = new Buffer(this.dataFrames);
                        this.dataFrames = [];
                        this.dataState = 0;

                        if (!this.message(buffer.toString('utf8', 0, buffer.length))) 
                            this.send(error: 'Invalid Message.');
                            this.close();
                            return;
                        

                     else 
                        this.dataFrames.push(b);
                    

                // Unused high bit frames
                 else if (this.dataState === 2) 
                    if (b === 0x00) 
                        this.close();
                    
                
            
        
    ,

    write: function(data) 
        var bytes = 0;
        if (!this.socket.writable) 
            return bytes;
        

        try 
            this.socket.write('\x00', 'binary');
            if (typeof data === 'string') 
                this.socket.write(data, 'utf8');
                bytes += Buffer.byteLength(data);
            
            this.socket.write('\xff', 'binary'); 
            this.socket.flush();
            bytes += 2;

         catch(e) 

        this.bytesSend += bytes;
        return bytes;
    ,

    message: function(msg) 
        if (this.decoder) 
            try 
                msg = this.decoder(msg);

             catch(e) 
                this.close();
                return false;
            
        
        this.onData(msg);
        return true;
    
;

我们在这里设置它:

var bison = require('bison');

// automatically do some encoding/decoding magic
var test = new WebSocket('localhost', 28785, bison.encode, bison.decode);
test.onConnect = function() 

;

test.onData = function(data) 

;

欢迎在 cmets 中提问。

PS:有关其工作原理的信息,请阅读规范:P

【讨论】:

【参考方案2】:

看看wiki上的modules page,它有一些websocket clients的模块在npm中可用。

【讨论】:

而不是仅仅说“这里有一个列表”,您可以为使用 0.4.8 并实现更新的 06 协议的稳定/最新/良好测试的 websocket 客户端修剪列表。

以上是关于如何编写一个 websocket 客户端的主要内容,如果未能解决你的问题,请参考以下文章

Java WebSocket:如何在不编写客户端的情况下测试服务器 WebSocket 端点 [关闭]

如何编写自己的 TCP/IP 或 ISO/OSI 堆栈以使用 WebSockets 而无需每次都使用握手?

如何响应龙卷风websocket中的服务器ping

如何在 Go 中创建 WebSocket 应用程序

当客户端更改 IP 地址或断开连接时,如何捕捉 websocket-close 事件?

如何编写 Netty 客户端以连接到 Signalr 集线器?