先说断线: 客户端断线可能性有很多, 比如死机, 闪退, 用户强制退出, 断网, 用户正常退出等等. 对于每种情况, 需要对应的使用操作系统SDK, 游戏引擎SDK, Colyseus SDK 针对不同的事件或者错误进行不同的处理.
以下代码选取自 Colyseus 官方 Unity SDK Example.
private void OnLeaveRoom(int code)
{
WebSocketCloseCode parsedCode = WebSocketHelpers.ParseCloseCodeEnum(code);
LSLog.Log(string.Format("ROOM: ON LEAVE =- Reason: {0} ({1})", parsedCode, code));
_pingThread.Abort();
_pingThread = null;
_room = null;
if (parsedCode != WebSocketCloseCode.Normal && !string.IsNullOrEmpty(_lastRoomId))
{
JoinRoomId(_lastRoomId,null);
}
}
再说重连: 重连的意义在于恢复 RoomID 与 SessionID. 为此 Colyseus 客户端 SDK 提供了 reconnect 函数.
同时 Colyseus 服务端 提供了 allowReconnection 函数, 允许离线的客户端在指定时间内重连 (恢复 RoomID 与 SessionID).
以下代码出自 Colyseus API:
Server:
async onLeave (client: Client, consented: boolean) {
// flag client as inactive for other users
this.state.players.get(client.sessionId).connected = false;
try {
if (consented) {
throw new Error("consented leave");
}
// allow disconnected client to reconnect into this room until 20 seconds
await this.allowReconnection(client, 20);
// client returned! let's re-activate it.
this.state.players.get(client.sessionId).connected = true;
} catch (e) {
// 20 seconds expired. let's remove the client.
this.state.players.delete(client.sessionId);
}
}
Client:
try {
const room = await client.reconnect("wNHTX5qik", "SkNaHTazQ");
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}
reconnect 函数需要程序员手动调用, 或者建立某种任务机制实现自动调用. Colyseus 内部不会自动调用.
官方 Unity SDK 中的 Example 中也有更为严谨的处理断线重连的方法可供参考.
关于 websocket 长连接:
是的, nginx 有超时断开机制, 但是参考官方文档就会发现, 可以任意配置超时时间.
server {
listen 80;
listen 443 ssl;
server\_name yourdomain.com;
ssl_certificate /path/to/your/cert.crt;
ssl_certificate_key /path/to/your/cert.key;
location / {
proxy_pass http://localhost:2567;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
这里配置了24小时不断连, 基本上可以满足所有需求了.
当然可以配合心跳, 心跳机制需要程序员自己实现, 简单的一个client.send()即可.