C# Socket.receive continuously receives 0 bytes and does not block in the loop

Ashish picture Ashish · Oct 7, 2013 · Viewed 7.8k times · Source

I am trying to write a simplest multithreaded TCP server in C#, which receives the data from multiple clients.

Every time a new client is connected, the socket connection is established and the socket is passed as an argument to the new class function, after that the while loop runs and receives the data till the client is connected.

The problem here is that the "socket.receive" is not blocking and receives 0 bytes of data. So the loop runs continuously, without blocking at socket.receive ("clientSocket.Receive(bb)" in the code.).

I am using Chrome browser as a client for testing. Even if I use any other client, the behavior of the TCP server remains the same.

The client sends the data only once but server continuously receives 0 bytes and while loop keeps on running.

I am pasting the Server output for reference.

Please help in blocking the Server at socket.receive to wait for next client transmission. The strange thing is that even if 0 bytes are received, the exception is also not called.

Please help.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
Threading;
using System.Timers;
using System.Security;
using System.Security.Permissions;
namespace SERVER
{
    static class Constants
    {
        public const int port = 8080;
        public const int buffer_size = 512;


    }
    class Program
    {
        static public string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
            //return ip;
        }

        static void Main(string[] args)
        {
            //IPEndPoint ipObj = new IPEndPoint(IPAddress.Parse("Server IP goes here"), 20487); //20487 is port. you can change it according to your wish
            System.Net.IPAddress IP = IPAddress.Any;
            int port = Constants.port;
            TcpListener listnerObj = new TcpListener(IP, port);
            listnerObj.Start();
            string client_addr;
            string[] client_addr_split;
            string IP_string = LocalIPAddress();

            Console.WriteLine("Server Started on {0}:{1}", IP_string, port);
            while (true)
            {
                Console.WriteLine("================================");
                Console.WriteLine("**    Waiting For Client     **");
                Socket clientSocket = listnerObj.AcceptSocket(); // waiting for the client to connect

                client_addr = clientSocket.RemoteEndPoint.ToString();
                client_addr_split = client_addr.Split(':');
                client_addr = client_addr_split[0];

                Console.WriteLine("Client Connected {0}", client_addr);
                ParameterizedThreadStart thread = delegate { new communication().doCommunicate(clientSocket, client_addr); };
                Thread th = new Thread(thread);
                th.Start(); // start the thread here 
            }
        }

        class communication
        {
            public int byteReceived;
            public byte[] bb;
            public void doCommunicate(Socket clientSocket, string client_addr)
            {
                clientSocket.Blocking = true;
                bb = new byte[Constants.buffer_size];

                //Console.WriteLine("***** Entered DoCommunicate *****");
                while (clientSocket.Connected)
                {
                    //Console.WriteLine("Entered While");
                    try
                    {
                        //Console.WriteLine("Entered TRY");
                        Console.WriteLine("Waiting to recieve Data from IP : client_addr");
                        //int ReceivedDataLength = Client.Receive(ReceivedBytes, 0, ReceivedBytes.Length, SocketFlags.None);
                        byteReceived = clientSocket.Receive(bb, 0, bb.Length, SocketFlags.None);
                        //byteReceived = clientSocket.Receive(bb);
                    }
                    catch (SocketException e)
                    {
                        Console.WriteLine("Error: Socket Exception.\n{0}\n{1}.", e.Message, e.ErrorCode);
                        break;
                    }
                    catch (ArgumentNullException e)
                    {
                        Console.WriteLine("Error : Argument Null Exception.\n{0}", e.Message);
                        break;
                    }
                    catch (ObjectDisposedException e)
                    {
                        Console.WriteLine("Error : Socket Disposed Exception Caught.\n{0}", e.Message);
                        break;
                    }
                    catch (SecurityException e)
                    {
                        Console.WriteLine("Error: Security Exception.\n{0}", e.Message);
                        break;
                    }
                    //clientSocketglobal.Send(Encoding.Default.GetBytes("Hello Client"), SocketFlags.None);
                    Console.WriteLineWriteLine("Received Byte count : {0}, from IP : {1}", byteReceived, client_addr); // Do whatever you want to do with the data recieved. Parsing and storing etc.
                    Console.WriteLine(Encoding.UTF8.GetString(bb));
                }
                //Console.WriteLine("While Loop Exited");
                Console.WriteLine("Socked and Class Object  Disposed");
                clientSocket.Close();
                clientSocket.Dispose();
                GC.Collect();
            }
        }
    }
}

OUTPUT Of server :

Server Started on 10.0.0.2:8080
================================
**    Waiting For Client     **
Client Connected 10.0.0.2
================================
**    Waiting For Client     **
Client Connected 10.0.0.2
================================
**    Waiting For Client     **
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 386, from IP : 10.0.0.2
GET /HelloWorld HTTP/1.1
Host: 10.0.0.2:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6


Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2

Answer

Marc Gravell picture Marc Gravell · Oct 7, 2013

If you received 0 bytes, that usually means the sender has closed their send socket. In a Socket, the send and receive channels are separate; I expect what is happening is that your send (their receive) is still open and available, hence clientSocket.Connected returning true (you can still send them a reply), but: they closed their send (your receive) as soon as they sent their payload (this is common, to indicate the end of a batch). Basically, you just need to detect the 0-byte receive, and treat that as the end: no more data will ever be incoming once you have had a non-positive reply from receive. So just write any response you need to write (they can still be listening, even though they will never speak again), and shutdown the socket.

As a side note: in HTTP/1.1 with Connection: keep-alive, the can keep their socket open ready to send the next request - but it just looks like in this case, they simply didn't. They closed their socket immediately after issuing the request. Which is fine. Just serve the response and close the socket completely. No more requests will be incoming.