Несколько разных соединений блокируются непоследовательноC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Несколько разных соединений блокируются непоследовательно

Сообщение Anonymous »

Я создаю диагностический сервис, который проверяет устройства и сохраняет результаты в файлах .json. У меня проблема с проверкой нескольких устройств одного типа. Одно из них — это устройство, к которому я подключаюсь по ssh, выполняю несколько простых команд (cat, systemctl и т. д.), а другое — устройство, к которому я подключаюсь через веб-сокет и жду первого сообщения, которое должно содержать строку версии.
На моем устройстве (Win 10) и Debian мой сервис работает как положено: для каждого устройства я получаю результаты примерно за 1-3 секунды (что нормально для моего случая). Однако на другом устройстве Debian, когда я запускаю свой сервис, я блокируюсь после 10-15 устройств, и мне приходится ждать результатов 30-45 секунд (что нехорошо).
Еще немного информации: все проверяемые устройства настроены одинаково. Разница лишь в том, с какого устройства я проверяю. Все они подключены к одной локальной сети.
Код проверки ssh-устройств:

Код: Выделить всё

DeviceStatus deviceStatus = await base.CheckDevice(cancellationToken);
if (!deviceStatus.Pingable)
return deviceStatus;

using var client = CreateSshClient();
await client.ConnectAsync(cancellationToken);

string? lcdVersion = await GetLcdAppVersion(client, cancellationToken);
deviceStatus.Components.Add(new("LcdApp", true, lcdVersion));

List tasks = new();

foreach (ServiceInfo service in _options.Value.LcdServices)
tasks.Add(Task.Run(async () =>
await GetServiceInfo(deviceStatus, service, cancellationToken, client)));

await Task.WhenAll(tasks);
client.Disconnect();
return deviceStatus;
Код для проверки веб-устройств:

Код: Выделить всё

DeviceStatus deviceStatus = await base.CheckDevice(cancellationToken);
if (!deviceStatus.Pingable)
return deviceStatus;

bool connected = false;
string? version = null;

Stopwatch watch = new();
watch.Start();

string address = "ws://" + _device.device_ip + ":" + (_device.device_port ?? 8882) + "/api";
using var ws = new ClientWebSocket();

try
{
var timedSource = new CancellationTokenSource();
timedSource.CancelAfter(TimeSpan.FromSeconds(5));

var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timedSource.Token);

Task dcTask = Task.Run(async () =>
{
try
{
await Task.Delay(TimeSpan.FromSeconds(10), source.Token);
}
finally
{
if (ws.State == WebSocketState.Open)
{
_logger.LogDebug("{ip}: WebSocket timeout exceeded, disconnecting", _device.device_ip);
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", cancellationToken);
}
if (!source.IsCancellationRequested)
source.Cancel();
}
});

await ws.ConnectAsync(new Uri(address), source.Token);
connected = ws.State == WebSocketState.Open;

if (!connected)
return deviceStatus;

var buffer = new byte[1024];
var result = await ws.ReceiveAsync(new ArraySegment(buffer), source.Token);

if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
//_logger.LogDebug("{ip}: Message received - {message}", _device.device_ip, message);

if (message.Contains("appInfo"))
{
JObject jObject = JObject.Parse(message);
AppInfo appInfo = jObject["appInfo"]!.ToObject()!;
version = appInfo.versionString;
if (version is null && appInfo.version is not null)
{
version = string.Join(".", appInfo.version);
}
}
}

await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", source.Token);
source.Cancel();
}
catch (TaskCanceledException)
{
_logger.LogInformation("{ip} is taking too long to respond", _device.device_ip);
}
catch (OperationCanceledException)
{
_logger.LogInformation("{ip} is taking too long to respond", _device.device_ip);
}
catch (Exception e)
{
if (!e.Message.Contains("close handshake"))
_logger.LogDebug("Error while checking {ip}: {e}", _device.device_ip, e.ToString());
}

deviceStatus.Components.Add(new("WebSocket", connected, version));

return deviceStatus;
ПРИМЕЧАНИЕ
Похоже, что задача отключения не работает все время, похоже, что она ожидает соединения, хотя CancellationTokenSource отменена
Я пробовал добавление задачи отключения, чтобы отменить проверку через 5 секунд. Я также оптимизировал работу с устройствами ssh, чтобы создать для каждого из них только один SshClient и запускать команды на этом одном клиенте. Он работал на первых двух (Win 10 и первом Debian), однако у другого Debian была та же проблема. Я также попробовал установить для ulimit -n значение 4096, но результат не изменился. Еще я пробовал ставить задачи в очередь, например в 5, и когда одна из них выполнена, запускаю следующую. В результате вся очередь остановилась на эти 30-45 секунд, а затем вернулась к проверке каждого устройства в ожидаемое время

Подробнее здесь: https://stackoverflow.com/questions/787 ... nsistantly
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»