You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#通过NetworkStream传输图片出错求助

解决C# NetworkStream传输大数据(图片)丢失/损坏问题

核心问题分析

你的代码存在两个关键错误,直接导致图片传输损坏:

  1. 服务器写入流时误用缓冲区总长度:stream.Read()返回的read变量是本次实际读取的字节数,最后一次读取时缓冲区大概率无法填满,此时写入data.Length会把多余的空字节写入MemoryStream,导致图片文件大小异常、损坏。
  2. 客户端未正确通知服务器数据发送完毕:发送完数据直接关闭TcpClient,可能导致服务器还未读取完所有数据就收到连接断开信号,stream.Read()提前返回0,造成数据丢失。

快速修复方案

修正服务器代码

将写入MemoryStream的逻辑改为使用实际读取的字节数,同时优化循环逻辑避免无限等待:

// get image
var ms = new MemoryStream();
int total = 0;
int read = -1;
// 将缓冲区声明移到循环外,避免重复创建对象
byte[] data = new byte[client.ReceiveBufferSize];
do
{
    if (!stream.CanRead)
    {
        break; // 无法读取时直接退出循环,避免无限等待
    }
    
    Console.WriteLine("get");
    read = stream.Read(data, 0, data.Length);
    if (read > 0)
    {
        // 关键:使用实际读取的字节数写入,而非缓冲区总长度
        ms.Write(data, 0, read);
        total += read;
    }
} while (read > 0);

修正客户端代码

发送完数据后,先刷新流并通知服务器数据发送完毕,再关闭连接:

try
{
    var stream = tcpClient.GetStream();
    
    if (stream.CanWrite)
    {
        stream.Write(image, 0, image.Length);
        stream.Flush(); // 确保所有数据都写入网络流
        // 通知服务器:客户端已完成发送,不会再发送数据
        tcpClient.Client.Shutdown(SocketShutdown.Send);
    }
}
catch (Exception e)
{
    Console.Error.WriteLine($"send error, {e.Message}");
}
finally
{
    tcpClient.Close();
}

更可靠的进阶方案:基于长度的传输

TCP是无边界的流协议,依赖连接关闭判断数据结束的方式不够可靠(比如连续传输多个文件时无法区分边界)。更专业的做法是先发送数据长度,再发送实际数据,让服务器精准知道需要接收多少字节:

客户端代码(带长度校验)

private static void SendData(byte[] image)
{
    Console.WriteLine($"image byte size is {image.Length}"); 
    File.WriteAllBytes("/Users/tim/Downloads/test_send.jpg", image); 

    var tcpClient = new TcpClient();
    try
    {
        tcpClient.Connect("127.0.0.1", 20000);
        var stream = tcpClient.GetStream();
        
        // 使用BinaryWriter简化长度和数据的写入
        using (var writer = new BinaryWriter(stream))
        {
            // 先发送图片字节数组的长度(Int32类型,占4字节)
            writer.Write(image.Length);
            // 再发送图片数据
            writer.Write(image);
            writer.Flush();
        }
        
        // 通知服务器发送完毕
        tcpClient.Client.Shutdown(SocketShutdown.Send);
    }
    catch (Exception e)
    {
        Console.Error.WriteLine($"TCP connect or send error, {e.Message}");
    }
    finally
    {
        tcpClient.Close();
    }
}

服务器代码(带长度校验)

static void Main(string[] args)
{
    int Port = 20000;
    TcpListener? server = null;
    try
    {
        server = new TcpListener(IPAddress.Any, Port);
        server.Start();

        var client = server.AcceptTcpClient();
        var stream = client.GetStream();
        
        // 先读取图片数据的总长度
        int imageLength;
        using (var reader = new BinaryReader(stream))
        {
            imageLength = reader.ReadInt32();
        }

        // 循环读取直到接收完所有数据
        var ms = new MemoryStream();
        int totalRead = 0;
        byte[] buffer = new byte[client.ReceiveBufferSize];
        
        while (totalRead < imageLength)
        {
            // 计算本次最多能读取的字节数(避免超过剩余需要接收的长度)
            int readSize = Math.Min(buffer.Length, imageLength - totalRead);
            int read = stream.Read(buffer, 0, readSize);
            
            if (read == 0)
            {
                throw new IOException("连接意外中断,未接收完整图片数据");
            }
            
            ms.Write(buffer, 0, read);
            totalRead += read;
            Console.WriteLine($"已接收 {totalRead}/{imageLength} 字节");
        }

        Console.WriteLine("get image finish");
        Console.WriteLine($"total is {totalRead}"); 
        
        byte[] image = ms.ToArray();
        Console.WriteLine($"the byte array size is {image.Length}");

        File.WriteAllBytes("/Users/tim/Downloads/test_received.jpg", image);
        Console.WriteLine("saved");
    }
    catch (Exception e)
    {
        Console.WriteLine($"Error: {e.Message}");
    }
    finally
    {
        server?.Stop();
    }
}

效果验证

使用上述方案后,服务器接收的字节数组长度会和客户端发送的完全一致,图片不会再出现损坏或丢失的情况。

内容的提问来源于stack exchange,提问作者Tim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:39:21