参考:
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来拼接数据。