參考:
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來拼接數據。
