无法通过套接字 C 发送文件

标签 c windows sockets

只有当我用自己的计算机执行此操作时它才有效,但是当我使用另一台计算机时,收到的文件一团糟,而且大小始终是另一个。

服务器:

while (1) {
        ZeroMemory(r_buf, MAX_BUFF_RECV - 1);
        bytesReceived = recv(sock, r_buf, FILE_DOWNLOAD_SIZE, 0);

        if (bytesReceived < 0) {
            // ERROR
            puts("[!] recv failed");
            return;
        }
        else if (bytesReceived < FILE_DOWNLOAD_SIZE) {
            // LAST CHUNCK
            if (WriteFile(out, r_buf, bytesReceived, &n, NULL) == FALSE) {
                printf("WriteFile() error %d\n", GetLastError());
            }
            break;
        }
        else {
            if (WriteFile(out, r_buf, bytesReceived, &n, NULL) == FALSE) {
                printf("WriteFile() error %d\n", GetLastError());
            }
        }
    }

客户:

while (1)
    {
        ZeroMemory(buff, FILE_DOWNLOAD_SIZE);
        nread = fread(buff, 1, FILE_DOWNLOAD_SIZE, f);

        if (nread != FILE_DOWNLOAD_SIZE) {
            send(s, buff, nread, 0);
            break;
        }
        else {
            send(s, buff, nread, 0);
        }
    }

我花了几个小时,请告诉我出了什么问题

最佳答案

在面向连接的传输中,例如 TCP,send()recv() 不是一对一的。无法保证您 send() 会在单个数据包中传输,也不保证 recv() 会收到您 send()< 的所有内容 一次完成。

无法保证 send() 会接受您提供的所有内容。它将尽可能地将所有内容复制到套接字的出站缓冲区中,并返回实际复制的字节数。因此它可以接受比请求更少的字节。

同样,recv() 将复制套接字入站缓冲区中当前可用的任何数据,至少 1 个字节,但不超过将指定的字节数放入指定的缓冲区中,并将返回复制的实际字节数。因此它可以接收比请求更少的字节。

您还需要知道实际传输了多少文件数据,以便知道何时停止读取数据。由于 recv() 返回的字节数少于请求的字节数,因此您不能仅依靠缓冲区大小来指示 EOF。

您没有在代码中考虑到这些。

尝试更多类似这样的事情:

服务器:

bool readRaw(SOCKET sock, void *buf, int bufSize)
{
    char *pbuf = (char*) buf;
    while (bufSize > 0)
    {
        int bytesReceived = recv(sock, pbuf, bufSize, 0);
        if (bytesReceived < 0)
        {
            printf("[!] recv() error %d\n", WSAGetLastError());
            return false;
        }
        else if (bytesReceived == 0)
        {
            puts("[!] client disconnected");
            return false;
        }
        else
        {
            pBuf += bytesReceived;
            bufSize -= bytesReceived;
        }
    }
    return true;
}

...

unsigned __int64 fileSize = 0;
if (readRaw(sock, &fileSize, sizeof(fileSize)))
{
    while (fileSize > 0)
    {
        int bufSize = min(fileSize, MAX_BUFF_RECV);

        if (!readRaw(sock, r_buf, bufSize))
            break;

        if (!WriteFile(out, r_buf, bufSize, &n, NULL))
        {
            printf("[!] WriteFile() error %d\n", GetLastError());
            break;
        }

        fileSize -= bufSize;
    }
}

客户:

bool sendRaw(SOCKET sock, void *buf, int bufSize)
{
    char *pbuf = (char*) buf;
    while (bufSize > 0)
    {
        int bytesSent = send(sock, pbuf, bufSize, 0);
        if (bytesSent < 0)
        {
            printf("[!] send() error %d\n", WSAGetLastError());
            return false;
        }
        else
        {
            pBuf += bytesSent;
            bufSize -= bytesSent;
        }
    }

    return true;
}

...

fseek(f, 0, SEEK_END);
long int pos = ftell(f);
fseek(f, 0, SEEK_SET);

if (pos == -1)
    printf("[!] ftell() error\n");
else
{
    unsigned __int64 fileSize = pos;
    if (sendRaw(s, &fileSize, sizeof(fileSize)))
    {
        while (fileSize > 0)
        {
            int bufSize = min(FILE_DOWNLOAD_SIZE, fileSize);

            nread = fread(buff, 1, bufSize, f);
            if (nread == 0)
            {
                printf("[!] fread() error\n");
                break;
            }

            if (!sendRaw(s, buff, nread))
                break;

            uifileSize -= nread;
        }
    }
}

关于无法通过套接字 C 发送文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32285485/

相关文章:

windows - 带有自定义链接的 OCaml 编译是否应该在 Windows 中工作(通过 MinGW)?

c - Socket编程c - 文件下载

c - 指针扰乱了我的价​​值观

c - 如何使用C在char中存储8位

c++ - StartService 失败,错误代码为 1053

javascript - 启动桌面应用程序的网页

android - socket.io 客户端连接反复断开

linux - epoll和远程1路关机

c - 动态分配二维数组

c - 不知道为什么我用 strtok/EOF 得到 "Bus error 10"