• NodeJs使用nodejs-websocket + protobuf


    参考:

    HTML5+NodeJs实现WebSocket即时通讯 (某人的blog)

    nodejs-websocket使用示例  (www.npmjs.com网站,有示例)

    Buffer API (nodejs api 中文版)

    nodejs-websocket + protobufjs

     一 安装nodejs-websocket

    在服务端项目文件夹下,新建一个pageage.json

    {
      "name": "realtime-server",
      "version": "0.0.1",
      "description": "my first realtime server",
      "dependencies": {
        "nodejs-websocket": "^1.7.2",
        "protobufjs": "^6.8.8"
      }
    }
    

    在服务端项目文件夹下shift+右键,在此处打开命令窗口,输入

    npm install nodejs-websocket
    

    安装完毕后,项目目录下会增加node_modules文件夹

      

    二 安装protobufjs

    在服务端项目文件夹下shift+右键,在此处打开命令窗口,输入

    npm install protobufjs
    

    输入后回车,等待安装完毕,如下图:

    三 准备测试用.proto文件

    准备一个测试用的proto文件,如下

    login.proto

    //登录
    package login;
    
    //登录请求
    message LoginReq{
    	required int32 uid = 1;      //用户id
    }
    

    proto文件转成.js

    将login.proto放在服务端项目文件夹下

    shift+右键,打开命令窗口,生成js

    pbjs -t static-module -w commonjs -o login.js login.proto
    

    生成d.ts (服务端不需要,客户端需要)

    pbts -o login.d.ts login.js
    

     四 服务端代码

     服务端连接成功后,等待接收。 如果接收到登录请求,则解析loginReq,然后返回一个loginReq。

    直接使用login.proto文件示例:

    var ws = require("nodejs-websocket");
    var protobufjs = require("protobufjs");
    var root = protobufjs.loadSync("./login.proto");   //直接使用login.proto文件
    
    console.log("开始创建websocket");
    var server = ws.createServer(function(conn){
    	console.log("连接成功");
        conn.on("binary", function (inStream) {
    		console.log("接收消息");
    		var data;
    		inStream.on("readable", function () {
                data = inStream.read();
            })
    		inStream.on("end", function () {
                console.log("Received " + data.length + " bytes of binary data");
    			
    			//解析接收的数据,cmd
    			var cmd = data.readUInt16BE(0);
    			console.log("接收数据的cmd:",cmd);
    			let bytes = Buffer.from(data,1);
    			//解析接收的数据,loginReq
    			var LoginReq = root.lookupType("login.LoginReq");
    			var loginReq = LoginReq.decode(bytes);
    			console.log("接收数据的uid:", loginReq.uid);
    			
    			
    			
    			//发送的数据,loginReq
    			var sendLoginReq = LoginReq.create();
    			sendLoginReq.uid = 123;
    			var sendData = LoginReq.encode(sendLoginReq).finish();
    			//发送的数据,cmd
    			var sendBuffer = Buffer.alloc(2);
    			sendBuffer.writeInt16BE(100);
    			//拼接数据并发送
    			var totalBuffer = Buffer.concat([sendBuffer,sendData],sendData.length + sendBuffer.length);
    			conn.sendBinary(totalBuffer);
            })
    		
            
        })
        conn.on("close", function (code, reason) {
            console.log("关闭连接")
        });
        conn.on("error", function (code, reason) {
            console.log("异常关闭")
        });
    }).listen(8001)
    console.log("开始创建websocket完毕");
    

     

    使用转换后login.js文件示例:

    var root = require("./login");    //使用login.js文件
     
    //连接成功
    io.on('connection', function(socket){
        console.log('a user connected');
        //监听登录请求
        socket.on('login', function(data,callback){         
             //解析登录数据
            var loginReqObj = root.login.LoginReq.decode(data);
            console.log("请求登录的用户:",loginReqObj.uid);
            //返回登录响应
            let loginResObj = root.login.LoginRes.create();
            loginResObj.code = 200;
            var buffer = root.login.LoginReq.encode(loginResObj).finish();
            socket.emit('login', buffer);
        });
    });
    

      

     

    五 客户端代码

    客户端请求连接服务端,连接成功后发送登录请求loginReq

    	/**连接成功*/
    	private onConnect(e:egret.Event){
    		console.log("ClientSocket 连接成功");
    		this.resetReconnect();
    		App.EventMananger.sendEvent(ClientSocket.SOCKET_CONNECT);
    
    		//测试
    		let loginData:login.LoginReq = new login.LoginReq();
    		loginData.uid = 123;
    		let buffer = login.LoginReq.encode(loginData).finish();
    		this.send(100, buffer);
    	}
    	
    	/**
    	 * 发送数据
    	 * @param cmd 数据协议
    	 * @param sendByte 发送的数据
    	 */ 
    	public send(cmd:number, sendByte:Uint8Array){
    		console.log("ClientSocket 发送:",cmd);
    		//发送的数据cmd+proto
    		let sendByteArray = new egret.ByteArray(sendByte);
    		let byteArray:egret.ByteArray = new egret.ByteArray();
    		byteArray.writeUnsignedShort(cmd);
    		byteArray.writeBytes(sendByteArray);
    		//发送
            this.socket.writeBytes(byteArray);
    		this.socket.flush();
    	}
    
    	/**接收数据*/
    	private onReceive(e:egret.Event){
    		//读取socket数据
    		var byte:egret.ByteArray = new egret.ByteArray();
            this.socket.readBytes(byte);
    		//读取cmd+proto
    		let cmd:number = byte.readUnsignedShort();
    		console.log("接收数据,cmd:",cmd);
    		//读取loginReq
    		let revByteArray:egret.ByteArray = new egret.ByteArray();
    		byte.readBytes(revByteArray);
    		let buffer:login.LoginReq = login.LoginReq.decode(revByteArray.bytes);
    		console.log("接收数据,uid:",buffer.uid);
    	}
    

      

    六 测试结果  

     运行服务端和客户端

    1. 客户端请求连接服务端

    2. 连接成功后,客户端发送登录请求loginReq

    3. 服务端接收到登录请求,解析loginReq并打印。 然后再返回一个loginReq。

    4. 客户端接收到服务端返回的loginReq,解析并打印。

    服务端输出:

    客户端输出:

     到此,一个简单的nodejs-websocket + protobufjs服务单搭建和联调测试完成。

    问题:

    一 nodejs服务端关于Buffer的操作

    看了一下Buffer的Api,没有找到writeBytes的方法,只有concat来拼接数据。

  • 相关阅读:
    bash实现多进程运行
    Erlang实现进程池
    Apache 和nginx支持跨域访问
    thinkphp 发送邮件
    判断PC和移动端 判断移动端系统
    check 选择框checked属性读取不到
    php使用PDO,并连接SQL
    SQL2005:由于目标机器积极拒绝,无法连接
    frozenui 移动端ui
    纯jquery 滚动评论
  • 原文地址:https://www.cnblogs.com/gamedaybyday/p/10550805.html
Copyright © 2020-2023  润新知