Search code examples
c#tcptcpclienttcplistener

Different data written to the server are becoming appended to become a single string


N.B. refer to this link.

I wrote this class to be used as a proxy in the server-end and as a client at the client-end.

My current source code is the following:

public class ClientClass : IDisposable
{
    private string Host { get; set; }
    private int Port { get; set; }

    public bool IsConnected { private set;  get; }

    public TcpClient Tcp { get; private set; }

    private System.Net.Sockets.NetworkStream stream;

    public ClientClass()
    {
        IsConnected = false;
    }

    //constructor for server program.
    public ClientClass(TcpListener listener)
    {
        Tcp = listener.AcceptTcpClient();

        Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
        Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;

        IsConnected = true;

        stream = Tcp.GetStream();
    }

    //constructor for client.
    public ClientClass(string host, int port)
    {
        Host = host;
        Port = port;
    }

    public string Read()
    {
        if (IsConnected)
        {
            byte[] buffer = new byte[Tcp.ReceiveBufferSize];//create a byte array
            int bytesRead = stream.Read(buffer, 0, Tcp.ReceiveBufferSize);//read count
            string str = Encoding.ASCII.GetString(buffer, 0, bytesRead);//convert to string
            return str.TrimEnd(new char[] {'\r', '\n'});//remove CR and LF
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public void Write(string str)
    {
        if (IsConnected)
        {
            str = str + Constants.CRLF;// add CR and LF
            byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(str);
            stream.Write(bytesToSend, 0, bytesToSend.Length);
            stream.Flush();
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public bool Connect()
    {
        if (IsConnected == false)
        {
            IsConnected = true;

            Tcp = new TcpClient(Host, Port);

            stream = Tcp.GetStream();

            return true;
        }

        return false;
    }

    public bool Disconnect()
    {
        if (IsConnected)
        {
            if (Tcp != null)
            {
                //stream.Flush();
                stream.Close();
                //Tcp.GetStream().Flush();
                //Tcp.GetStream().Close();
                Tcp.Close();

                return true;
            }
        }

        return false;
    }

    #region dispose pattern
    // Flag: Has Dispose already been called?
    bool disposed = false;

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            // Free any other managed objects here
            if (stream != null)
            {
                stream.Flush();
                stream.Close();
                stream.Dispose();
                stream = null;
            }
            if (Tcp != null)
            {
                if (Tcp.Connected)
                {
                    Tcp.Client.Disconnect(false);
                    Tcp.Client.Close();
                    Tcp.Client.Dispose();
                    Tcp.Client = null;

                    //Tcp.GetStream().Flush();
                    //Tcp.GetStream().Close();
                    Tcp.Close();                        
                    Tcp = null;
                }
            }
        }

        // Free any unmanaged objects here.
        // ...
        disposed = true;
    }

    ~ClientClass()
    {
        Dispose(false);
    }
    #endregion
}

The problem I am facing with this code is:

ClientClass client = new ClientClass(...);
client.Write("1");
client.Write("2");
client.Write("hello");

are going to the other end as only one input:

"12hello"

, rather than three separate inputs {"1", "2", and "hello"}.

How can I fix this?



Solution

  • TCP is a stream protocol, not a packet protocol. All that you are guaranteed is the same bytes in the same order (or a socket failure), not the composition of groups. So: anything beyond that you need to add yourself. With text-based protocols, a common approach might be to put a line feed (\n) after each logical payload, and then look for the same when decoding. With binary protocols, a length prefix is more common.