Вопрос о прослушивании и отставании для сокетов - PullRequest
7 голосов
/ 23 ноября 2010

Я пишу приложение на C #, которое должно обрабатывать входящие соединения, и я никогда раньше не занимался программированием на стороне сервера.Это приводит меня к следующим вопросам:

  • Плюсы и минусы высокого отставания / низкого отставания?Почему бы нам не установить огромное количество невыполненных заданий?
  • Если я вызываю Socket.Listen (10), после 10 Accept () я должен снова вызывать Listen ()?Или я должен вызывать Listen () после каждого Accept ()?
  • Если я установлю свой backlog равным 0 и гипотетически два человека захотят подключиться к моему серверу одновременно, что произойдет?(Я вызываю Socket.Select в цикле и проверяю читаемость сокета прослушивания, после того, как я обработаю первое соединение, будет ли второе соединение успешным после следующей итерации, если я снова вызову Listen ()?)

Заранее спасибо.

Ответы [ 3 ]

19 голосов
/ 23 ноября 2010

Журнал ожидания прослушивания - , как сказал Питер , - очередь, которая используется операционной системой для хранения соединений, которые были приняты стеком TCP, но еще не приняты вашей программой. Концептуально, когда клиент подключается, он помещается в эту очередь, пока ваш код Accept() не удалит его и не передаст вашей программе.

Таким образом, журнал ожидания прослушивания является параметром настройки, который может использоваться, чтобы помочь вашему серверу обрабатывать пики при одновременных попытках подключения. Обратите внимание, что это связано с пиками при одновременных попытках подключения и никоим образом не связано с максимальным количеством одновременных подключений, которое может поддерживать ваш сервер. Например, если у вас есть сервер, который получает 10 новых подключений в секунду, то маловероятно, что настройка невыполненных запросов на прослушивание окажет какое-либо влияние, даже если эти подключения являются долгоживущими, а ваш сервер поддерживает 10 000 одновременных подключений (при условии, что ваш сервер не работает на максимальном уровне) из процессора, обслуживающего существующие соединения!). Однако, если сервер периодически испытывает короткие периоды, когда он принимает 1000 новых подключений в секунду, вы, вероятно, можете предотвратить отклонение некоторых подключений, настроив журнал ожидания прослушивания, чтобы обеспечить большую очередь и, следовательно, дать вашему серверу больше времени для вызова Accept() за каждое соединение.

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

Лично я создаю прослушивание, которое можно настроить внешне через файл конфигурации.

Как и когда вы вызываете listen и accept, зависит от стиля кода сокетов, который вы используете. В синхронном коде вы вызывали бы Listen() один раз со значением, скажем, 10, для своего журнала ожидания прослушивания, а затем вызывали цикл Accept(). Призыв к прослушиванию устанавливает конечную точку, к которой ваши клиенты могут подключиться, и концептуально создает очередь невыполненных заданий прослушивания указанного размера. Вызов Accept() удаляет ожидающее соединение из очереди прослушивания, настраивает сокет для использования приложения и передает его в ваш код как вновь установленное соединение. Если время, необходимое вашему коду для вызова Accept(), обработайте новое соединение и повторите цикл для повторного вызова Accept() дольше, чем разрыв между одновременными попытками подключения, тогда вы начнете накапливать записи в очереди ожидания ожидания.

В случае асинхронных сокетов все может быть немного по-другому, если вы используете асинхронный прием, вы будете прослушивать один раз, как и раньше, а затем публиковать несколько (снова настраиваемых) асинхронных приемов. По завершении каждого из них вы обрабатываете новое соединение и публикуете новое асинхронное подтверждение. Таким образом, у вас есть очередь прослушивания невыполненных заданий и ожидающая принятия очередь, поэтому вы можете принимать соединения быстрее (более того, асинхронные приемы обрабатываются в потоках пула потоков, поэтому у вас нет единого жесткого цикла принятия). Обычно это более масштабируемо и дает две точки для настройки для обработки большего количества одновременных попыток подключения.

3 голосов
/ 23 ноября 2010

Бэклог обеспечивает выделение очереди для клиентов, которые пытаются подключиться к серверу, но вы еще не обработали.

Это касается времени между тем, когда клиент фактически подключается к серверу, и временем, когда вы Accept или EndAccept клиенте.

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

По поводу ваших вопросов:

  1. У меня нет информации об этом. Если номер по умолчанию не создает проблем (нет отклоненных клиентских подключений), оставьте его по умолчанию. Если вы видите много ошибок, когда новые клиенты хотят подключиться, увеличьте число. Тем не менее, это может быть потому, что вы принимаете слишком много времени для принятия нового клиента. Вы должны решить эту проблему, прежде чем увеличивать отставание;

  2. Нет, это обрабатывается системой. Об этом позаботится обычный механизм приема клиентов;

  3. См. Мое предыдущее объяснение.

2 голосов
/ 29 января 2016

Попробуйте эту программу, и вы увидите, для чего нужно отставание.

using System;
using System.Net;
using System.Net.Sockets;

/*
   This program creates TCP server socket. Then a large number of clients tries to connect it.
   Server counts connected clients. The number of successfully connected clients depends on the BACKLOG_SIZE parameter.
 */


namespace BacklogTest
{
    class Program
    {
        private const int BACKLOG_SIZE = 0; //<<< Change this to 10, 20 ... 100 and see what happens!!!!
        private const int PORT = 12345;
        private const int maxClients = 100;

        private static Socket serverSocket;
        private static int clientCounter = 0;

        private static void AcceptCallback(IAsyncResult ar)
        {
            // Get the socket that handles the client request
            Socket listener = (Socket) ar.AsyncState;
            listener.EndAccept(ar);
            ++clientCounter;
            Console.WriteLine("Connected clients count: " + clientCounter.ToString() + " of " + maxClients.ToString());

            // do other some work
            for (int i = 0; i < 100000; ++i)
            {
            }

            listener.BeginAccept(AcceptCallback, listener);
        }

        private static void StartServer()
        {
            // Establish the locel endpoint for the socket
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, PORT);

            // Create a TCP/IP socket
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen
            serverSocket.Bind(localEndPoint);
            serverSocket.Listen(BACKLOG_SIZE);
            serverSocket.BeginAccept(AcceptCallback, serverSocket);
        }

        static void Main(string[] args)
        {
            StartServer();

            // Clients connect to the server.
            for (int i = 0; i < 100; ++i)
            {
                IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, PORT);

                // Create a TCP/IP socket and connect to the server
                Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                client.BeginConnect(remoteEP, null, null);
            }

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