如何使用单个 TcpClient 实例从客户端向服务器发送多条字符串消息?

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

我有单独的客户端和服务器控制台应用程序。我只是想从客户端向服务器发送一个字符串,并让服务器使用 TcpClient 将字符串写入控制台。我可以很好地发送一条消息,但是当我将 while 循环放入客户端应用程序以尝试在不关闭 TcpClient 的情况下发送多条消息时,服务器不会向控制台写入任何内容。

//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)");
        }
    }
}

我对学习套接字很感兴趣,两天来一直在研究 SO 问题和 MSDN 文档,但无法弄清楚为什么它没有按我的预期工作。我什至觉得提交问题有点傻,因为我确定这是我不理解的基本问题。有人可以给我一些知识吗?

解决方案

//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);
        }
    }
}

如果您调试服务器,您会发现它确实接收到数据。您只是没有显示数据,因为您的服务器唯一的输出是在返回的字节数为 0 的循环之后:Console.WriteLine($"Message:{ dataReceived }\n");。当底层套接字已关闭时,字节数将仅为 0。这永远不会发生,因为您的客户端陷入了无限循环。

对于像这样的简单的基于文本的 client/server 示例,更好的方法是将 StreamWriterStreamReader 与基于行的消息一起使用,即 WriteLine()ReadLine()。然后换行符作为消息分隔符,您的服务器可以在每次收到新行时写入消息。

另请注意,在上面的示例中,您假设每个数据块仅包含完整字符。但是您使用的是 UTF8,其中字符可以是两个或更多字节,而 TCP 不保证发送的字节是如何分组的。使用 StreamWriterStreamReader 也会修复这个错误,但如果你想自己明确地这样做,你可以使用 Decoder class,它将缓冲部分字符。

有关如何正确实施像这样的简单 client/server 网络程序的一些示例,请参阅以下帖子:
.NET Simple chat server example

C# TcpClient: Send serialized objects using separators?