derHugo
derHugo

Reputation: 90570

TCP Client stalled until disconnected by the server

When trying to receive a string or file content (as string) via TCP I am stuck with an issue wher the receiving works in general, but the line

print("TCP -> Data received:\n" + file + "\n\n" + totalrecbytes + " Bytes");

is kind of stalled until I activelly disconnect from the server side. Than it works as expected.

I debugged and receiving the data inside the

while ((recBytes = netstream.Read(bytes, 0, bytes.Length)) > 0)

loop works just fine. It also ends the loop in the correct moment. But after that simply nothing happens. I get no errors, am not "trapped" in any loop but also do not get the expected output of

print("TCP -> Data received:\n" + file + "\n\n" + totalrecbytes + " Bytes");

until I disconnect from the server side. Than I see the expected output and the client is disconnected.

Here is the implementation (original source)

private Thread _tcpThread;
private TcpClient _socketConnection;

public void Connect()
{
    try
    {
        _tcpThread = new Thread(ReciveDataClient);
        _tcpThread.IsBackground = true;
        _tcpThread.Start();
    }
    catch (Exception e)
    {
        print(e.Message);
    }
}

private void ReciveDataClient()
{
    try
    {
        _socketConnection = new TcpClient("xxx.xxx.xxx.xxx", 54321);
        print(this, "TCP -> Connection Success!");
    }
    catch (Exception e)
    {
        print("connection error: " + e.Message)
        return;
    }

    try
    {
        var bytes = new byte[BUFFER_SIZE];

        while (_socketConnection.Connected)
        {
            if (_socketConnection.Available <= 0) continue;

            // Get a stream object for reading              
            var netstream = _socketConnection.GetStream();

            int totalrecbytes = 0;

            int recBytes;
            string file = "";

            // Read incomming stream into byte arrary.                  
            while ((recBytes = netstream.Read(bytes, 0, bytes.Length)) > 0)
            {
                var incommingData = new byte[recBytes];
                Array.Copy(bytes, 0, incommingData, 0, recBytes);
                // Convert byte array to string message.                        
                var serverMessage = Encoding.ASCII.GetString(incommingData);
                file += serverMessage;
                totalrecbytes += recBytes;
            }

            print("TCP -> Data received:\n" + file + "\n\n" + totalrecbytes + " Bytes");

            netstream.Close();
        }

        print("TCP -> connection was terminated by the server");
    }
    catch (Exception e)
    {
        print(e.Message)
        return;
    }
}

I would expect that I can maintain the connection alive but still receive the data correctly and communicate with the server on a persistent TCP connection.

What am I missing or doing wrong here?


The only workarround I could find so far is allways disconnect from the server side after sending data and in my code wrap the whole ReceiveDataClient in a while loop like

private void ReciveDataClient()
{
    while (true)
    {
        try
        {
            _socketConnection = new TcpClient(_server.ToString(), _server.Port);

            //...

in order to immediately start a new connection after the server sent some data and disconnected the client.

Upvotes: 1

Views: 266

Answers (1)

derHugo
derHugo

Reputation: 90570

Thanks to the help of Damien_The_Unbeliever and Immersive I could figure it out. It really helps to read the docs from time to time especially if it is the first time you use something ^^

NetworkStream.Read is a blocking call and as the doc states

returns: The number of bytes read from the NetworkStream, or 0 if the socket is closed.

so ofcourse the while loop actually never terminated.


So adopting the example provided there worked for me except that if the server ended the connection I got another issue so instead of checking for _socketConnection.IsConnected I used the marked answer from this post so all together this works for me now

private Thread _tcpThread;
private TcpClient _socketConnection;

public void Connect()
{
    if(_socketConnection != null) return;

    try
    {
        _tcpThread = new Thread(ReciveDataClient);
        _tcpThread.IsBackground = true;
        _tcpThread.Start();
    }
    catch (Exception e)
    {
        print("TCP -> Thread error: " + e.Message);
    }
}

public void Disconnect()
{
    if(_socketConnection = null) return;

    _tcpThread.Abort();
}

private void ReciveDataClient()
{
    try
    {
        _socketConnection = new TcpClient("xxx.xxx.xxx.xxx", 54321);
        print(this, "TCP -> Connection Success!");
    }
    catch (Exception e)
    {
        print("TCP -> connection error: " + e.Message)
        return;
    }

    try
    {
        while(true)
        {
            // Get a stream object for reading              
            var netstream = _socketConnection.GetStream();

            //Check if still connected                
            if(_socketConnection.Client.Poll(0, SelectMode.SelectRead))
            {
                byte[] buff = new byte[1];
                if( _socketConnection.Client.Receive( buff, SocketFlags.Peek ) == 0 )
                {
                    // Server disconnected or connection lost
                    break;
                }
            }

            // Check to see if this NetworkStream is readable.
            if(myNetworkStream.CanRead)
            {
                byte[] myReadBuffer = new byte[BUFFER_SIZE];
                StringBuilder myCompleteMessage = new StringBuilder();
                int numberOfBytesRead = 0;
                int totalBytesReceived = 0;

                // Incoming message may be larger than the buffer size.
                do
                {
                    numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);
                    myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));    
                    totalBytesReceived += numberOfBytesRead;        
                }
                while(myNetworkStream.DataAvailable);

                // Print out the received message to the console.
                print("TCP -> Data received:\n" + myCompleteMessage.ToString() + "\n\n" + totalrecbytes + " Bytes");
            }
            else
            {
                //Prevent a direct loop
                Thread.Sleep(100);
            }          
        }

        print("TCP -> connection was terminated by the server");
    }
    catch(ThreadAbortException)
    {
        print("TCP -> Disconnected");
    }
    catch(Exception e)
    {
        print(e.Message)
    }

    // Clean up
    _socketConnection?.Close();
    _socketConnection?.Dispose();
    _socketConnection = null;
}

Upvotes: 1

Related Questions