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

Should send() and recv() buffer size be as big as possible?

我正在通过 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() returns 实际读取的字节数或错误时为 -1。您应该从 recvbuf 复制那些字节。还要检查 return 值。如果它是 -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. 
}

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

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