Search code examples
c#tcp.net-4.0tcpclientnetworkstream

TCP Server not receiving properly when data is dynamicaly typed


I am working on what should be a simple TCP server application that receives data from a stream and stores it in a list.

I have succeeded in getting the data when it is sent in one message per connection. My problem seems to be when testing it using telnet from the command line. I will start to type and the program will grab one or two characters depending on my typing speed and then won't receive anything from that stream again. I really am at a loss for why. If I put a thread.sleep in the stream.DataAvailable loop then it will get a few more characters but again will stop. Any help is appreciated. My class is as follows:

public class TCPServer
{
    private TcpListener listener;

    public List<string> messages;

    public TCPServer(IPAddress ip, int port)
    {
        try
        {
            messages = new List<string>();

            listener = new TcpListener(ip, port);
            listener.Start();

            listener.BeginAcceptTcpClient(ClientConnected, listener);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }

    private void ClientConnected(IAsyncResult ar)
    {

        TcpClient client;
        try
        {
            client = listener.EndAcceptTcpClient(ar);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
            return;
        }

        try
        {
            NetworkStream stream = client.GetStream();
            string message = "";

            while (!stream.DataAvailable)
            {
            }

            while (stream.DataAvailable)
            {                 
                byte[] readBytes = new byte[65536];
                stream.Read(readBytes, 0, readBytes.Length);
                message += Encoding.ASCII.GetString(readBytes).TrimEnd('\0');
            }

            if (message != null)
            {
                messages.Add(message);
                message = "";
            }
            listener.BeginAcceptTcpClient(ClientConnected, listener);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }

    public void Stop()
    {
        listener.Stop();
    }

}

Solution

  • So I managed to solve this problem by looking more into the NetworkStream class. In the callback from BeginReceiveTcpClient I extracted the network stream from the tcpclient so I could access the BeginReceive async method. The relevant code is below:

     private void ClientConnected(IAsyncResult ar)
        {
            byte[] readBytes = new byte[65536];
    
            TcpClient client;
            try
            {
                client = listener.EndAcceptTcpClient(ar);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
                return;
            }
    
            try
            {
                NetworkStream stream = client.GetStream();
                stream.BeginRead(buffer, 0, buffer.Length, ReadStream, stream);
    
                listener.BeginAcceptTcpClient(ClientConnected, listener);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
            }
        }
    
        private void ReadStream(IAsyncResult ar)
        {
            try
            {
    
                NetworkStream stream = (NetworkStream)ar.AsyncState;
                int bytesRead = stream.EndRead(ar);
    
                content += Encoding.ASCII.GetString(buffer, 0, bytesRead);
                dataProcessor.ProcessData(messages);
                stream.BeginRead(buffer, 0, buffer.Length, ReadStream, stream);
    
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
            }
        }