You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C# WPF多线程聊天应用服务器端NetworkStream始终无数据可用问题求助

C# WPF多线程聊天应用服务器端NetworkStream始终无数据可用问题求助

你好,我仔细看了你的代码,发现几个关键问题导致服务器端stream.DataAvailable一直返回false,咱们一步步来解决:


1. 服务器端完全没有读取流数据的逻辑

你当前的Server.Communicate方法里,只是循环打印stream.DataAvailable的状态,但从来没有尝试读取流中的数据。哪怕客户端已经发送了数据,服务器不去主动读取的话,不仅无法拿到消息,还可能导致流状态异常。

而且DataAvailable只是一个瞬时状态——如果在你检查的瞬间数据还没传输到,就会返回false,但之后数据到达了,你要等10秒才会再次检查,这完全错过了接收时机。

修复方案:在循环中加入读取逻辑,并且和客户端保持一致的编码(你客户端用的是UnicodeEncoding.Unicode,也就是UTF-16):

public void Communicate(TcpListener listener)
{
    String data;
    listener.Start();
    Debug.WriteLine("start Connecting to Client");
    client = listener.AcceptTcpClient();
    Debug.WriteLine("Connected to Client");
    if (client != null)
    {
        Debug.WriteLine("client is valid");
        NetworkStream stream = client.GetStream();
        byte[] buffer = new byte[client.ReceiveBufferSize];
        int bytesRead;

        // Read方法是阻塞的,会一直等待直到有数据可读或连接关闭
        while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            string receivedMsg = UnicodeEncoding.Unicode.GetString(buffer, 0, bytesRead);
            Debug.WriteLine($"收到客户端消息:{receivedMsg}");
            Debug.WriteLine($"当前DataAvailable状态:{stream.DataAvailable}");
        }

        // 连接关闭后清理资源
        client.Close();
        listener.Stop();
    }
}

2. 客户端发送数据后未强制刷新缓冲区

客户端发送数据时,.NET可能会把数据暂时存在缓冲区里,没有立即发送到网络。你可以在发送后调用Flush()强制清空缓冲区,确保数据立即传输:

public void Communicate(TcpClient client, String message, System.Windows.Controls.Label messagebox)
{
    Debug.WriteLine("start Communication");
    NetworkStream stream = client.GetStream();
    byte[] message_byte = UnicodeEncoding.Unicode.GetBytes(message);
    
    stream.Write(message_byte, 0, message_byte.Length);
    stream.Flush(); // 强制发送缓冲区数据

    // 这里的inputData数组没用到,可以删掉或者补充接收服务器响应的逻辑
    // byte[] inputData = new Byte[client.ReceiveBufferSize];

    // 注意:WPF控件不能跨线程直接修改,这里要加Dispatcher
    messagebox.Dispatcher.Invoke(() => 
    {
        messagebox.Content = messagebox.Content + "\n" + "message is sent";
    });
}

3. 额外提醒:WPF跨线程UI访问问题

你现在在客户端的Communicate方法里直接修改Label的Content,这会触发跨线程访问UI控件异常——WPF的UI元素只能在主线程操作。上面的代码已经帮你加上了Dispatcher.Invoke来处理这个问题,服务器端如果之后要更新UI,也要用同样的方式。


按照上面的修改,你应该能看到服务器端成功接收到消息,stream.DataAvailable也会在数据到达时正确返回true。

备注:内容来源于stack exchange,提问作者Lisa

火山引擎 最新活动