~1 second TcpListener Pending()/AcceptTcpClient()

2020-07-23 05:26发布

问题:

Probably just watch this video: http://screencast.com/t/OWE1OWVkO As you see, the delay between a connection being initiated (via telnet or firefox) and my program first getting word of it.

Here's the code that waits for the connection

    public IDLServer(System.Net.IPAddress addr,int port)
    {
        Listener = new TcpListener(addr, port);

        Listener.Server.NoDelay = true;//I added this just for testing, it has no impact

        Listener.Start();

        ConnectionThread = new Thread(ConnectionListener);
        ConnectionThread.Start();


    }

    private void ConnectionListener()
    {
        while (Running)
        {
            while (Listener.Pending() == false) { System.Threading.Thread.Sleep(1); }//this is the part with the lag
            Console.WriteLine("Client available");//from this point on everything runs perfectly fast 
            TcpClient cl = Listener.AcceptTcpClient(); 

            Thread proct = new Thread(new ParameterizedThreadStart(InstanceHandler));
            proct.Start(cl);


        }

    }

(I was having some trouble getting the code into a code block)

I've tried a couple different things, could it be I'm using TcpClient/Listener instead of a raw Socket object? It's not a mandatory TCP overhead I know, and I've tried running everything in the same thread, etc.

回答1:

Maybe it's some kind of dns resolve? Are you using IP address to access your server's host or some name which is being resolved by your DNS? The code ParmesanCodice gave should work with no delay unless there's something wrong on client/network side.

Try to add following line to your windows\system32\drivers\etc\hosts:

127.0.0.1       localhost

it may solve your problem or just connect as 127.0.0.1:85



回答2:

You should consider accepting your clients asynchronously, this will most likely remove the lag you are seeing.

I've modified your code slightly

public IDLServer(System.Net.IPAddress addr,int port)
{
    Listener = new TcpListener(addr, port);

    Listener.Start();        

    // Use the BeginXXXX Pattern to accept clients asynchronously
    listener.BeginAcceptTcpClient(this.OnAcceptConnection,  listener);
}

private void OnAcceptConnection(IAsyncResult asyn) 
{
    // Get the listener that handles the client request.
    TcpListener listener = (TcpListener) asyn.AsyncState;

    // Get the newly connected TcpClient
    TcpClient client = listener.EndAcceptTcpClient(asyn);

    // Start the client work
    Thread proct = new Thread(new ParameterizedThreadStart(InstanceHandler));
    proct.Start(client);

    // Issue another connect, only do this if you want to handle multiple clients
    listener.BeginAcceptTcpClient(this.OnAcceptConnection,  listener);    
}


回答3:

Doesn't the debugger add overhead ?

I had issues like this when I was building my MMO server. can't remember how I got round it now.

I think this has something to do with resource allocation on services, I use the approach suggested by ParmesanCodice (well a similar one at least) and during testing I found that the first 5 to 10 connections were rubbish but after that the service seems to hammmer out new connections like theres no tomorrow ...

Maybe its a socket thing in the framework.

Have you tried a load test? Throw say 1000 connections at it and see what happens, it should get faster after handling each one.



回答4:

You could avoid the entire Listener.Pending while loop. AcceptTcpClient() is a blocking call so you could just let your code run and pend on that. I don't know why that loop would take 1 second (instead of 1 millisecond) but since you indicate that is where the lag is, you can get rid of it.