代码之家  ›  专栏  ›  技术社区  ›  Marlon

关于套接字的侦听和backlog的问题

  •  7
  • Marlon  · 技术社区  · 15 年前

    我正在用C语言编写一个需要处理传入连接的应用程序,我以前从未做过服务器端编程。这就引出了以下问题:

    • 高积压/低积压的利弊?我们为什么不把积压的数量定得很大呢?
    • 如果我调用Socket.Listen(10),在10个Accept()s之后,我必须再次调用Listen()吗?还是每次Accept()之后都要调用Listen()?
    • 如果我将backlog设置为0,假设两个人同时要连接到我的服务器,会发生什么情况?(我正在调用Socket.Select in a loop并检查侦听套接字的可读性,在我处理完第一个连接之后,如果我再次调用Listen()的话,在下一次迭代中第二个连接是否会成功?)

    提前谢谢。

    3 回复  |  直到 15 年前
        1
  •  19
  •   Community Mohan Dere    9 年前

    监听积压是, as Pieter said ,操作系统用来存储已被TCP堆栈接受但尚未被程序接受的连接的队列。从概念上讲,当一个客户机连接时,它被放在这个队列中,直到 Accept() 代码移除它并将其交给程序。

    因此,listen backlog是一个可用于帮助服务器处理并发连接尝试高峰的优化参数。请注意,这与并发连接尝试中的峰值有关,并且与服务器可以维护的最大并发连接数无关。例如,如果您有一个服务器,每秒接收10个新的连接,那么即使在长时间使用这些连接并且服务器支持10000个并发连接(假设您的服务器不在为现有连接服务的CPU上注销)的情况下,调整监听积压也不太可能有任何影响。。但是,如果服务器在每秒接受1000个新连接时偶尔遇到短时间问题,则可以通过调整侦听积压以提供更大的队列,从而为服务器提供更多的调用时间,从而防止某些连接被拒绝 接受() 对于每个连接。

    至于优点和缺点,优点是可以更好地处理并发连接尝试中的峰值,相应的缺点是操作系统需要为侦听积压队列分配更多空间,因为它更大。所以这是一个性能与资源的权衡。

    就我个人而言,我使监听积压可以通过配置文件进行外部调整。

    如何以及何时调用listen和accept取决于所使用的套接字代码的样式。用你会调用的同步代码 Listen() 一次使用一个值,比如10,表示您的侦听待办事项,然后循环调用 接受() . listen调用设置客户端可以连接的端点,并在概念上创建指定大小的listen backlog队列。打电话 接受() 从侦听积压队列中移除挂起的连接,设置应用程序使用的套接字,并将其作为新建立的连接传递给代码。如果代码调用 接受() ,处理新连接,并循环调用 接受() 再次超过并发连接尝试之间的间隔,然后您将开始在侦听积压队列中累积条目。

    对于异步套接字,它可能有点不同,如果您使用async-accepts,您将像以前一样监听一次,然后发布几个(同样可配置的)async-accepts。当其中每一个完成时,您将处理新连接并发布一个新的异步接受。通过这种方式,您有一个侦听积压队列和一个挂起的接受“队列”,因此您可以更快地接受连接(此外,异步接受是在线程池线程上处理的,因此您没有一个紧密的接受循环)。这通常更具可伸缩性,并为您提供了两个调整点,以处理更多并发连接尝试。

        2
  •  3
  •   Pieter van Ginkel    15 年前

    backlog所做的是为试图连接到服务器但尚未处理的客户机提供一个队列。

    这关系到客户机实际连接到服务器和您 Accept 或 EndAccept 客户。

    如果接受客户机需要很长时间,则可能积压工作已满,新的客户机连接将被拒绝,直到您有时间处理队列中的客户机。

    关于你的问题:

    1. 我没有这方面的信息。如果默认号码没有造成任何问题(没有被拒绝的客户端连接),请将其保留为默认号码。如果在新客户端要连接时看到许多错误,请增加该数字。然而,这可能是因为你花了太多时间来接受一个新客户。你应该在增加积压之前解决这个问题;

    2. 不,这是由系统处理的。接受客户的正常机制负责这一点;

    3. 看我之前的解释。

        3
  •  3
  •   ifs    10 年前

    试试这个程序,你会发现什么是积压好。

    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();
            }
        }
    }
    
    推荐文章