C# C TCP文件传输-图像半传输

C# C TCP文件传输-图像半传输,c#,file,tcp,transfer,C#,File,Tcp,Transfer,我正在开发一个TCP文件传输客户端-服务器程序。目前,我能够发送文本文件和其他文件格式,例如.zip,所有内容在服务器端都完好无损。然而,当我传输一个.gif文件时,最终的结果是一个与原始文件大小相同的gif文件,但只有部分图像显示为大部分字节丢失或在服务器端未正确写入 客户端向服务器发送一个1KB的头数据包,其中包含文件的名称和大小。然后,服务器会在准备就绪时发出OK响应,然后创建一个与要发送的文件一样大的文件缓冲区 下面是一些代码来演示我的问题: // Serverside method s

我正在开发一个TCP文件传输客户端-服务器程序。目前,我能够发送文本文件和其他文件格式,例如.zip,所有内容在服务器端都完好无损。然而,当我传输一个.gif文件时,最终的结果是一个与原始文件大小相同的gif文件,但只有部分图像显示为大部分字节丢失或在服务器端未正确写入


客户端向服务器发送一个1KB的头数据包,其中包含文件的名称和大小。然后,服务器会在准备就绪时发出OK响应,然后创建一个与要发送的文件一样大的文件缓冲区

下面是一些代码来演示我的问题:

// Serverside method snippet dealing with data being sent while (true) { // Spin the data in if (streams[0].DataAvailable) { streams[0].Read(fileBuffer, 0, fileBuffer.Length); break; } } // Finished receiving file, write from buffer to created file FileStream fs = File.Open(LOCAL_FOLDER + fileName, FileMode.CreateNew, FileAccess.Write); fs.Write(fileBuffer, 0, fileBuffer.Length); fs.Close(); Print("File successfully received."); 我尝试了一个二进制编写器,而不是仅仅使用filestream来获得相同的结果

我认为成功的文件传输就像转换成字节、传输然后再转换回文件名/类型一样简单,这是错误的吗


非常感谢您提供的所有帮助/建议。

当您通过TCP进行写入时,数据可以以多个数据包的形式到达。我认为您的早期测试恰好适合一个数据包,但这个gif文件将以2个或更多个数据包的形式到达。因此,当您调用Read时,您将只得到目前为止到达的内容—您需要反复检查,直到获得了标头所要求的字节数为止


在使用TCP进行一些工作时,我发现了一个很大的帮助。

当您通过TCP进行写入时,数据可以以许多数据包的形式到达。我认为您的早期测试恰好适合一个数据包,但这个gif文件将以2个或更多个数据包的形式到达。因此,当您调用Read时,您将只得到目前为止到达的内容—您需要反复检查,直到获得了标头所要求的字节数为止


在使用TCP进行一些工作时,我发现了很大的帮助。

感谢您的输入Tvanfosson。我修改了我的代码,并设法使其正常工作。我的客户端和服务器之间的同步性已关闭。不过我采纳了你的建议,用一次读取一个字节来代替读取。

谢谢你的输入。我修改了我的代码,并设法使其正常工作。我的客户端和服务器之间的同步性已关闭。不过,我采纳了您的建议,将读取替换为一次读取一个字节。

正如其他人所指出的,数据不一定一次全部到达,并且您的代码每次通过循环都会覆盖缓冲区的开头。编写读取循环的更可靠的方法是读取尽可能多的可用字节,并增加一个计数器来跟踪到目前为止已读取的字节数,以便知道将它们放在缓冲区中的位置。类似这样的方法效果很好:

int totalBytesRead = 0;
int bytesRead;
do
{
    bytesRead = streams[0].Read(fileBuffer, totalBytesRead, fileBuffer.Length - totalBytesRead);
    totalBytesRead += bytesRead;
} while (bytesRead != 0);
当没有可读取的数据时,Stream.Read将返回0


这样做比一次读取一个字节要好。它还提供了一种确保读取正确字节数的方法。如果TotalByteRead不等于循环完成时预期的字节数,则会发生错误。

正如其他人所指出的,数据不一定一次全部到达,并且每次通过循环时代码都会覆盖缓冲区的开头。编写读取循环的更可靠的方法是读取尽可能多的可用字节,并增加一个计数器来跟踪到目前为止已读取的字节数,以便知道将它们放在缓冲区中的位置。类似这样的方法效果很好:

int totalBytesRead = 0;
int bytesRead;
do
{
    bytesRead = streams[0].Read(fileBuffer, totalBytesRead, fileBuffer.Length - totalBytesRead);
    totalBytesRead += bytesRead;
} while (bytesRead != 0);
当没有可读取的数据时,Stream.Read将返回0


这样做比一次读取一个字节要好。它还提供了一种确保读取正确字节数的方法。如果TotalByteRead不等于循环完成时预期的字节数,则发生了错误。

这与图像无关。。这是关于你的代码。 如果图像字节丢失或写入不正确,则表示文件传输代码错误,甚至会收到.zip文件或任何其他文件。。它会被篡改的。 将字节缓冲区长度设置为文件大小是一个巨大的错误。假设您要发送一个大约1GB的大文件。。然后需要1GB的内存。。对于空闲传输,您应该循环发送文件

这是一种发送/接收文件的方式,没有大小限制

发送文件

接收文件


快乐编码:

这与你的图像无关。。这是关于你的代码。 如果图像字节丢失或写入不正确,则表示文件传输代码错误,甚至会收到.zip文件或任何其他文件。。它会被篡改的。 将字节缓冲区长度设置为文件大小是一个巨大的错误。假设您要发送一个大约1GB的大文件。。然后需要1GB的内存。。对于空闲传输,您应该循环发送文件

这是一种发送/接收文件的方式,没有大小限制

发送文件

接收文件

快乐鳕鱼
ing:

每次都用新数据覆盖缓冲区。我怀疑你成功的测试都在一个缓冲区内。从网络读取文件时,您需要将每个缓冲区写入文件。客户端向服务器发送一个1KB的头数据包,其中包含文件的名称和大小。然后,服务器会在准备就绪时发出OK响应,然后创建一个与要发送的文件一样大的文件缓冲区。这仍然会导致问题吗?下面的传输层上是否有默认缓冲区大小?我应该在OP中解释这一点,我现在就添加它。你每次都用新数据覆盖你的缓冲区。我怀疑你成功的测试都在一个缓冲区内。从网络读取文件时,您需要将每个缓冲区写入文件。客户端向服务器发送一个1KB的头数据包,其中包含文件的名称和大小。然后,服务器会在准备就绪时发出OK响应,然后创建一个与要发送的文件一样大的文件缓冲区。这仍然会导致问题吗?下面的传输层上是否有默认缓冲区大小?我应该在OP中解释这一点,我现在就添加它。正如你发布的:谢谢!刚发现,正如你发布的:谢谢!
using (FileStream fs = new FileStream(srcPath, FileMode.Open, FileAccess.Read))
{
        long fileSize = fs.Length;
        long sum = 0;   //sum here is the total of sent bytes.
        int count = 0;
        data = new byte[1024];  //8Kb buffer .. you might use a smaller size also.
        while (sum < fileSize)
        {
            count = fs.Read(data, 0, data.Length);
            network.Write(data, 0, count);
            sum += count;
        }
        network.Flush();
}
long fileSize = // your file size that you are going to receive it.
using (FileStream fs = new FileStream(destPath, FileMode.Create, FileAccess.Write))
{
        int count = 0;
        long sum = 0;   //sum here is the total of received bytes.
        data = new byte[1024 * 8];  //8Kb buffer .. you might use a smaller size also.
        while (sum < fileSize)
        {
            if (network.DataAvailable)
            {
                {
                    count = network.Read(data, 0, data.Length);
                    fs.Write(data, 0, count);
                    sum += count;
                }
            }
        }
}