9

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
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ashish
  • 479
  • 3
  • 7
  • 18

1 Answers1

13

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.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks Marc, But if that is the case then why is no exception raised? – Ashish Oct 07 '13 at 09:58
  • 2
    @Ashish why would an exception be raised? You are asking for data, it says "no more data - ever". You then ask it for data: it says "no more data - ever". You then ask it for data: it says "no more data - ever". You then ask it for data: it says "no more data - ever". There is nothing exception worthy here... just: pay attention to the reply. Computers don't get bored of saying "no". – Marc Gravell Oct 07 '13 at 10:04
  • Thanks Marc, I understand.Is there a better way of receiving data? – Ashish Oct 07 '13 at 10:10
  • @Ashish that depends on the scenario. For low volume, that is fine. For higher volume you *might* want to look at the async API (not to be confused with the begin/end API, which is different). – Marc Gravell Oct 07 '13 at 10:11
  • In my case, it was my read buffer being full and its offset being at the end, because my read buffer was smaller than the max size of a message ended with a separator. – Pierre Aug 21 '19 at 01:40