C# Ошибка подключения к серверу WebSocket
При большом количестве подключений к серверу я получаю ошибку на стороне клиента Unable to connect to the remote server Невозможно подключиться к удаленному серверу
При запуске количество ошибок всегда разное от 0 до 100 и т.п. При этом проект с сервером при нагрузке в 1000 подключений потребляет на 10мб больше озу, у клиентского приложения нагрузка полностью отсутствует. Подскажите как можно стабилизировать работу с сокетами.
Код сервера
Program.cs
using Microsoft.AspNetCore.HttpOverrides;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
});
var connectionString = builder.Configuration.GetConnectionString("Programs");
builder.Services.AddSqlite<ContextProgram>(connectionString);
var app = builder.Build();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseHttpsRedirection();
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(15)
};
app.UseWebSockets(webSocketOptions);
app.UseAuthorization();
app.MapControllers();
app.Run();
Код контролера
public class SocketController : Controller
{
[HttpGet("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Socket(webSocket);
}
else
{
// HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
private async Task Socket(WebSocket webSocket)
{
try
{
var buffer = new byte[1024 * 4];
var receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
receiveResult.MessageType,
receiveResult.EndOfMessage,
CancellationToken.None);
receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
await Task.Delay(10);
}
await webSocket.CloseAsync(
receiveResult.CloseStatus.Value,
receiveResult.CloseStatusDescription,
CancellationToken.None);
}
catch (Exception ex)
{
string message = ex.Message.ToString();
// webSocket.Abort();
}
}
}
Код для проверки нагрузки на сервер или же просто подключение в многопотоке к серверу
using System.Net.WebSockets;
using System.Text;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
SemaphoreSlim _semaphore;
CancellationTokenSource _cancelToken;
CancellationTokenSource CancellationTokenSource = new();
Console.WriteLine("Start");
int thread = 1000;
_semaphore = new SemaphoreSlim(thread);
_cancelToken = new CancellationTokenSource();
var pool = new List<Task>(thread);
for (int i = 0; i < thread; i++)
{
await _semaphore.WaitAsync().ConfigureAwait(false);
int val = i;
ClientWebSocket webSocketClient = new ClientWebSocket();
CancellationToken cancellationToken = new();
pool.Add(Task.Run(async () =>
{
await Socket(webSocketClient, cancellationToken, val);
_semaphore.Release();
}, _cancelToken.Token));
}
await Task.WhenAll(pool.ToArray()).ConfigureAwait(false);
Console.WriteLine("Done");
Console.ReadKey();
async Task Socket(ClientWebSocket webSocketClient, CancellationToken cancellationToken, int i)
{
string error = "";
try
{
await webSocketClient.ConnectAsync(new Uri("ws://localhost:5000/ws"), cancellationToken).ConfigureAwait(false);
if (webSocketClient.State == WebSocketState.Open)
{
await Send(webSocketClient, i.ToString(), cancellationToken);
await SocketNew(webSocketClient);
}
}
catch (Exception ex)
{
error = ex.Message.ToString();
Console.WriteLine("Ошибка подключения" + $" {error}");
return;
}
}
async Task Send(ClientWebSocket webSocketClient, string requestString, CancellationToken cancellationToken)
{
var requestBytes = UTF8Encoding.UTF8.GetBytes(requestString);
var subscribeRequest = new ArraySegment<byte>(requestBytes);
await webSocketClient.SendAsync(subscribeRequest, WebSocketMessageType.Text, true, cancellationToken).ConfigureAwait(false);
}
async Task SocketNew(WebSocket webSocket)
{
try
{
var buffer = new byte[1024 * 4];
var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
string message = Encoding.UTF8.GetString(buffer, 0, receiveResult.Count);
Console.WriteLine("Ответ от сокета " + message + $" Поток: {Thread.CurrentThread.ManagedThreadId}");
if (message != "")
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed", CancellationToken.None);
return;
}
receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
}
catch (Exception ex)
{
Console.WriteLine("Ошибка при получение ответа");
}
}
Ошибка Ошибка подключения System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Net.Http.HttpRequestException: Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение. (localhost:5001) ---> System.Net.Sockets.SocketException (10061): Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение. at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketErr or error, CancellationToken cancellationToken) at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.S ources.IValueTaskSource.GetResult(Int16 token) at System.Net.Sockets.Socket.g__WaitForConnectWithCancellation|277_0( AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken) --- End of inner exception stack trace --- at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessag e request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request) at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellati onAsync(CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpReq uestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, CancellationToken cancellationToken) at Program.<>c__DisplayClass0_0.<<$>g__Socket|0>d.MoveNext() in D:\Project\Visul studio\Delete2\Delete2\Program.cs:line 43