Search code examples
c#multithreadingtcpstreamnetworkstream

C# TCP Client multiple threading


I have the below script which is listening to accept a TCP client, then sends a command and returns the result (This is just a part of the code).

I believe the issue that I am facing is in relation to threading...
When Client connects all is good, but if the client disconnects I want the Cleanup(); exception to run, meaning I want the connection to disconnect, update the status and start listening again.

THE CODE:

private void Form1_Load(object sender, EventArgs e)
        {
            th_StartListen = new Thread(new ThreadStart(StartListen));
            th_StartListen.Start();
            txtCmdOutput.Focus();
        }

        private void StartListen()
        {
            //Creating a TCP Connection and listening to the port
            tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
            tcpListener.Start();
            toolStripStatusLabel1.Text = "Listening on port 6666 ...";
            int counter = 0;
            appStatus = 0;

            while (appStatus != 2)
            {
                try
                {
                    client = tcpListener.AcceptTcpClient();
                    counter++;
                    clientList.Add(client);
                    IPEndPoint ipend = (IPEndPoint)client.Client.RemoteEndPoint;
                    //Updating status of connection
                    toolStripStatusLabel1.Text = "Connected from "+ IPAddress.Parse(ipend.Address.ToString());
                    appStatus = 1;
                    th_handleClient = new Thread(delegate () { handleClient(client, counter); });
                    th_handleClient.Start();
                    
                }
                catch (Exception err)
                {
                    {
                        Cleanup();
                    }
                }
            }
        }

        private void handleClient(object client, int i)
        {
            TcpClient streamData = (TcpClient)client;
            byte[] data = new byte[4096];
            byte[] sendData = new byte[4096];
            int byteRead;
            string strdata;
            ASCIIEncoding encode = new ASCIIEncoding();
            Thread.Sleep(2000);
            NetworkStream networkstream = streamData.GetStream();
            //Send Command 1
            sendData = encode.GetBytes("1");
            networkstream.Write(sendData, 0, sendData.Length);
            networkstream.Flush();

            //Retrieving and filtering data
            while (true)
            {
                if (networkstream.DataAvailable == true)
                {
                    
                    byteRead = 1;
                    Debug.WriteLine(byteRead);
                    byteRead = networkstream.Read(data, 0, 4096);
                    Debug.WriteLine(byteRead);
                    strdata = Encoding.ASCII.GetString(data, 0, byteRead);

                    //Get user info
                    if (strdata.StartsWith("1"))
                    {
                        updateLabel(labelMachinename, strdata,0);
                        updateLabel(labelSampleOutput, strdata, 1);
                    }
                    if (strdata.StartsWith("2"))
                    {
                        updateText(txtCmdConsole, strdata);
                    }
                }
            }
        }

THE CLEANUP FUNCTION:

private void Cleanup()
            {
                try
                {
                    networkStream.Close();
                    toolStripStatusLabel1.Text = "Connection Lost";
                }
                catch (Exception err) { }
                
            }

The thing is that the script gets stuck in this loop:

while (true)
            {
                if (networkstream.DataAvailable == true)
                {
                    
                    byteRead = 1;
                    Debug.WriteLine(byteRead);
                    byteRead = networkstream.Read(data, 0, 4096);
                    Debug.WriteLine(byteRead);
                    strdata = Encoding.ASCII.GetString(data, 0, byteRead);

                    //Get user info
                    if (strdata.StartsWith("1"))
                    {
                        updateLabel(labelMachinename, strdata,0);
                        updateLabel(labelSampleOutput, strdata, 1);
                    }
                    if (strdata.StartsWith("2"))
                    {
                        updateText(txtCmdConsole, strdata);
                    }
                }
            }

Because the if statement is not met.

It was my understanding that If I created two threads, th_StartListen and th_handleClient that the listening thread would keep running independently and catch the exception when there is no connection?

while (appStatus != 2)
            {
                try
                {
                    client = tcpListener.AcceptTcpClient();
                    counter++;
                    clientList.Add(client);
                    IPEndPoint ipend = (IPEndPoint)client.Client.RemoteEndPoint;
                    //Updating status of connection
                    toolStripStatusLabel1.Text = "Connected from "+ IPAddress.Parse(ipend.Address.ToString());
                    appStatus = 1;
                    th_handleClient = new Thread(delegate () { handleClient(client, counter); });
                    th_handleClient.Start();
                    
                }
                catch (Exception err)
                {
                    {
                        Cleanup();
                    }
                }
            }

I hope someone can help me with figuring this one out... and hope the code is understandable.

Free to ask me any questions or to share more information!


Solution

  • Thanks PMF for the explanation:

    This seemed to work for me:

    private void handleClient(object client, int i)
            {
                try
                {
                    TcpClient streamData = (TcpClient)client;
                    byte[] data = new byte[4096];
                    byte[] sendData = new byte[4096];
                    int byteRead;
                    string strdata;
                    ASCIIEncoding encode = new ASCIIEncoding();
                    Thread.Sleep(2000);
                    NetworkStream networkstream = streamData.GetStream();
                    //Send Command 1
                    sendData = encode.GetBytes("1");
                    networkstream.Write(sendData, 0, sendData.Length);
                    networkstream.Flush();
                    //Listen...
                    while (true)
                    {
                        
                        byteRead = 1;
                        byteRead = networkstream.Read(data, 0, 4096);
    
                        if (networkstream.DataAvailable != true)
                        {
    
                            
                            //Debug.WriteLine(byteRead);
                            strdata = Encoding.ASCII.GetString(data, 0, byteRead);
    
                            //Get user info
                            if (strdata.StartsWith("1"))
                            {
                                updateLabel(labelMachinename, strdata, 0);
                                updateLabel(labelSampleOutput, strdata, 1);
                            }
                            if (strdata.StartsWith("2"))
                            {
                                updateText(txtCmdConsole, strdata);
                            }
                        }
                    }
                }
                catch (Exception err)
                {
                    {
                        Cleanup();
    
                    }
                }
    
            }
    

    I added a try and while loop and just put a variable that would throw an exception byteRead = networkstream.Read(data, 0, 4096); to throw in the error.