Winsock正在接收额外的数据
Winsock receiving extra data
我试图使用Winsock制作一个文件下载程序,但我意识到,如果互联网连接速度较慢,客户端会接收到一些不需要的数据以及服务器发送的数据
所以我做了一个简单的测试:
从服务器我发送的数字从1到30000:
char* buf = (char*)malloc(BUFLEN);
for( int i = 0;i < 30000;++i ){
ZeroMemory(buf, BUFLEN);
itoa(i+1, buf, 10);
send(current_client, buf, BUFLEN, 0);
}
free(buf);
客户端接收并保存它们:
char *buf = (char*)malloc(DEFAULT_BUFLEN);
ofstream out;
out.open(filename, ios::binary);
for( int i = 0;i < 30000;++i ){
ZeroMemory(buf, DEFAULT_BUFLEN);
recv(ConnectSocket, buf, DEFAULT_BUFLEN, 0);
out.write(buf, DEFAULT_BUFLEN);
out << endl;
}
out.close();
free(buf);
我希望在文件中看到这样的内容:
1
2
3
4
…
30000
但相反,传输了一些包含"/0"的额外数据包,文件如下所示:
1
2
3
4
5
6
…
2600
如果我尝试跳过"/0"数据包,服务器中的数据也会被跳过,如下所示:
1
2
3
4
5
6
9<-缺少7和8
…
2600
我做错了什么?
recv()
告诉您实际收到了多少字节。您忽略了输出整个缓冲区的值,即使它没有完全填满。在服务器端也是如此——你发送的数据比格式化的数据多。
您也没有考虑到send()
和recv()
可以发送/接收比您请求的更少的字节。
试试这个:
bool sendraw(SOCKET socket, void *buf, int buflen)
{
unsigned char *p = (unsigned char*) buf;
while (buflen > 0)
{
int sent = send(socket, p, buflen, 0);
if (sent < 1) return false;
p += sent;
buflen -= sent;
}
return true;
}
for( int i = 0; i < 30000;++i )
{
int j = htonl(i+1);
if (!sendraw(current_client, &j, sizeof(int)))
break;
}
bool recvraw(SOCKET socket, void *buf, int buflen)
{
unsigned char *p = (unsigned char*) buf;
while (buflen > 0)
{
int received = recv(socket, p, buflen, 0);
if (received < 1) return false;
p += received;
buflen -= received;
}
return true;
}
ofstream out;
out.open(filename, ios::binary);
for( int i = 0; i < 30000;++i )
{
int j;
if (!recvraw(ConnectSocket, &j, sizeof(int)))
break;
out << ntohl(j) << endl;
}
out.close();
来自recv
:的手册页面
对于面向连接的套接字(例如,类型为SOCK_STREAM),调用recv将返回与当前可用数据一样多的数据,最多可达指定的缓冲区大小。
这意味着recv
可能会给您不完整的数据包。如果数据包上有固定长度或终止符,则需要在附加到缓冲区的循环中调用recv
,直到接收到所有数据为止。然而,这带来了另一个问题,即对recv
的第二次调用可能会给您最后一个数据包的剩余部分,但也会给您另一个数据包包含的部分。
在您的情况下,也可能是发送方发送的速度快于接收方接收的速度,在这种情况下,recv
将阻塞(如果套接字正在阻塞)或返回错误(如果套接字未阻塞)。你必须检查recv
返回的值才能知道它是什么。如果套接字是非阻塞的,那么recv
将返回SOCKET_ERROR
(即-1
),WSAGetLastError
将返回WSAEWOULDBLOCK
。
我发现了问题所在
正如Joachim和Remy所说,有时客户端不会收到整个缓冲区,所以我对代码进行了一些修改:
来自服务器端:
sent = 0;
while( sent != BUFLEN ){
sent += send(current_client, (buf+sent), BUFLEN-sent, 0);
}
和客户端:
recvd = 0;
while( recvd != DEFAULT_BUFLEN ){
recvd += recv(ConnectSocket, (buf+recvd), DEFAULT_BUFLEN-recvd, 0);
}
我知道缓冲区并没有完全填满,通常我会以char*的形式发送二进制数据,而不仅仅是整数。
- Winsock 数据不是从 IP 检索的,而是从普通 URL 检索的
- 如何通过TCP/IP Winsock发送双型数据
- Winsock 从服务器接收乱码数据
- Winsock:从套接字中删除数据
- Winsock recv() 返回不正确的数据
- 如何使用 winsock (c++) 发送recv 非字符数据
- recv (Winsock) 函数挂起,但数据可用
- C++ 绕道 Winsock recv 挂钩 - 自定义数据包
- C++ WinSock Recv 在接收 0 数据时终止线程而不是返回错误代码
- C++TCP Winsock服务器多次接收相同的数据包
- Winsock正在接收额外的数据
- 未在客户端Winsock中接收到完整数据
- Winsock发送空数据
- 为什么我在使用 winsock 时没有收到 UDP 数据包?
- Winsock C++发送数据时出现问题
- C++服务器无法从客户端/Winsock 接收数据
- Windows/Winsock UDP 数据包正在分组在一起
- C++Winsock将冻结接收数据
- 在C++winsock中通过TCP发送大数据(如文件)
- Winsock发送额外的数据