3

我正在使用带有 epoll 的非阻塞套接字在 linux C++ 上编写一个程序,等待 EPOLLOUT 以便对某些数据执行 send()。

我的问题是:我已经读过,在非阻塞模式下,数据被复制到内核的缓冲区,因此 send() 调用可能会立即返回,表明所有数据都已发送,而实际上它只是复制到内核的缓冲区。

我如何知道远程对等方实际发送和接收数据的时间,以了解实际传输速率?

4

4 回答 4

2

您可以使用 IOCTL 获取内核套接字缓冲区中的当前数据量。这将允许您检查实际发送的内容。不过,我不确定这是否重要,除非您有大量缓冲区和少量数据要发送,否则可能不感兴趣。

调查套接字 fd 上的 TIOCOUTQ/TIOCINQ ioctl。

于 2013-07-26T10:33:23.513 回答
2

我的问题是:我已经读过在非阻塞模式下数据被复制到内核的缓冲区

这发生在所有模式中,而不仅仅是非阻塞模式。我建议你复习你的阅读材料。

因此,一个 send() 调用可能会立即返回,表明所有数据都已发送,而实际上它只是复制到内核的缓冲区中。

同样,在所有模式下都是如此。

我如何知道远程对等方实际发送和接收数据的时间,以了解实际传输速率?

发送完所有数据后,关闭套接字以进行输出,然后设置阻塞模式并读取,或者继续选择“可读”;然后在任何一种情况下都读取应该产生的 EOS。这起到了对收盘的对等确认的作用。然后停止计时器。

于 2013-07-26T10:36:36.567 回答
2

无论是否处于非阻塞模式,只要将数据复制到内核缓冲区,send 就会返回。阻塞和非阻塞模式的区别在于缓冲区满的时候。在缓冲区满的情况下,阻塞模式将暂停当前线程,直到写入发生,而非阻塞模式将立即返回 EAGAIN 或 EWOULDBLOCK。

在 TCP 连接中,内核缓冲区通常等于窗口大小,因此一旦有太多数据仍未确认,连接就会阻塞。这意味着发送方知道远程端接收数据的速度。

对于 UDP,它有点复杂,因为没有确认。这里只有接收端能够测量真实速度,因为发送的数据可能会在途中丢失。

在 TCP 和 UDP 两种情况下,内核都不会尝试发送链路层无法处理的数据。如果网络拥塞,链路层也可以流出数据。

回到你的情况,当使用非阻塞套接字时,如果你正确处理了 EAGAIN 或 EWOULDBLOCK 错误,你可以测量网络速度。这对于 TCP 来说当然是正确的,在这种情况下,您发送的数据比当前窗口大小(可能是 64K 左右)更多,您也可以了解使用 UDP 套接字的链路层速度。

于 2013-07-26T10:48:34.437 回答
1

send()只是将数据放入内核的缓冲区然后退出,让内核在后台执行实际的传输,所以你真正能做的就是测量内核接受你传出数据的速度。除非对等方为收到的每个缓冲区发送确认(并且无法检测何时收到 TCP 自己的确认),否则您无法真正测量实际的传输速度。但是,当有太多数据仍在传输中时,使用可以阻塞的事实send()可以帮助您了解您的代码将传出数据传递给send().

send()告诉您接受了多少字节。因此,很容易计算出一个近似的接受速度——用接受的字节数除以自上次调用send(). 因此,当您调用send()发送X字节并获取Y返回的字节时,将时间记录为time1send()再次调用以发送X字节并获取Y返回的字节,将时间记录为time2,您将看到您的代码以大约Y / ((time2-time1) in ms)每毫秒字节数发送数据,您可以然后根据B/KB/MB/GB per ms/sec/min/hr需要使用计算。在数据传输的整个生命周期中,这让您可以很好地了解应用程序的一般传输速度。

于 2013-07-27T02:34:18.337 回答