Stream CopyToAsyn c - обнаружение отключения клиента и установка времени ожидания - PullRequest
0 голосов
/ 16 апреля 2020

Я пишу ConnectionHandler как часть Kestrel. Идея состоит в том, что при подключении клиента ConnectionHandler открывает сокет с другим сервером в сети, получает непрерывный поток данных и перенаправляет их обратно клиенту. Тем временем клиент также может отправлять данные на ConnectionHandler, который последний постоянно пересылает на другой сервер в сети (открытый сокет).

public override async Task OnConnectedAsync(ConnectionContext connection)
{
  TcpClient serverSocket = TcpClient(address, port);
  serverSocket.ReceiveTimeout = 10000;
  serverSocket.SendTimeout = 10000;

  NetworkStream dataStream = serverSocket.GetStream();
  dataStream.ReadTimeout = 10000;
  dataStream.WriteTimeout = 10000;

  Stream clientStreamOut = connection.Transport.Output.AsStream();
  Stream clientStreamIn = connection.Transport.Input.AsStream();

  Task dataTask = Task.Run(async () =>
  {
      try
      {
          await dataStream.CopyToAsync(clientStreamOut);
      }
      catch
      {
          await LogsHelper.Log(logStream, LogsHelper.BROKEN_CLIENT_STREAM);
          return;
      }
  }, connection.ConnectionClosed);

  Task clientTask = Task.Run(async () =>
  {
      try
      {
          await clientStreamIn.CopyToAsync(dataStream);
      }
      catch
      {
          await LogsHelper.Log(logStream, LogsHelper.BROKEN_DATA_STREAM);
          return;
      }
  }, connection.ConnectionClosed);
  await Task.WhenAny(dataTask, clientTask);
}

Я столкнулся с 3 проблемами:

  1. Для сокета с другим сервером я использую TcpClient, а я NetworkStream. Даже если для ReadTimeout и WriteTimeout установлено значение 10 секунд, для TcpClient и NetworkStream открытый сокет ожидает бесконечно, даже если другой сервер в сети не отправляет данные в течение 5 минут. .
  2. Установка таймаута для clientStreamOut и clientStreamIn (e.g: clientStreamIn.ReadTimeout = 10000;) также не удалась, за исключением того, что она не поддерживается для этого конкретного потока. Мне было интересно, можно ли как-то предоставить тайм-аут?
  3. Когда клиент подключается к ConnectionHandler, OnConnectedAsync срабатывает. Проблема с кодом возникает, когда клиент отключается (из-за сбоя сети или по любой другой причине). Иногда обнаруживается отключение клиента, и сеанс завершается, в то время как в других случаях он навсегда зависает, даже если клиент фактически был отключен. Я ожидал, что CopyToAsync выдаст исключение в случае разъединения, так как я предполагаю, что CopyToAsync пытается записать, но это не всегда случай.

connection.ConnectionClosed - это CancellationToken от OnConnectedAsync, я прочитал здесь https://github.com/dotnet/runtime/issues/23207, что его можно использовать в CopyToAsync. Однако я не уверен, как я могу это использовать. Также стоит отметить, что у меня нулевой контроль над клиентским кодом.

Я запускаю приложение, используя Docker

FROM mcr.microsoft.com/dotnet/core/sdk:3.1
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...