c# - 为什么文件不能通过 tcp 在 C# 中的客户端和 C 中的服务器之间正确传输(保存?)?

标签 c# c++ tcp network-programming

我已经在 C# 中设置了 TCP 客户端,在 C 中设置了服务器。 当我要传输文件时,一些数据包丢失,文件没有正确保存。

我比较过我尝试传输的 PDF 文件,有一半的数据包没有保存,所以我无法在另一台电脑上打开它。

客户端代码:

public void SendFile(string file, string destPath = "C:\\")
    {
        int bufferSize = 1024;
        byte[] filebuff = new byte[bufferSize];
        string fileName = destPath + file;

        //send to TcpServer request to send file
        stream.Write(textToBytes("RECEIVEFILE"), 0, 11);
        try
        {
            FileStream streamFile = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            BinaryReader binReader = new BinaryReader(streamFile);


            //send file name to TcpServer
            stream.Write(textToBytes(file), 0, file.Length);


            //get file size
            long filesize = streamFile.Length;

            //send file size to TcpServer
           //sendData(stream, BitConverter.GetBytes(filesize));

            //if file doesn't exist
            if (file == null)
            {
                Console.WriteLine("Error.");
            }

            //if file is empty
            if (filesize == 0)
            {
                Console.WriteLine("File size: 0");
                return;
            }


            int totalLength = Convert.ToInt32(filesize);

            Console.WriteLine("Totallength: " + totalLength);
            long numberOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(streamFile.Length) / bufferSize));
            int currentPacketLength;

            for (int i = 0; i < numberOfPackets; i++)
            {
                if (filesize > bufferSize)
                {
                    currentPacketLength = bufferSize;
                    totalLength = totalLength - currentPacketLength;
                }
                else
                    currentPacketLength = totalLength;

                filebuff = new byte[currentPacketLength];
                //streamFile.Read(filebuff, 0, currentPacketLength);
                binReader.Read(filebuff, 0, currentPacketLength);


                stream.Write(filebuff, 0, filebuff.Length);
            }

            streamFile.Close();
        }
        catch
        {
            Console.WriteLine("There's no file...");
        }


    }

    public void DownloadFile(string fileName)
    {
        byte[] recBuffer = new byte[1024];
        byte[] fileNameBytes;
        long received = 0;
        long receivedAll = 0;
        byte[] fileData = new byte[1024];

        stream.Write(textToBytes("SENDFILE"), 0, 8);
        fileNameBytes = Encoding.UTF8.GetBytes(fileName);

        stream.Write(fileNameBytes, 0, fileNameBytes.Length);
        byte[] fileSizeBytes = new byte[4];
        stream.Read(fileSizeBytes, 0, fileSizeBytes.Length);
        int bytes = BitConverter.ToInt32(fileSizeBytes, 0);

        Console.WriteLine("I'm downloading file...");

        while (receivedAll < bytes)
        {
            received = stream.Read(fileData, 0, fileData.Length);
            if (received < 0)
            {
                Console.WriteLine("Error");
                break;
            }
            BinaryWriter bWrite = new BinaryWriter(File.Open("C:\\" + fileName, FileMode.Append));
            bWrite.Write(fileData);
            bWrite.Close();
            receivedAll += received;

        }

        if(receivedAll == bytes)
        {
            Console.WriteLine("File downloaded successfuly.");
        }
    }

服务器代码:

void ReceiveFile(int client_socket)
{
const int buffsize = 1024;
char buff[buffsize];
long filesize, received = 0, receivedall;
char filenamechar[512];

std::string filename, fullFilename;
memset(filenamechar, 0, 512);
 /*
    if(recv(client_socket, filenamechar, 512, 0) != 512)
{
    printf("Error - filename.\n");
    return;
}

fullFilename = "/Users/xxx/" + std::string(filenamechar);

*
if(recv(client_socket, &filesize, sizeof(long), 0) != sizeof(long))
{
    printf("Child process: error.\n");
    return;
}*/

filesize = 331776;

std::fstream fileFromClient;

fullFilename = "/Users/xxx/sockets.pdf";

fileFromClient.open(fullFilename, std::ios::binary | std::ios::out);

receivedall = 0;
while (receivedall < filesize)
{
    memset(buff, 0, 1024);
    received = recv(client_socket, buff, 1024, 0);
    if(received <= 0)
    {
        std::cout << "error" << std::endl;
        break;
    }
    receivedall += received;

    fileFromClient << buff;
    fputs(buff, stdout);
}

fileFromClient.close();

std::cout << "\nreceivedall: " << receivedall << std::endl;
std::cout << "filesize: " << filesize << std::endl;
if(receivedall != filesize)
    printf("Error\n");
else
    printf("File saved successfuly\n");

}

void SendFile(int client_socket)
{
char path[512];
char fileName[512];
char fullFileName[512];
long fileLen, sent, sentAll, read;
struct stat fileinfo;
FILE* file;
unsigned char bufor[1024];

memset(path, 0, 512);
strcpy(path, "/Users/xxxx/");

if (recv(client_socket, fileName, 512, 0) <= 0)
{
    printf("Child process: error\n");
    return;
}

strcpy(fullFileName, strcat(path, fileName));
printf("Child process: client wants file: %s\n", fullFileName);


if (stat(fullFileName, &fileinfo) < 0)
{
    printf("Child process: can't get file info\n");
    return;
}

if (fileinfo.st_size == 0)
{
    printf("Child process: file size: 0\n");
    return;
}

fileLen = fileinfo.st_size;

if (send(client_socket, &fileLen, sizeof(long), 0) != sizeof(long))
{
    printf("Child process: error\n");
    return;
}

sentAll = 0;
file = fopen(fullFileName, "rb");
if (file == NULL)
{
    printf("Error\n");
    return;
}

while (sentAll < fileLen)
{
    read = fread(bufor, 1, 1024, file);
    sent = send(client_socket, bufor, read, 0);
    if (read != sent)
        break;
    sentAll += sent;
    printf("Child process: sent %ld bytes\n", sentAll);
}

if (sentAll == fileLen)
    printf("Child process: file sent successfuly\n");
else
    printf("Child process: error\n");
fclose(file);
return;    
}

如何保证每个数据包都被妥善保存?

最佳答案

这一行有一个问题:

fileFromClient << buff;

这会写出buff的内容直到找到一个零字节。由于您正在传输二进制文件,因此您可以预期这些字节会很频繁。接收到的数据包的其余部分将不会被写入。

而不是使用 <<运算符,你应该使用

fileFromClient.write(buff, received);

关于c# - 为什么文件不能通过 tcp 在 C# 中的客户端和 C 中的服务器之间正确传输(保存?)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54370799/

相关文章:

c# - 是否可以限制 Parallel.ForEach 的内核数?

c# - 从 c# 调试 c++ cli - 未命中 c++ 断点

c# - 使用 Angular 将 POST 2 引导参数传递给 API

c++ - 为什么迭代 std::set 比迭代 std::vector 慢得多?

c#-4.0 - 使用在 C# 中执行的带有 TCP/IP 接口(interface)的 ESC/POS 命令直接打印到热敏打印机

java - 在没有服务器的情况下建立平等客户端的双向 TCP 通信的最佳方法是什么?

c# - 以编程方式在 UpdatePanel 中添加用户控件

c++ - 虚拟表中的索引是如何在 C++ 中决定的?

c++ - 如何通过 Boost::MPI 发送 2d C 样式数组?

scala - 使用 Akka 在 Scala 上使用 SSL 的 TCP 套接字