c# .net
csharp .net WebSocket Client
kimbs0301
2025. 2. 23. 14:46
.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Model.cs
using System;
namespace WebSocketClient;
public class EchoMessage
{
public int Sequence { get; set; }
public string Content { get; set; } = string.Empty;
public Int64 CurrentTime { get; set; } = 0;
}
PacketCountTimer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WebSocketClient;
public class PacketCountTimer
{
public Timer? CountTimer = null;
public int SendCount = 0;
public int RecvCount = 0;
public void Start()
{
int interval = 1 * 1000; // in milliseconds
CountTimer = new Timer(PrintCount, new object(), 1 * 1000, interval);
}
private void PrintCount(object? state)
{
if (state == null) return;
if (Monitor.TryEnter(state))
{
try
{
Console.WriteLine($"SendCount: {SendCount} RecvCount: {RecvCount}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
Monitor.Exit(state);
}
}
}
}
Program.cs
using System;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
namespace WebSocketClient;
public class Program
{
public static void Main(string[] args)
{
var packetCountTimer = new PacketCountTimer();
packetCountTimer.Start();
for (int i = 1; i <= 1000; i++)
{
var connectTimeout = new CancellationTokenSource();
connectTimeout.CancelAfter(2000);
var url = new Uri($"ws://localhost:2121/connect?username={i}");
var clientSocket = new ClientWebSocket();
clientSocket.Options.DangerousDeflateOptions = new WebSocketDeflateOptions
{
ClientContextTakeover = true,
ServerContextTakeover = true
};
clientSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(10); // 10초마다 서버로 Pong 전송
//clientSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0);
clientSocket.ConnectAsync(url, null, connectTimeout.Token).Wait();
if (clientSocket.State != WebSocketState.Open)
{
Console.WriteLine($"Failed to connect: {url}");
clientSocket.Dispose();
continue; // next
}
Console.WriteLine($"connect {i}");
Task.Run(async () =>
{
ClientWebSocket socket = clientSocket;
var recvByteArray = new byte[1024 * 4];
while (socket.State == WebSocketState.Open)
{
var recvBuffer = new ArraySegment<byte>(recvByteArray);
WebSocketReceiveResult result;
try
{
result = await socket.ReceiveAsync(recvBuffer, CancellationToken.None);
}
catch (Exception ex)
{
if (socket.State == WebSocketState.Open)
{
Console.WriteLine($"Error: {ex.Message}");
try
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
socket.Dispose();
}
catch (Exception) { }
}
break;
}
if (result.MessageType == WebSocketMessageType.Binary)
{
if (result.Count < 1) continue; // next
TryDeserializeClientMessage(Encoding.UTF8.GetString(recvByteArray, 0, result.Count));
//Console.WriteLine($"{result.MessageType} {result.EndOfMessage} {Encoding.UTF8.GetString(recvByteArray, 0, result.Count)}");
Interlocked.Increment(ref packetCountTimer.RecvCount);
}
else if (result.MessageType == WebSocketMessageType.Text)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
socket.Dispose();
break;
}
else if (result.MessageType == WebSocketMessageType.Close)
break;
}
});
Task.Run(async () =>
{
ClientWebSocket socket = clientSocket;
WebSocketMessageFlags socketMessageFlags = CreateMessageFlags(endOfMessage: true, compressMessage: false);
for (int i = 1; i <= 100000; i++)
{
var now = DateTime.UtcNow.Ticks;
var echoMessage = new EchoMessage()
{
Sequence = i,
Content = DateTime.UtcNow.Ticks.ToString(),
CurrentTime = now
};
//Console.WriteLine(Encoding.UTF8.GetString(JsonSerializer.SerializeToUtf8Bytes(echoMessage)));
var sendBuffer = new ArraySegment<byte>(JsonSerializer.SerializeToUtf8Bytes(echoMessage));
Interlocked.Increment(ref packetCountTimer.SendCount);
try
{
await socket.SendAsync(sendBuffer, WebSocketMessageType.Binary, socketMessageFlags, CancellationToken.None);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
break;
}
await Task.Delay(50);
}
while (socket.State == WebSocketState.Open)
{
await Task.Delay(100);
if (packetCountTimer.RecvCount >= 10_000_000)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, cancellationToken: CancellationToken.None);
socket.Dispose();
break;
}
}
});
}
Console.ReadLine();
}
static EchoMessage? TryDeserializeClientMessage(string message)
{
try
{
return JsonSerializer.Deserialize<EchoMessage>(message);
}
catch (Exception ex)
{
Console.WriteLine($"Error: invalid message format {ex.Message}");
return null;
}
}
private static WebSocketMessageFlags CreateMessageFlags(bool endOfMessage, bool compressMessage)
{
WebSocketMessageFlags flags = WebSocketMessageFlags.None;
if (endOfMessage == true)
flags |= WebSocketMessageFlags.EndOfMessage;
if (compressMessage == false)
flags |= WebSocketMessageFlags.DisableCompression;
return flags;
}
}