Вопрос о прослушивании и отставании для сокетов

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

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

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

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

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

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

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

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

    С асинхронными сокетами это может быть немного иначе, если вы используете async accepts, вы будете прослушивать один раз, как и раньше, а затем публиковать несколько (снова настраиваемых) асинхронных подключений. По мере завершения каждого из них вы обрабатываете новое соединение и публикуете новый asynchronous прием. Таким образом, у вас есть очередь на прослушивание в ожидании и ожидающая принимающая «очередь», и поэтому вы можете быстрее принимать соединения (более того, асинхронные принимает на streamи пулов streamов, так что у вас нет единого жесткого цикла принятия). Это, как правило, более масштабируемо и дает вам две точки для настройки, чтобы обрабатывать более параллельные попытки подключения.

    То, что делает backlog, представляет собой очередь с клиентами, которые пытаются подключиться к серверу, но которые вы еще не обработали.

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

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

    Что касается ваших вопросов:

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

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

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

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

     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(); } } }