views:

71

answers:

2

I had a problem with too many connections After a few test i deducted the problem is with MY server. The fact that the server listening port was on the left side should have told me.

When running the same client code using a server on a different machine i dont get hundreds of ports opened. When my server on my local machine i get > 200 connects connecting to my listening port. I think i am handling clients wrong. My code is below with all non server and client code removed

{
    TcpListener server = null;
    server = new TcpListener(port);
    server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    server.Start();

    while (true)
    {
        var client = server.AcceptTcpClient();
        using(var stream = client.GetStream()) {
        ...
        stream.Read(...
        ...
        stream.Write(...
        } //using above should close this.
        client.Close();
    }
    server.Stop();
}

I modified the code to use asynchronous connections and it locks up the 2nd time it does stream.Read just under the while (client.Connected)

    server = new TcpListener(port);
    server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    server.Start();
    server.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), server);
    while (true)
        Thread.Sleep(1000); //infinite loop for testing




public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
    Byte[] bytes = new Byte[1024 * 4];
    TcpListener listener = (TcpListener)ar.AsyncState;
    using (TcpClient client = listener.EndAcceptTcpClient(ar))
    {
        using (var stream = client.GetStream())
        using (var ostream = new MemoryStream())
        {
            while (client.Connected)
            {
                int i;
                while ((i = stream.Read(bytes, 0, bytes.Length)) == bytes.Length)
                    ostream.Write(bytes, 0, i);

                ostream.Write(bytes, 0, i);
                szresults = Func(ostream)
                var obuf = Encoding.UTF8.GetBytes(szresults);
                stream.Write(obuf, 0, obuf.Length);
            }
        }
        client.Close();
    }
}
+1  A: 

You're dealing with a connection within the same thread. That means you can only actively process a single connection at a time. The simplest approach is to pass the client to a new thread, and deal with it there.

Now that doesn't scale hugely well - using fully asynchronous operations everywhere will allow you to serve the same number of clients using fewer threads - but in most cases it will work well enough, IME. It's certainly where I'd go next.

Ideally you don't want to create a new OS thread each time - it's probably reasonable to use the system thread pool for this, so the thread can be reused after the connection has been completely handled. There are risks around filling up the OS thread pool, but I suspect that's unlikely to bite you.

Finally, I'd put the TcpClient into a using statement to make sure you dispose of it even if something else fails. Of course, if you're handing it over to another thread it should be that thread which immediately uses a using statement.

Jon Skeet
Oh! its because i am closing the connection! thats why there is so many. Interesting. I think threads will work well but i'll consider using ASync (BeginAcceptTcpClient). I'm surprised. TcpClient does implement disposable but DOESNT implement the dispose function. It looks like i now need to check with F12 rather then .Dis. *writes part 2 below*
acidzombie24
I did a quick test by writing a goto tryAgain and tryAgain: directly under the client.GetStream()) {. The first line of code under that is `while ((i = stream.Read(bytes, 0, bytes.Length)) == bytes.Length)`. Do you have any idea why my code is blocking there? Using tamper data i can see ajax POST request go through my application but stream just blocks. The line before goto is stream.Write(obuf, 0, obuf.Length); I added a flush after that like with no success. Why is this blocking? with a quick test it seems like client doesnt get first response. (it does a post request every second)
acidzombie24
@acidzombie24: It implements `IDisposable` explicitly. You should still be able to use a using statement. I don't really understand your sample code here - could you edit your question with some full code?
Jon Skeet
I attempted to fix this and made it use asynchronous connections. It continues to lock up the 2nd time i read from the stream. Full socket code above.
acidzombie24
It feels like the socket is trying to tell me it should be closed (if i dont close the buffer or socket the client doesnt get my reply and read locks the thread up). So once again i am confused as what i should do. Maybe the server should be overloaded with that many connections/ports? i'll mention again the client is javascript using GM_xmlhttpRequest
acidzombie24
If you're dealing with HTTP then you should *either* have persistent connections but only read as far as the content-length tells you, and *write* a content-length as well, *or* close the connection after each request. It's up to the client to tell you whether or not they want to use persistent connections though. Any reason why you're trying to implement this yourself instead of using `HttpListener` which can do all this for you?
Jon Skeet
Originally i planned an actual client. So i am suppose to close after each request. So what am i to do about netstat and tons of ports TIME_WAIT? Is this perfectly fine? Using TcpListener was a learning experience. I'll be attempting HttpListener to see how my results change. (i think i have a basic understand tcplistener now)
acidzombie24
Yes, TIME_WAIT is fine. But yes, HttpListener is a much better approach in general - you don't want to have to do all the HTTP work yourself.
Jon Skeet
I finished converting to HttpListener. Its kind of interesting. <10lines of code change. The initial request just looked for the first \r\n\r and took the remainder as a json string and added its json reply to the end of a 2 lined html response i found online. It worked perfectly in the browsers i wanted to support. HttpListener was identical except i guess i would have better support for content type. netstat shows me similar request. Consider my question answered. accepted.
acidzombie24
A: 

You need to create threads for each connection and properly close socket using socket.shutdown and socket.close method, As it can be seen in your code that you are not closing socket and directly stopping the server due to which socket remain open.

I would like you to go through this article once. I got help from figure 5 of this article.

You might also get some related issue i faced in this article form here

Shantanu Gupta
The TcpClient is being closed - assuming there are no exceptions - and the stream is being closed too. I'd expect those to shut down the socket appropriately.
Jon Skeet