C++ Windows recv() 不会 return 即使数据可用
C++ Windows recv() doesn't return even if data are available
我正在编写 C++ 程序。我需要接收一个文件,我正在通过 TCP 套接字使用 recv() 函数来执行此操作。
download_file() {
while (left_bytes != 0 && !connection_closed) {
if (left_bytes >= buffer_max_size)
bytes_to_download = buffer_max_size;
else
bytes_to_download = left_bytes;
if (request.conn->read_data(buffer, bytes_to_download))
{
left_bytes -= buffer->get_size();
temporary_file.write_data(buffer);
} else connection_closed = true;
}
}
read_data() {
while (bytes_received < size && alive_) {
bytes_read = recv(sock_, read_buffer, size, 0);
if (bytes_read == SOCKET_ERROR) {
delete[] local_buffer;
throw SocketException(WSAGetLastError());
}
// the connection is closed
if (bytes_read == 0) alive_ = false;
else {
bytes_received += bytes_read;
buffer->add(local_buffer, bytes_read);
}
}
}
问题是 recv 从不 returns。它接收除少数 KB 之外的整个文件,并在 recv() 上冻结。缓冲区大小为 1460。
只有在每次调用 recv 时使用 cout 将某些内容打印到控制台时,我才会收到该文件。只有在这种情况下,我才会收到整个文件。
否则,如果我将 WAITALL 设置为套接字选项并且客户端在文件发送后关闭连接,我会收到整个文件。
这是发送文件的客户端代码:
TransmitFile(file_request->connection_->get_handle_socket(), file_handler.get_file_handle(), file_request->file_size_, 65535, nullptr, nullptr, TF_USE_SYSTEM_THREAD)
编辑
这是我在客户端和服务器之间发送和读取文件大小的方式。
std::stringstream stream_;
stream_.str(std::string());
// append the file size
const __int64 file_size = htonll(GetFileSize(file_handle_, nullptr););
stream_ << ' ' << file_size << ' ';
然后我用send发送这个字符串
这是我读取文件大小的方式
// Within stream_ there is all the content of the received packet
std::string message;
std::getline(stream_, message, ' ');
this->request_body_.file_size_ = ntohll(strtoll(message.c_str(), nullptr, 0));
编辑
我清理了代码,发现 read_data() 显然被调用了一次,我错误地更新了缓冲区变量。因此,我以错误的方式跟踪缓冲区内内容的大小,这让我再次调用了 recv()。
第一件事:recv()
如果没有剩余字节可供读取但连接仍处于打开状态,则会阻塞。因此,无论您怎么说您的代码在做什么,必须就是这里发生的事情。
这可能是由于以下任一原因造成的:
- 发件人谎报了文件的大小,或者没有发送承诺的字节数
- 无论什么原因,接收端都没有正确解释文件大小
- 'counts down' 接收器中剩余字节数的逻辑存在某种缺陷
问题是,查看您发布的代码示例,很难说是哪一个,因为代码有点混乱,而且在我看来,它比需要的更复杂。我会建议你解决这个问题。
- 正在发送文件的大小。
不要把它作为字符串发送。而是以二进制形式发送它,在发送端使用(比如)htonll()
,在接收端使用 ntohll()
。然后,接收方知道要准确读取 8 个字节才能弄清楚接下来会发生什么。很难弄错。
- 正在发送文件本身。
TransmitFile()
看起来是个不错的选择。坚持下去。
- 接收文件并倒数剩余字节数。
仔细查看该代码并考虑重写它。有点乱。
- 如果还是不行怎么办。
使用 WireShark 检查是否正在发送预期的数据,然后在调试器中遍历接收器中的代码。绝对没有理由不这样做,除非您出于某种原因 没有 调试器,在这种情况下请说出来,有人会尽力帮助您。登录到 cout
可以解决您的问题这一事实是在转移注意力。这只是改变了时间,然后它恰好工作正常。
就是这样。祝你好运。
我正在编写 C++ 程序。我需要接收一个文件,我正在通过 TCP 套接字使用 recv() 函数来执行此操作。
download_file() {
while (left_bytes != 0 && !connection_closed) {
if (left_bytes >= buffer_max_size)
bytes_to_download = buffer_max_size;
else
bytes_to_download = left_bytes;
if (request.conn->read_data(buffer, bytes_to_download))
{
left_bytes -= buffer->get_size();
temporary_file.write_data(buffer);
} else connection_closed = true;
}
}
read_data() {
while (bytes_received < size && alive_) {
bytes_read = recv(sock_, read_buffer, size, 0);
if (bytes_read == SOCKET_ERROR) {
delete[] local_buffer;
throw SocketException(WSAGetLastError());
}
// the connection is closed
if (bytes_read == 0) alive_ = false;
else {
bytes_received += bytes_read;
buffer->add(local_buffer, bytes_read);
}
}
}
问题是 recv 从不 returns。它接收除少数 KB 之外的整个文件,并在 recv() 上冻结。缓冲区大小为 1460。 只有在每次调用 recv 时使用 cout 将某些内容打印到控制台时,我才会收到该文件。只有在这种情况下,我才会收到整个文件。
否则,如果我将 WAITALL 设置为套接字选项并且客户端在文件发送后关闭连接,我会收到整个文件。 这是发送文件的客户端代码:
TransmitFile(file_request->connection_->get_handle_socket(), file_handler.get_file_handle(), file_request->file_size_, 65535, nullptr, nullptr, TF_USE_SYSTEM_THREAD)
编辑
这是我在客户端和服务器之间发送和读取文件大小的方式。
std::stringstream stream_;
stream_.str(std::string());
// append the file size
const __int64 file_size = htonll(GetFileSize(file_handle_, nullptr););
stream_ << ' ' << file_size << ' ';
然后我用send发送这个字符串
这是我读取文件大小的方式
// Within stream_ there is all the content of the received packet
std::string message;
std::getline(stream_, message, ' ');
this->request_body_.file_size_ = ntohll(strtoll(message.c_str(), nullptr, 0));
编辑
我清理了代码,发现 read_data() 显然被调用了一次,我错误地更新了缓冲区变量。因此,我以错误的方式跟踪缓冲区内内容的大小,这让我再次调用了 recv()。
第一件事:recv()
如果没有剩余字节可供读取但连接仍处于打开状态,则会阻塞。因此,无论您怎么说您的代码在做什么,必须就是这里发生的事情。
这可能是由于以下任一原因造成的:
- 发件人谎报了文件的大小,或者没有发送承诺的字节数
- 无论什么原因,接收端都没有正确解释文件大小
- 'counts down' 接收器中剩余字节数的逻辑存在某种缺陷
问题是,查看您发布的代码示例,很难说是哪一个,因为代码有点混乱,而且在我看来,它比需要的更复杂。我会建议你解决这个问题。
- 正在发送文件的大小。
不要把它作为字符串发送。而是以二进制形式发送它,在发送端使用(比如)htonll()
,在接收端使用 ntohll()
。然后,接收方知道要准确读取 8 个字节才能弄清楚接下来会发生什么。很难弄错。
- 正在发送文件本身。
TransmitFile()
看起来是个不错的选择。坚持下去。
- 接收文件并倒数剩余字节数。
仔细查看该代码并考虑重写它。有点乱。
- 如果还是不行怎么办。
使用 WireShark 检查是否正在发送预期的数据,然后在调试器中遍历接收器中的代码。绝对没有理由不这样做,除非您出于某种原因 没有 调试器,在这种情况下请说出来,有人会尽力帮助您。登录到 cout
可以解决您的问题这一事实是在转移注意力。这只是改变了时间,然后它恰好工作正常。
就是这样。祝你好运。