c - send() 和 recv() 缓冲区大小应该尽可能大吗?

标签 c windows sockets http winsock

我正在通过 http 使用 winsock 发送一个 .mp3 文件(.jpg 和其他扩展名,大小在 1K 到 50MB 之间)。客户端发送文件,服务器接收文件。
我有几个问题:

  1. send() 缓冲区大小和 recv() 缓冲区大小应该相同吗?

  2. 我应该选择什么尺寸,固定尺寸还是足以包含所有数据的尺寸?

代码来了。

客户:

... //POST /index.html HTTP/1.1 and so on

sprintf_s(header, "%sContent-Length: %d\r\n", header, sizeof(szFileData ));
sprintf_s(header, "%s%s\r\n", header , szFileData );  

... //Content-Disposition: form-data; name=\"submit\" and so on

while(send(sock,  header, strlen(header), 0) == SOCKET_ERROR)
{
    Sleep(1000);
}

服务器:

recv(sock, recvbuf , 4096 , 0);  //neither strlen(recvbuf) nor 4096 works
...//extract file name, content and so on

FILE *pFile;
pFile = fopen ( filename , "wb" );
if ( fwrite(filedata, sizeof(filedata), 1,  pfile) != 1)
{
    MessageBox(NULL, "Failed!", "MSG", MB_OK);
}

我得到的结果要么是空的,要么丢失了一些内容。

最佳答案

两个问题。

1) send() 不一定发送所有内容。在某些情况下,它可能只发送您提供的部分内容。因此,请为此做好准备。

2) recv() 返回实际读取的字节数,错误返回-1。您应该从 recvbuf 复制那些字节。还要检查返回值。如果它是 -1,那么有一个错误,你需要使用 errno 来找出错误是什么。

为确保发送所有内容,请使用 sendall(来自 Beej's guide):

#include <sys/types.h>
#include <sys/socket.h>

int sendall(SOCKET s, char *buf, int *len)
{
    int total = 0;        // how many bytes we've sent
    int bytesleft = *len; // how many we have left to send
    int n;

    while(total < *len) {
        n = send(s, buf+total, bytesleft, 0);
        if (n == -1) { break; }
        total += n;
        bytesleft -= n;
    }

    *len = total; // return number actually sent here

    return n==-1?-1:0; // return -1 on failure, 0 on success
} 

接收类似的东西:

int nbytes = 0;
while ((nbytes = recv(sock, recvbuf , 4096 , 0)) > 0){
    // From here, valid bytes are from recvbuf to recvbuf + nbytes.
    // You could simply fwrite(fp, recvbuf, nbytes) or similar. 
}

确保您不会混淆应用程序缓冲区和套接字缓冲区。它们是不同的东西。套接字缓冲区位于内核空间中。应用程序缓冲区是您在这里使用的。可能有一个最佳尺寸,但它会根据您正在做的事情而有所不同。将它们设为 4K 通常是合理的。

如果有任何不清楚的地方,请查阅 Beej 的指南。这一切都非常简单,但在真正的应用程序中,如果在 Linux 上,我倾向于使用非阻塞套接字和/或 epoll。

关于c - send() 和 recv() 缓冲区大小应该尽可能大吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33646539/

相关文章:

c - 试图从内存中打印出有用的数据

c - 具有公共(public)源文件和子项目的正确项目组织

c - 从非阻塞套接字接收部分数据

c++ - connect() 中的 EHOSTDOWN 和 EHOSTUNREACH 是否致命?

windows - 计算机 sleep 后无法访问 Docker

ruby - 如何在 ruby​​ 中创建非阻塞 TCP 服务器和 TCP 套接字,只有以下更改才会有所不同?

c - C99 中 _Bool 的用途是什么?

c - 需要帮助找出为什么 for 循环的计数器变量被循环内的函数更改

windows - 服务 创建服务 - 将 SC_MANAGER_CREATE_SERVICE 分配给用户

windows - 如何在Surface RT上卸载暂存的应用程序包?