Home > OS >  C# TCP Client multiple threading
C# TCP Client multiple threading

Time:12-19

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!

CodePudding user response:

That's not how threads work. A thread runs asynchronously (that's the very purpose of it), hence th_handleClient.Start() returns immediately and the main loop continues to run. Which, in this case, is good, because you want to be able to accept a new connection while the old one is still being used. You need to put your Cleanup code into the handleClient method, eg:

        try
        {
            while (true)
            {
                if (networkstream.DataAvailable == true)
                {
                    // ...
                }
            }
        }
        catch (SocketException x)
        {
            Cleanup(streamData);
        }

Note that your handler thread should probably not update the state of the application, because you don't want to terminate the server after the first client disconnects. (Luckily, appstatus is never set to 2 anywhere in the posted code).

CodePudding user response:

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.

  • Related