gpt4 book ai didi

c - 有没有比 select() 和 poll() 更快的非阻塞方法来检查数据?

转载 作者:IT王子 更新时间:2023-10-29 00:43:33 24 4
gpt4 key购买 nike

我有一个 C 程序使用 sendto() 方法尽可能快地从发送方向接收方发送数据,接收方使用 recvfrom() 方法接收数据。数据被封装到第 2 层以太网帧中,应用程序将以太网帧直接写入线路(没有 TCP 或 UDP 甚至 IP)。这是在 x86_64 Linux 上(开发机器只是股票 Ubuntu 14.04)。我无意移植到任何其他操作系统,应用程序设计范围是针对 Linux 的,因此其他操作系统无关紧要。

发件人:

    while (true)
{
sendResult = sendto(sockFD, txBuffer, fSize+headersLength, 0,
(struct sockaddr*)&socket_address, sizeof socket_address);
}

接收方:

    while (true)
{
recvfrom(sockFD, rxBuffer, fSizeTotal, 0, NULL, NULL);
}

我希望发件人能够检查收到的数据包;如果接收方应用程序退出,它会将数据发送回发送方说“我退出”,以便发送方停止发送数据。我在发件人上使用 poll() 来检查收到的消息,如下所示,但这显着降低了传输速度,从略低于 1Gbps (968Mbps) 到大约 10Mbps。我正在使用两台具有 1Gbps NIC 的 PC 之间的交叉电缆进行测试。发送方对发送的帧和帧大小进行计数,接收方对接收到的帧和帧大小进行计数,因此为了确认,应用程序实际上以足够接近的线速接收,我不只是看 NIC 利用率或类似情况。

轮询() 方法:

int rv;
struct pollfd ufds[1];
ufds[0].fd = sockFD;
ufds[0].events = POLLIN


while (true)
{
sendResult = sendto(sockFD, txBuffer, fSize+headersLength, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));

// wait for events on the sockets, 1ms timeout
rv = poll(ufds, 1, 1);

if (rv > 0) {
if (ufds[0].revents & POLLIN) {
recvfrom(sockFD, rxBuffer, fSizeTotal, 0, NULL, NULL);
}
}

}

1 毫秒是可以为 poll() 方法设置的最短超时时间。这就是为什么我的传输程序只能以 10Mbps 传输。该应用程序可以轻松地使 1Gbps 的链接饱和,尽管 CPU 使用率极低,正如我之前所说的那样,我获得了 968Mbps(顺便说一下,我不是指峰值,这是持续的吞吐量)。

我删除了 poll() 调用并使用下面的示例切换到 select(),但再次使用我可以在这里使用的最小延迟,我的传输应用程序只能获得 175Mbps。不接近原来的968Mbps;

Select() 方法:

fd_set readfds;
struct timeval tv;
int rv, n;

FD_ZERO(&readfds);
FD_SET(sockFD, &readfds);
n = sockFD + 1;


while (true)
{
sendResult = sendto(sockFD, txBuffer, fSize+headersLength, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));

tv.tv_sec = 0;
tv.tv_usec = 000001;
rv = select(n, &readfds, NULL, NULL, &tv);
if (rv > 0) {
if (FD_ISSET(sockFD, &readfds)) {
recvfrom(sockFD, rxBuffer, fSizeTotal, 0, NULL, NULL);
}

}

对于今天的系统来说,这两种方法似乎都太慢了(对于上述所有测试,我的 CPU 使用率约为 2%)。我希望尽快将此应用程序移动到一些 10GigE 机器上并在那里开始测试,但我显然不能使用这两种方法中的任何一种。有没有更快的方法可以检查?

虽然这些应该是非阻塞的,但是通过要求超时它们在某种程度上是阻塞的;我看过this thread但这不是我需要的答案。有没有我可以简单地调用它的方法来检查它被调用的那一刻,等待读取的数据,然后如果没有数据等待读取则立即返回?

作为辅助节点,在发布此之前我还没有阅读 recvfrom 方法()以查看延迟在哪里,但我确实尝试了以下方法,因为更改代码只花了 30 秒,结果是低于 1Mbps 的最差结果;

发件人:

    while (true)
{
// Continually send a frame then check for a frame, send a frame then check for a frame...
sendResult = sendto(sockFD, txBuffer, fSize+headersLength, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
recvfrom(sockFD, rxBuffer, fSizeTotal, 0, NULL, NULL);
}

最佳答案

我根本不会使用非阻塞模式。只需在阻塞模式下专用一个线程。这样一来,您只需执行一个系统调用:recvfrom(),这样您就可以将上下文切换保存到内核中。

关于c - 有没有比 select() 和 poll() 更快的非阻塞方法来检查数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23922842/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com