recv()正确使用C ++

时间:2014-03-11 13:45:49

标签: c++ loops recv

我正在使用C ++开发自己的FTP客户端,但我遇到了函数 recv()。当我使用recv()获取数据时,它们可能不完整,因为我使用 TCP 协议,因此我必须在循环中使用recv。问题是,当我收到应该收到的所有内容后收到服务器阻止,然后我的程序卡住了。 我不知道我要接收多少字节,所以我无法控制它并在完成后停止它。我现在发现了两个不太优雅的解决方案:

  1. 是使用string.substr()(或TR1正则表达式)来查找所需的 表达式,然后在阻止之前停止调用recv
  2. 第二是     设置timeval结构,然后通过控制套接字     setsockopt()函数。问题是我能得到的响应时间很长     数据不完整。
  3. 问题是,对此有什么干净而优雅的解决方案吗?

5 个答案:

答案 0 :(得分:3)

显而易见的事情是提前传输待接收消息的长度(许多协议,包括例如HTTP这样做,以解决完全相同的问题)。这样,你知道当你收到金额X时,就不会再有了。

这将在99.9%的情况下正常工作,并且在0.1%的服务器对你撒谎或服务器意外崩溃或有人偶然发现网络电缆(或类似情况发生)的情况下会发生灾难性故障。可悲的是,"连接"由TCP建立是一种幻觉,你没有多少手段来检测连接何时死亡。另一端可以关闭,你不会注意到任何事情,除非你试图发送并收到错误(或者直到几个小时之后)。

因此,您还需要一种备用策略,以确定事情不会像预期的那样好。您可以使用selectpoll来了解数据何时可用,因此您不会永远阻止永远不会发出的消息。

使用线程解决块到端问题(如其他答案中所提出的)不是一个很好的选择,因为阻塞不是实际的问题。实际问题是你不知道什么时候到达传输结束。在传输结束时有一个工作线程阻塞将工作"但是会使工作线程无限期地被阻塞,消耗资源并且具有不确定的,依赖于系统的命运。

在退出之前你不能join线程,因为它被阻止了(因此尝试join它会使你的主线程死锁)。当您的进程退出并且套接字关闭时,该线程将解除阻塞,但是(至少在某些操作系统,例如Windows上)将立即终止。这可能不会造成太大的危害,但是以不受控制的方式终止线程总是比让它正确退出更不可取。在其他操作系统上,您可能还有剩余的线程。

答案 1 :(得分:2)

由于您使用的是C ++,因此与库存C相比,有一些替代库可以极大地简化网络编程。我个人最喜欢的是Boost::Asio,但其他人可用。这些库不仅可以节省您在C中编码的麻烦,还可以提供异步功能来解决阻塞问题。

答案 2 :(得分:1)

典型方法是使用select() / pselect()poll() / ppoll()。两者都允许指定超时,以便在没有传入数据时退出。

然而,我不知道你应该如何“应该收到所有应该收到的recv”。当没有网络问题时,依赖超时也是非常低效的......

或者您发送数据的大小,数据之前,您读取的数据,或数据连接是否以EOF终止。在这种情况下,read()将返回-1并退出。

答案 3 :(得分:0)

我可以想到两个选项,不需要对现有代码进行重大改写,第三个选项更为激进:

  1. 使用non-blocking I/O并定期轮询数据。当消息不完整或者无法从套接字读取更多数据时,您可以执行其他工作。
  2. 使用单独的工作线程来执行I / O.即使它阻塞同步recv()调用,你的主线程也可以继续工作。一旦通过TCP接收到完整的消息,工作线程就可以将它接收的数据传输到主线程进行处理。
  3. 使用操作系统特定功能(Windows上的I / O完成端口或Linux上的aio),但这些功能要复杂得多,在走这条路线之前一定要考虑Boost.Asio

答案 4 :(得分:0)

你可以将recv函数放在它自己的线程中,并在另一个线程中进行处理。