* LCHeartBeat.cs:
* LCConnection.cs: * LCWebSocketClient.cs: chore: 重构连接相关结构
parent
d66d1e53dc
commit
1447070c8f
|
@ -43,11 +43,6 @@ namespace LeanCloud.Realtime.Internal.Connection {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal Action OnDisconnect;
|
internal Action OnDisconnect;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始重连事件
|
|
||||||
/// </summary>
|
|
||||||
internal Action OnReconnecting;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重连成功事件
|
/// 重连成功事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -73,14 +68,26 @@ namespace LeanCloud.Realtime.Internal.Connection {
|
||||||
responses = new Dictionary<int, TaskCompletionSource<GenericCommand>>();
|
responses = new Dictionary<int, TaskCompletionSource<GenericCommand>>();
|
||||||
heartBeat = new LCHeartBeat(this, HEART_BEAT_INTERVAL, HEART_BEAT_INTERVAL);
|
heartBeat = new LCHeartBeat(this, HEART_BEAT_INTERVAL, HEART_BEAT_INTERVAL);
|
||||||
router = new LCRTMRouter();
|
router = new LCRTMRouter();
|
||||||
client = new LCWebSocketClient(router, heartBeat) {
|
client = new LCWebSocketClient {
|
||||||
OnMessage = OnClientMessage,
|
OnMessage = OnClientMessage,
|
||||||
OnClose = OnClientDisconnect
|
OnClose = OnClientDisconnect
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task Connect() {
|
internal async Task Connect() {
|
||||||
await client.Connect();
|
try {
|
||||||
|
LCRTMServer rtmServer = await router.GetServer();
|
||||||
|
try {
|
||||||
|
LCLogger.Debug($"Primary Server");
|
||||||
|
await client.Connect(rtmServer.Primary);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LCLogger.Error(e);
|
||||||
|
LCLogger.Debug($"Secondary Server");
|
||||||
|
await client.Connect(rtmServer.Secondary);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -93,7 +100,7 @@ namespace LeanCloud.Realtime.Internal.Connection {
|
||||||
// 重新创建连接组件
|
// 重新创建连接组件
|
||||||
heartBeat = new LCHeartBeat(this, HEART_BEAT_INTERVAL, HEART_BEAT_INTERVAL);
|
heartBeat = new LCHeartBeat(this, HEART_BEAT_INTERVAL, HEART_BEAT_INTERVAL);
|
||||||
router = new LCRTMRouter();
|
router = new LCRTMRouter();
|
||||||
client = new LCWebSocketClient(router, heartBeat) {
|
client = new LCWebSocketClient {
|
||||||
OnMessage = OnClientMessage,
|
OnMessage = OnClientMessage,
|
||||||
OnClose = OnClientDisconnect
|
OnClose = OnClientDisconnect
|
||||||
};
|
};
|
||||||
|
@ -140,12 +147,12 @@ namespace LeanCloud.Realtime.Internal.Connection {
|
||||||
internal async Task Close() {
|
internal async Task Close() {
|
||||||
OnNotification = null;
|
OnNotification = null;
|
||||||
OnDisconnect = null;
|
OnDisconnect = null;
|
||||||
OnReconnecting = null;
|
|
||||||
OnReconnected = null;
|
OnReconnected = null;
|
||||||
await client.Close();
|
await client.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClientMessage(byte[] bytes) {
|
private void OnClientMessage(byte[] bytes) {
|
||||||
|
_ = heartBeat.Refresh(OnPingTimeout);
|
||||||
try {
|
try {
|
||||||
GenericCommand command = GenericCommand.Parser.ParseFrom(bytes);
|
GenericCommand command = GenericCommand.Parser.ParseFrom(bytes);
|
||||||
LCLogger.Debug($"{id} <= {FormatCommand(command)}");
|
LCLogger.Debug($"{id} <= {FormatCommand(command)}");
|
||||||
|
@ -178,21 +185,25 @@ namespace LeanCloud.Realtime.Internal.Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClientDisconnect() {
|
private void OnClientDisconnect() {
|
||||||
|
heartBeat.Stop();
|
||||||
OnDisconnect?.Invoke();
|
OnDisconnect?.Invoke();
|
||||||
OnReconnecting?.Invoke();
|
|
||||||
// 重连
|
// 重连
|
||||||
_ = Reconnect();
|
_ = Reconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void OnPingTimeout() {
|
||||||
|
await client.Close();
|
||||||
|
OnClientDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Reconnect() {
|
private async Task Reconnect() {
|
||||||
OnReconnecting?.Invoke();
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int reconnectCount = 0;
|
int reconnectCount = 0;
|
||||||
// 重连策略
|
// 重连策略
|
||||||
while (reconnectCount < MAX_RECONNECT_TIMES) {
|
while (reconnectCount < MAX_RECONNECT_TIMES) {
|
||||||
try {
|
try {
|
||||||
LCLogger.Debug($"Reconnecting... {reconnectCount}");
|
LCLogger.Debug($"Reconnecting... {reconnectCount}");
|
||||||
await client.Connect();
|
await Connect();
|
||||||
break;
|
break;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reconnectCount++;
|
reconnectCount++;
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace LeanCloud.Realtime.Internal.Connection {
|
||||||
/// 更新心跳监听
|
/// 更新心跳监听
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal async Task Update(Action onTimeout) {
|
internal async Task Refresh(Action onTimeout) {
|
||||||
LCLogger.Debug("HeartBeat update");
|
LCLogger.Debug("HeartBeat update");
|
||||||
pingCTS?.Cancel();
|
pingCTS?.Cancel();
|
||||||
pongCTS?.Cancel();
|
pongCTS?.Cancel();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using LeanCloud.Realtime.Internal.Router;
|
|
||||||
using LeanCloud.Realtime.Internal.Connection;
|
|
||||||
|
|
||||||
namespace LeanCloud.Realtime.Internal.WebSocket {
|
namespace LeanCloud.Realtime.Internal.WebSocket {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -34,44 +32,12 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
|
||||||
|
|
||||||
private ClientWebSocket ws;
|
private ClientWebSocket ws;
|
||||||
|
|
||||||
private readonly LCRTMRouter router;
|
|
||||||
|
|
||||||
private readonly LCHeartBeat heartBeat;
|
|
||||||
|
|
||||||
internal LCWebSocketClient(LCRTMRouter router, LCHeartBeat heartBeat) {
|
|
||||||
this.router = router;
|
|
||||||
this.heartBeat = heartBeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 连接
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal async Task Connect() {
|
|
||||||
try {
|
|
||||||
LCRTMServer rtmServer = await router.GetServer();
|
|
||||||
try {
|
|
||||||
LCLogger.Debug($"Primary Server");
|
|
||||||
await Connect(rtmServer.Primary);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LCLogger.Error(e);
|
|
||||||
LCLogger.Debug($"Secondary Server");
|
|
||||||
await Connect(rtmServer.Secondary);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接收
|
|
||||||
_ = StartReceive();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接指定 ws 服务器
|
/// 连接指定 ws 服务器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server"></param>
|
/// <param name="server"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task Connect(string server) {
|
internal async Task Connect(string server) {
|
||||||
LCLogger.Debug($"Connecting WebSocket: {server}");
|
LCLogger.Debug($"Connecting WebSocket: {server}");
|
||||||
Task timeoutTask = Task.Delay(CONNECT_TIMEOUT);
|
Task timeoutTask = Task.Delay(CONNECT_TIMEOUT);
|
||||||
ws = new ClientWebSocket();
|
ws = new ClientWebSocket();
|
||||||
|
@ -79,6 +45,9 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
|
||||||
Task connectTask = ws.ConnectAsync(new Uri(server), default);
|
Task connectTask = ws.ConnectAsync(new Uri(server), default);
|
||||||
if (await Task.WhenAny(connectTask, timeoutTask) == connectTask) {
|
if (await Task.WhenAny(connectTask, timeoutTask) == connectTask) {
|
||||||
LCLogger.Debug($"Connected WebSocket: {server}");
|
LCLogger.Debug($"Connected WebSocket: {server}");
|
||||||
|
await connectTask;
|
||||||
|
// 接收
|
||||||
|
_ = StartReceive();
|
||||||
} else {
|
} else {
|
||||||
throw new TimeoutException("Connect timeout");
|
throw new TimeoutException("Connect timeout");
|
||||||
}
|
}
|
||||||
|
@ -92,7 +61,6 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
|
||||||
LCLogger.Debug("Closing WebSocket");
|
LCLogger.Debug("Closing WebSocket");
|
||||||
OnMessage = null;
|
OnMessage = null;
|
||||||
OnClose = null;
|
OnClose = null;
|
||||||
heartBeat.Stop();
|
|
||||||
try {
|
try {
|
||||||
// 发送关闭帧可能会很久,所以增加超时
|
// 发送关闭帧可能会很久,所以增加超时
|
||||||
// 主动挥手关闭,不会再收到 Close Frame
|
// 主动挥手关闭,不会再收到 Close Frame
|
||||||
|
@ -152,7 +120,6 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (result.MessageType == WebSocketMessageType.Binary) {
|
} else if (result.MessageType == WebSocketMessageType.Binary) {
|
||||||
_ = heartBeat.Update(HandleExceptionClose);
|
|
||||||
// 拼合 WebSocket Message
|
// 拼合 WebSocket Message
|
||||||
int length = result.Count;
|
int length = result.Count;
|
||||||
byte[] data = new byte[length];
|
byte[] data = new byte[length];
|
||||||
|
@ -165,13 +132,12 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 客户端网络异常
|
// 客户端网络异常
|
||||||
LCLogger.Error(e);
|
LCLogger.Error(e);
|
||||||
OnClose?.Invoke();
|
HandleExceptionClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleExceptionClose() {
|
private void HandleExceptionClose() {
|
||||||
try {
|
try {
|
||||||
heartBeat.Stop();
|
|
||||||
ws.Abort();
|
ws.Abort();
|
||||||
ws.Dispose();
|
ws.Dispose();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
Loading…
Reference in New Issue