0

I have a simple client/server chat app I'm building based on a guide. In the client app, there is a method which initiates the connection, then another method (running under a thread) that is actively looking for new messages from the server. This works as expected, however if the connection to the server instance fails (if i kill the server, for example), the client can no longer reconnect because the object

    TcpClient clientSocket = new TcpClient();

is declared globally and cannot be reused for a new connection attempt, as the socket is a one use thing. If it try to reuse it I get an exception that the remote host already closed the connection on this socket.

In order to resolve this, I know that I need to create a new instance of my clientSocket object every time the connection method runs, to avoid having to restart the client after a connection loss event. By creating clientSocket under the connection method rather than globally, it works fine and I'm able to reconnect by running the method again after the connection has been lost, however, I cannot pass this specific object instance (since it was created under my method rather than globally) to my getMessage() listener method, therefore it cannot interact through this socket.

In my understanding there are 2 possible solutions to this:

  • either I reuse the same clientSocket instance over and over again, by Disconnecting and reconnecting it. This did not work, as I don't seem to be able to properly disconnect it and I keep getting the exception that I cannot reconnect to an active socket (which, in reality, has already disconnected as the server got killed). I can .Close() it, but then a new instance cannot be created.

  • or I create a new TcpClient clientSocket instance every time i attempt to connect as mentioned above, which seems to be the way to go, but I cannot make my getMessage method see and use this specific instance. If i recreate the instance inside getMessage obviously it would not work as that instance is not connected.

In short, I would need my method to interact with a specific object instance that was made under a different method's scope. Or any other solutions which allows me to reuse/recreate the same socket in my code. I'm happy to answer any questions if the code isn't clear.

Full client code:

    public partial class Form1 : Form
    {  
        TcpClient clientSocket = new TcpClient(); // im declaring this globally here, this way both methods can see it but i cannot reuse it after a connection loss

        NetworkStream serverStream = default(NetworkStream);

        string readData = null;
        bool connect = true;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {                
            byte[] outStream = Encoding.ASCII.GetBytes(textBox2.Text + "$");
            serverStream.Write(outStream, 0, outStream.Length);
            serverStream.Flush();
        }

        //This method initiates the connection
        public void button2_Click(object sender, EventArgs e)
        {    
            // i COULD create the TcpClient clientSocket instance here instead, but this way getMessage() will not be able to see it
            connect = true;

            try {

                string ip = ipBox.Text;
                int port = Convert.ToInt32(portBox.Text);
                readData = "Connected";

                clientSocket.Connect(ip, port);
                serverStream = clientSocket.GetStream();

                byte[] outStream = Encoding.ASCII.GetBytes(textBox3.Text + "$");
                serverStream.Write(outStream, 0, outStream.Length);
                serverStream.Flush();
                msg();

                Thread ctThread = new Thread(getMessage);
                ctThread.Start();
            }    
            catch
            {
                MessageBox.Show("Connection failed, cannot reach host");    
            }
            }

        // This method is being ran under a thread to keep looking for messages
        private void getMessage()
        {
            while (connect == true)
            {
                serverStream = clientSocket.GetStream();
                int buffSize = 0;
                byte[] inStream = new byte[10025];
                buffSize = clientSocket.ReceiveBufferSize;

                try
                {
                    serverStream.Read(inStream, 0, buffSize);
                }
                catch
                {    
                    MessageBox.Show("Connection lost, server stopped responding");
                    connect = false;
                }

                string returndata = Encoding.ASCII.GetString(inStream);
                readData = "" + returndata;
                msg();
            }    
        }
        private void msg()
        {
            if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(msg));
            else
                textBox1.Text = textBox1.Text + Environment.NewLine + " >> " + readData;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ipBox.Text = "xx.xx.xx.xx";
            portBox.Text = "8888";
            textBox3.Text = Environment.UserDomainName + "//" + Environment.UserName;
        }
    }

Any help is appreciated, I went through countless questions and articles and couldn't find an answer to this.

kenyér
  • 11
  • 2
  • In the future, please remove all the empty lines to reduce scrolling. –  Feb 13 '18 at 16:53
  • Your issue is with connect = true? If the server is shutdown connect is never going to false and then you are stuck in the while loop. You need to capture the End Event Async so you can set connect = false. – jdweng Feb 13 '18 at 17:04
  • No, connect is fine. The issue is with reconnecting the socket. I cannot reuse the same socket, and I can only recreate the object instance if I put it in my method that initiates the connection. If I do that, however, then my second method cannot interact with that specific instance due to scope limitation. I'm looking for a solution to this. – kenyér Feb 14 '18 at 09:02

0 Answers0