send() 和 recv() 缓冲区大小应该尽可能大吗?
Should send() and recv() buffer size be as big as possible?
我正在通过 http 使用 winsock 发送一个 .mp3 文件(.jpg 和其他扩展名,大小在 1K 到 50MB 之间)。客户端发送文件,服务器接收文件。
我有几个问题:
send() 缓冲区大小和recv() 缓冲区大小应该相同吗?
我应该选择什么尺寸,固定尺寸还是足以容纳所有数据的尺寸?
代码来了。
客户:
... //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.
我正在通过 http 使用 winsock 发送一个 .mp3 文件(.jpg 和其他扩展名,大小在 1K 到 50MB 之间)。客户端发送文件,服务器接收文件。
我有几个问题:
send() 缓冲区大小和recv() 缓冲区大小应该相同吗?
我应该选择什么尺寸,固定尺寸还是足以容纳所有数据的尺寸?
代码来了。
客户:
... //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.