即使数据可用,C ++ Windows recv()也不会返回

时间:2018-06-09 14:53:41

标签: c++ windows sockets winsock

我正在编写一个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永远不会返回。它接收整个文件,除了几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()。

1 个答案:

答案 0 :(得分:0)

首先:recv()将阻止,如果没有剩余的字节要读,但连接仍然是打开的。所以无论你对代码的作用有什么看法,都必须成为这里发生的事情。

这可能是由于以下任何原因:

  • 发件人撒谎了文件的大小,或者没有发送承诺的字节数
  • 无论出于何种原因,文件大小未在接收端正确解释
  • “倒计时”接收器中剩余的字节数的逻辑在某种程度上是有缺陷的

麻烦的是,看看你发布的代码示例,很难说是哪个,因为代码有点混乱,在我看来,它比它需要的更复杂。我打算建议你解决这个问题。

  1. 发送文件大小。
  2. 不要把它作为一个字符串发送。使用(例如)发送端的htonll()和接收端的ntohll()以二进制方式发送它。然后,接收器知道准确读取8个字节以确定接下来会发生什么。这很难弄错。

    1. 发送文件本身。
    2. TransmitFile()看起来是个不错的选择。坚持下去。

      1. 接收文件并倒计时剩余的字节数。
      2. 仔细查看该代码并考虑重写它。这有点乱。

        1. 如果仍然无效,该怎么办。
        2. 检查WireShark是否正在发送预期数据,然后在调试器中遍历接收器中的代码。除非你因为某些原因没有拥有调试器,否则绝对没有理由不这样做,在这种情况下请说明,有人会尽力帮助你。记录到cout修复问题的事实是一个红鲱鱼。这只会改变时间,然后才恰好正常工作。

          这就是全部。祝你好运。