Files
2026-07-10 10:24:29 +08:00

82 lines
3.0 KiB
C#

using System;
using System.IO;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using ChannelsNS = System.Threading.Channels;
using XWorld.Framework.Protocol;
namespace XWorld.Server.Gateway
{
// 一个 WebSocket 连接:收循环解码帧→Submit;发循环排空出站队列→SendAsync(每 socket 仅一个发循环,发送串行)
public sealed class Connection : IClientConnection
{
public int PlayerId { get; }
private readonly WebSocket _socket;
private readonly ServerLoop _loop;
private readonly ChannelsNS.Channel<byte[]> _outbound = ChannelsNS.Channel.CreateUnbounded<byte[]>();
public Connection(int playerId, WebSocket socket, ServerLoop loop)
{
PlayerId = playerId; _socket = socket; _loop = loop;
}
public void Send(byte[] frame) => _outbound.Writer.TryWrite(frame);
public async Task RunAsync(CancellationToken ct)
{
var sendTask = SendLoopAsync(ct);
try { await ReceiveLoopAsync(ct).ConfigureAwait(false); }
finally
{
_outbound.Writer.TryComplete();
await sendTask.ConfigureAwait(false);
}
}
private async Task ReceiveLoopAsync(CancellationToken ct)
{
var buf = new byte[8192];
using var ms = new MemoryStream();
try
{
while (_socket.State == WebSocketState.Open && !ct.IsCancellationRequested)
{
ms.SetLength(0);
WebSocketReceiveResult res;
do
{
res = await _socket.ReceiveAsync(new ArraySegment<byte>(buf), ct).ConfigureAwait(false);
if (res.MessageType == WebSocketMessageType.Close) return;
ms.Write(buf, 0, res.Count);
} while (!res.EndOfMessage);
Frame frame;
try { frame = FrameCodec.Decode(ms.ToArray()); }
catch (FormatException) { continue; } // 畸形帧:丢弃,不拖垮连接
_loop.Submit(new FrameCommand { PlayerId = PlayerId, Frame = frame });
}
}
catch (OperationCanceledException) { } // 主机关停/请求中止
catch (WebSocketException) { } // 对端突然断开(TCP 掉线)
}
private async Task SendLoopAsync(CancellationToken ct)
{
try
{
await foreach (var frame in _outbound.Reader.ReadAllAsync(ct).ConfigureAwait(false))
{
if (_socket.State != WebSocketState.Open) break;
await _socket.SendAsync(new ArraySegment<byte>(frame),
WebSocketMessageType.Binary, true, ct).ConfigureAwait(false);
}
}
catch (OperationCanceledException) { }
catch (WebSocketException) { } // 对端已断,停止发送
}
}
}