Замена Socket.ReceiveAsync с помощью NetworkStream.ReadAsync(ожидаемый)

У меня есть приложение, которое одновременно создает пару сотен TCP-соединений и получает от них постоянный поток данных.

 private void startReceive()
    {
        SocketAsyncEventArgs e = new SocketAsyncEventArgs();
        e.Completed += receiveCompleted;
        e.SetBuffer(new byte[1024], 0, 1024);
        if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }  
    }

    void receiveCompleted(object sender, SocketAsyncEventArgs e)
    {
        ProcessData(e);

        if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
    }

Мои попытки привели к чему-то вроде этого:

private async void StartReceive()
    {
        byte[] Buff = new byte[1024];
        int recv = 0;
        while (Socket.Connected)
        {
            recv = await NetworkStream.ReadAsync(Buff, 0, 1024);
            ProcessData(Buff,recv);
        }
    }

Проблема, с которой я столкнулась, - это метод, вызывающий StartReceive(), который будет блокироваться и не будет входить в сопровождающий StartSend() method called after StartReceive() . Creating a new task for StartReceive() would just end up with 300-ish threads, and it seems to do so just by calling StartReceive() `anyways.

Каким будет правильный метод реализации новых async и await ключевых слов в моем существующем коде при использовании NetworkStream, поэтому используется пул потоков, который Socket.SendAsync() и Socket.ReceiveAsync() используют, чтобы избежать нужно иметь сотни потоков/задач?

Есть ли преимущество в производительности при использовании NetworkStream таким образом через порты завершения ввода/вывода с beginreceive?

Ответ 1

Здесь вы меняете две вещи: асинхронный стиль (SocketAsyncEventArgs до Task/async) и уровень абстракции (Socket to NetworkStream).

Поскольку вам уже удобно работать с Socket, я рекомендую просто изменить асинхронный стиль и продолжить использование класса Socket.

Async CTP не дает Socket любых async -совместимых методов (это странно, я предполагаю, что они были исключены по ошибке и будут добавлены в .NET 4.5).

Не сложно создать собственный метод расширения ReceiveAsyncTask (и аналогичные обертки для других операций), если вы используете мою библиотеку AsyncEx:

public static Task<int> ReceiveAsyncTask(this Socket socket,
    byte[] buffer, int offset, int size)
{
  return AsyncFactory<int>.FromApm(socket.BeginReceive, socket.EndReceive,
      buffer, offset, size, SocketFlags.None);
}

Как только вы это сделаете, ваш StartReceive может быть записан следующим образом:

private async Task StartReceive()
{
  try
  {
    var buffer = new byte[1024];
    while (true)
    {
      var bytesReceived = await socket.ReceiveAsyncTask(buffer, 0, 1024)
          .ConfigureAwait(false);
      ProcessData(buffer, bytesReceived);
    }
  }
  catch (Exception ex)
  {
    // Handle errors here
  }
}

Теперь, чтобы устранить многие незначительные моменты: