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

时间:2015-11-11 08:15:09

标签: c windows sockets http winsock

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

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

  2. 我应该选择什么尺寸,固定尺寸或足够大的尺寸来包含所有数据?

  3. 代码来了。

    客户:

    ... //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 个答案:

答案 0 :(得分:3)

两个问题。

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。