关于发送/接收的问题

时间:2009-11-17 23:23:29

标签: c++ networking sockets

套接字编程新手。有几个问题:

我的程序与其输出实际上不一致。有时我的客户收到,有时它不会。我每次也使用相同的输入。

  1. 只需要确认:收到的字节数是否可以小于服务器发送的字节数?

  2. 如果我拥有所需的所有字节,我该怎么做才能停止接收?

  3. 客户端有没有办法知道它“接收”了多少字节,以便我可以将recv置于while循环中?

  4. 感谢每个人的时间:)如果重要的话,在C ++ / non阻止中执行此操作。

2 个答案:

答案 0 :(得分:3)

  1. 假设这是TCP(不是UDP),您可以将套接字视为字节流。发件人可以以想要的任何方式将它们放入,并且您可以以想要的任何方式将它们取出。因此,发件人可以在一次调用中写入1k块,如果需要,您可以一次接收一个字节。

  2. 有很多方法,但这里有两个相当简单的方法:

    • 如果发送方在发送所有数据后关闭套接字,接收方将接收所有发送的数据,下一次对recv的调用将返回0,表示没有其他内容可以接收。这就是HTTP / 1.0的工作原理。
    • 您可以更改协议以发送某种包含您要发送的数据长度的标头,然后recv将知道预期的字节数。使用Content-length标头,这就是HTTP / 1.1的工作方式(大部分都是如此)。
  3. 您可以使用select告诉您是否有任何内容,但它不会告诉您多少。见问题2。

答案 1 :(得分:2)

使用recv()和非阻塞系统会在您拨打电话时为您提供当前可用的字节数(最大为您提供的缓冲区的大小)。

因此,如果您的发送方例如发送4K,则会通过IP流将其分解为较小的数据包,如果您在第一个数据包到达时调用recv(),则只能获得该数据包(其余部分)数据将在几毫秒或几秒后到达,具体取决于网络的延迟。对recv()的后续调用将获得无,部分或全部其余数据(取决于网络时序,缓冲等)。

此外(使用非阻塞IO)recv()可以返回一个EAGAIN的rc,这意味着此时没有数据可用。在这种情况下,通常使用select()调用等待某些内容可用并再次调用recv()。

这也可能对此有所帮助:

int err, avail= 0;
err= soioctl(skt FIONREAD, (char*)&avail);

此调用预先检查可读取的字节数,因此当您随后调用recv()时,将至少为此字节数提供服务(假设您为recv()提供的缓冲区足够大)。

关于如何停止的问题:

通常使用IP流上的数据,有一种方法可以判断消息是否完整。例如。与许多RFC通信(例如与邮件服务器或http服务器通信)命令以\ n终止。因此,如果您收到数据并且其中没有\ n,则继续阅读,因为应该有更多。

在其他形式中,数据的开头将有一些方法告诉您将跟随多少数据。 HTTP请求的标头具有大小字段,或者在通过SOCKS代理建立连接时,请求和返回数据包已定义长度。在这样的情况下,您可以循环,直到您有该数量的数据(或直到连接失败)。

但这确实是在流上定义协议的问题,即发送方和接收方必须建立某种协议如何发送数据。 IMAP服务器读取最多\ n的命令并处理它们,打印服务器可能会读取所有数据,直到连接终止(recv()失败并且rc <0)而另一个协议可能只是前两个字节作为长度字段来告诉将跟随多少数据。