Программирование .NET TcpSocket - PullRequest
4 голосов
/ 17 апреля 2011

Как правильно принимать сокеты в среде с несколькими подключениями в .NET? Хватит ли следующего, даже если нагрузка высокая?

while (true)
{
   //block untill socket accepted
   var socket = tcpListener.AcceptSocket();
   DoStuff(socket) //e.g. spawn thread and read data
}

То есть я могу принимать сокеты в одном потоке, а затем обрабатывать сокеты в потоке / потоке данных / что угодно. Так что вопрос только в части принятия ..

Ответы [ 7 ]

1 голос
/ 17 апреля 2011

Посмотрите на шаблон Reactor или Proactor в зависимости от того, хотите ли вы блокировать или нет. Я рекомендую книгу Patterns для параллельных и сетевых объектов .

1 голос
/ 17 апреля 2011

Возможно, вы захотите асинхронную операцию BeginAccept вместо синхронного принятия.

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

0 голосов
/ 18 апреля 2011

Поскольку я использую Async CTP и DataFlow, текущий код выглядит следующим образом:

private async void WaitForSockets()
{
    var socket = await tcpListener.AcceptSocketAsync();
    WaitForSockets();
    incomingSockets.Post(socket);
}

Обратите внимание, что то, что выглядит как рекурсивный вызов, не приведет к переполнению стека или блокировке. Он просто запустит нового ожидающего нового сокета и завершит работу.

0 голосов
/ 18 апреля 2011

Это не имеет большого значения для производительности.Важно то, как вы общаетесь с каждым клиентом.Такая обработка потребляет намного больше ресурсов ЦП, чем прием сокетов.

Я бы использовал BeginAccept / EndAccept для сокета слушателя И BeginReceive / EndReceive для сокетов клиента.

0 голосов
/ 17 апреля 2011

Я думаю, что лучший подход - это вызвать BeginAccept (), а в OnAccept снова вызвать BeginAccept. Это должно дать вам лучший параллелизм.

OnAccept должен выглядеть примерно так:

private void OnAccept(IAsyncResult ar)
{
   bool beginAcceptCalled = false;
   try
   {
       //start the listener again
       _listener.BeginAcceptSocket(OnAccept, null);
       beginAcceptCalled = true;
       Socket socket = _listener.EndAcceptSocket(ar);
       //do something with the socket..
   }
   catch (Exception ex)
   {
       if (!beginAcceptCalled)
       {
          //try listening to connections again
          _listener.BeginAcceptSocket(OnAccept, null);
        }
    }
}
0 голосов
/ 17 апреля 2011

BeginAcceptSocket - лучший выбор, если вы хотите самый производительный сервер.

Что еще более важно, эти асинхронные операции используют Threadpool под капотом, в то время как в текущей реализации вы создаете и уничтожаете множество потоков, что действительно дорого.

0 голосов
/ 17 апреля 2011

Это должно быть хорошо, но если нагрузка становится еще выше, вы можете рассмотреть возможность использования асинхронных версий этого метода: BeginAcceptSocket / EndAcceptSocket .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...