我使用winsock over http发送.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);
}
我得到的结果是空的或丢失了一些内容。
答案 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。