我已经成功编写了一个 csharp websocket 服务器并且客户端可以连接,但是客户端发送一条
ping
消息,但服务器没有响应 pong
,因此客户端断开连接。
经过进一步调查,结果发现我需要运行
ReadAsync
来捕获 ping 消息,但随后它处于等待状态,因此会阻止一切!
我很想访问底层套接字,这样我就可以执行
socket.available
来检查读取数据,但这是不可能的。
那么你应该如何用 C# 编写一个 websocket 服务器(不要说 SignalR!)来响应 ping 并确定客户端是否已断开!
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
class Program
{
static async Task ClientHandler(HttpContext context)
{
using WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();
Console.WriteLine("Websocket client connected from {0}", socket.SubProtocol);
var buffer = new byte[1024 * 4];
WebSocketReceiveResult payload = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string? message = Encoding.UTF8.GetString(buffer);
Console.WriteLine("Received {0}", message);
// workaround for replying to ping from client which requires ReceiveAsync to be active
// Task.Run(async () =>
// {
// await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
// });
while (socket.State == WebSocketState.Open)
{
Console.WriteLine("Sending message...");
byte[] msg = System.Text.Encoding.Default.GetBytes("Hello, World!");
await socket.SendAsync(new ArraySegment<byte>(msg, 0, msg.Length), payload.MessageType, true, CancellationToken.None);
Thread.Sleep(200);
}
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "No more messages", CancellationToken.None);
Console.WriteLine("Connection closed");
}
static void Main()
{
var app = WebApplication.CreateBuilder().Build();
app.UseWebSockets();
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
if (context.WebSockets.IsWebSocketRequest)
await ClientHandler(context);
else
context.Response.StatusCode = StatusCodes.Status400BadRequest;
else
await next(context);
});
app.Run("http://127.0.0.1:8001");
}
}
检查此代码:
class Program
{
static async Task ClientHandler(HttpContext context)
{
using WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();
Console.WriteLine("WebSocket client connected.");
var buffer = new byte[1024 * 4];
// Task to continuously receive messages
var receiveTask = Task.Run(async () =>
{
while (socket.State == WebSocketState.Open)
{
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
Console.WriteLine("WebSocket client disconnected.");
}
else if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine("Received message: {0}", message);
}
else if (result.MessageType == WebSocketMessageType.Binary)
{
Console.WriteLine("Received binary message of length: {0}", result.Count);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
Console.WriteLine("Received close message.");
}
}
});
// Task to continuously send messages
var sendTask = Task.Run(async () =>
{
while (socket.State == WebSocketState.Open)
{
var msg = Encoding.UTF8.GetBytes("Hello, World!");
await socket.SendAsync(new ArraySegment<byte>(msg, 0, msg.Length), WebSocketMessageType.Text, true, CancellationToken.None);
await Task.Delay(200);
}
});
await Task.WhenAny(receiveTask, sendTask);
Console.WriteLine("WebSocket connection closed.");
}
static void Main()
{
var builder = WebApplication.CreateBuilder();
var app = builder.Build();
app.UseWebSockets();
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
await ClientHandler(context);
}
else
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
else
{
await next(context);
}
});
app.Run("http://127.0.0.1:8001");
}
}