我正在开发一个TCP文件传输客户端 - 服务器程序。目前,我能够完美地发送文本文件和其他文件格式,例如.zip,服务器端的所有内容都完好无损。但是,当我传输.gif时,最终结果是一个与原始格式相同的gif,但只有部分图像显示大部分字节丢失或在服务器端没有正确写入。
客户端向服务器发送带有文件名称和大小的1KB标头数据包。然后服务器响应OK,如果准备就绪,然后创建一个与要发送的文件一样大的fileBuffer。
以下是一些用于演示我的问题的代码:
// 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.");
// Clientside method snippet dealing with a file send while(true) { con.Read(ackBuffer, 0, ackBuffer.Length); // Wait for OK response to start sending if (Encoding.ASCII.GetString(ackBuffer) == "OK") { // Convert file to bytes FileStream fs = new FileStream(inPath, FileMode.Open, FileAccess.Read); fileBuffer = new byte[fs.Length]; fs.Read(fileBuffer, 0, (int)fs.Length); fs.Close(); con.Write(fileBuffer, 0, fileBuffer.Length); con.Flush(); break; } }
我尝试过二进制编写器而不是仅使用具有相同结果的文件流。
我认为成功的文件传输就像转换为字节,传输然后转换回文件名/类型一样简单吗?
非常感谢所有帮助/建议。
答案 0 :(得分:1)
当您通过TCP写入时,数据可以到达多个数据包。我认为你的早期测试碰巧适合一个数据包,但这个gif文件到达2个或更多。因此,当您调用Read时,您将只获得到目前为止已到达的内容 - 您需要反复检查,直到您获得了与标题告诉您期望的字节数相同的字节数。
在使用TCP进行一些工作时,我发现Beej's guide to network programming是一个很大的帮助。
答案 1 :(得分:1)
它不是关于你的形象..这是关于你的代码。
这是一种很好地发送/接收文件的方法,没有大小限制。
发送文件
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;
}
}
}
}
快乐的编码:)
答案 2 :(得分:0)
感谢您输入Tvanfosson。我修改了我的代码,并设法让它工作。我的客户端和服务器之间的同步性已关闭。我接受了你的建议,并将读取替换为一次读取一个字节。
答案 3 :(得分:0)
正如其他人所指出的那样,数据不一定全部到达,并且每次循环时你的代码都会覆盖缓冲区的开头。编写读取循环的更健壮的方法是读取尽可能多的字节数,然后递增计数器以跟踪到目前为止已读取的字节数,以便您知道将它们放在缓冲区中的位置。这样的事情效果很好:
int totalBytesRead = 0;
int bytesRead;
do
{
bytesRead = streams[0].Read(fileBuffer, totalBytesRead, fileBuffer.Length - totalBytesRead);
totalBytesRead += bytesRead;
} while (bytesRead != 0);
当没有数据可供阅读时, Stream.Read
将返回0。
以这种方式执行操作比一次读取一个字节要好。它还为您提供了一种确保读取正确字节数的方法。如果totalBytesRead
不等于循环结束时预期的字节数,那么就会发生一些不好的事情。