Search code examples
c#socketstcpclient

How can I send multiple string messages from client to server using a single instance of TcpClient?


I have separate client and server console apps. I'm simply trying to send a string from the client to the server and have the server write the string to the console using TcpClient. I can send a single message just fine but when I throw a while loop into the client app to try and send multiple messages without closing the TcpClient, the server doesn't write anything to the console.

//Server
using (TcpClient client = listener.AcceptTcpClient())
{
    NetworkStream ns = client.GetStream();
    byte[] buffer = new byte[1024];
    while (true)
    {
        if (ns.DataAvailable)
        {
            int bytesRead = 0;
            string dataReceived = "";
            do
            {
                bytesRead = ns.Read(buffer, 0, buffer.Length);
                dataReceived += Encoding.UTF8.GetString(buffer, 0, bytesRead);
            }
            while (bytesRead > 0);
            Console.WriteLine($"Message:{ dataReceived }\n");
        }
    }
}

//Client
using (TcpClient client = new TcpClient(hostname, port))
{
    if (client.Connected)
    {
        Console.WriteLine("Connected to server");
        NetworkStream ns = client.GetStream();
        string message = "";
        //Removing this while loop I can send a single message that the server will write to console
        //but with the loop present the server does not write anything
        while (true)
        {
            message = Console.ReadLine();
            byte[] messageBytes = UTF8Encoding.UTF8.GetBytes(message);
            ns.Write(messageBytes);
            Console.WriteLine($"Message Sent! ({ messageBytes.Length } bytes)");
        }
    }
}

I'm interested in learning sockets and have been pouring over SO questions and MSDN docs for two days but cannot figure out why it's not working as I intend. I feel a bit silly even submitting a question because I'm sure it's something basic I'm not understanding. Could someone please drop some knowledge on me?

SOLUTION

//Server
using (TcpClient client = listener.AcceptTcpClient())
{
    NetworkStream ns = client.GetStream();
    StreamReader sr = new StreamReader(ns);
    string message = "";
    while (true)
    {
        message = sr.ReadLine();
        Console.WriteLine(message);
    }
}

//Client
using (TcpClient client = new TcpClient(hostname, port))
{
    if (client.Connected)
    {
        Console.WriteLine("Connected to server");
        NetworkStream ns = client.GetStream();
        StreamWriter sw = new StreamWriter(ns) {Autoflush = true};
        string message = "";
        while (true)
        {
            message = Console.ReadLine();
            sw.WriteLine(message);
        }
    }
}

Solution

  • If you debug your server, you'll see that it does receive data. You're just not displaying the data, because the only output your server does is after the loop when the byte count returned is 0: Console.WriteLine($"Message:{ dataReceived }\n");. The byte count will only be 0 when the underlying socket has been shutdown. That never happens because your client is stuck in an infinite loop.

    A better approach, for a simple text-based client/server example like this, is to use StreamWriter and StreamReader with line-based messages, i.e. WriteLine() and ReadLine(). Then the line breaks serve as the message delimited, and your server can write the message each time it receives a new line.

    Note also that in your example above, you are assuming that each chunk of data contains only complete characters. But you're using UTF8 where characters can be two or more bytes, and TCP doesn't guarantee how bytes that are sent are grouped. Using StreamWriter and StreamReader will fix this bug too, but if you wanted to do it explicitly yourself, you can use the Decoder class, which will buffer partial characters.

    For some examples of how to correctly implement a simple client/server network program like that, see posts like these:
    .NET Simple chat server example
    C# multithreading chat server, handle disconnect
    C# TcpClient: Send serialized objects using separators?