2009-11-17 71 views
1

套接字编程的新手。有几个问题:关于send/recv的问题

我的程序真的与它的输出不一致。有时我的客户收到,有时它没有收到。我每次都使用相同的输入。

  1. 只需要确认:可以在字节接待人数少于从服务器发送的字节数?

  2. 我该如何让它停止接收一次我拥有所有需要的字节?

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

感谢大家的时间:)在C++ /非阻塞的情况下做到这一点,如果这很重要的话。

回答

3
  1. 假设这是TCP(不UDP),你能想到的插座作为字节流。发件人可以以任何方式将他们置于想要的位置,并且您可以以任何方式将其取出想要的。因此,发件人可以在一次调用中写入1k块,并且如果需要,您可以一次接收一个字节。

  2. 有多种方式,但这里有两个很简单的:

    • 如果发件人发送的所有数据后,关闭套接字,接收器将接收所有发送的数据,以及接下来的recv调用将返回0,表示没有其他东西可以接收。这就是HTTP/1.0的工作原理。
    • 您可以更改协议以发送包含您要发送的数据长度的某种标头,然后recv将知道需要多少字节。使用Content-length头部,这就是HTTP/1.1的工作原理(大部分情况)。
  3. 你可以使用select来告诉你是否有任何东西,虽然它不告诉你多少。参见问题2.

2

用的recv()和非阻塞系统会给你,当你拨打电话(高达您提供缓冲区的大小),无论是当前可用的字节数。因此,如果你的发送者例如发送4K,这将在IP流上被分解成更小的分组,并且如果你对recv()的调用在第一个分组到达时发生,你只会得到(剩下的数据将在几毫秒或几秒后到达,具体取决于网络的延迟)。随后对recv()的调用将不会获得任何数据,部分或全部数据(取决于网络时间,缓冲等)。

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

也可以帮助是什么这一呼吁:

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

此调用检查前期多少字节可用于读取,所以当你随后调用的recv()将会为您献上至少该字节数(假设您提供给recv()的缓冲区足够大)。

关于如何停止你的问题:

与通过IP数据流

通常情况下,有一种方法来告诉该消息是否完整。例如。与许多RFC通信(例如与邮件服务器或http服务器交谈)命令以\ n结尾,因此如果您收到数据并且其中没有\ n,则您继续阅读,因为应该有更多。

在其他形式中,数据的开始会告诉你有多少数据会跟随。 HTTP请求的头部具有大小字段,或者通过SOCKS代理进行连接时,请求和返回数据包已定义长度。在这样的情况下,你可以循环,直到你有这个数量的数据(或直到连接失败)。

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