对poll()和recvfrom()的困惑

时间:2014-02-12 23:34:44

标签: c linux sockets polling recvfrom

我正在尝试在C中实现发送/接收原始以太网帧的协议,并且我在Linux环境中使用poll()recvfrom()遇到了一些问题。我认为我的问题主要是概念性的,所以我暂时不会发布我的代码。

我有两个用于传入数据的套接字,并且poll()用于通过其返回值和关联的pollfd结构的状态来指示任何套接字上的数据何时就绪。当我第一次运行程序时,这对我来说很有用。为了测试我只对ARP帧感兴趣,并且我能够使用poll()等待ARP帧到达。当它到达时,我调用recvfrom()将数据复制到我可以处理它的位置。所有这一切都很好。

问题是后续调用poll()会继续报告即使没有新数据到达套接字,也可以从套接字读取数据。一旦我调用recvfrom()并从套接字读取数据,我希望poll()等到新帧到达之后再报告数据就绪。我以前从未使用过poll(),所以我不确定是否需要一个明确的步骤来“清除”描述符,以便它会停止导致poll()报告数据准备好直到新的框架进来。我在调用revents之前清除pollfd结构的poll()成员,但每次调用poll()都会设置revents的值回到1。

我查看了poll()手册页,我没有找到有关此信息的运气。我觉得我误解了插槽/轮询如何在高层工作,所以任何帮助都会受到赞赏。

[编辑] 这是我的大部分代码。我实际上通过只包含一个套接字简化了这个例子的代码。所有这些都被封装在类中并展开,但重写它就像这样再现了我的问题。我的最终代码对API调用进行了错误检查,并复制了我的接收缓冲区以处理帧而不仅仅是打印内容,但除此之外它几乎相同。

#include <stdio.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <poll.h>
#include <linux/if_ether.h>

int main()
{

    uint8_t sendBuffer_[1536];
    uint8_t receiveBuffer_[1536];
    struct pollfd pollStruct[1];

    printf("Making socket...");
    int mySocket = socket( AF_PACKET, SOCK_RAW, htons(ETH_P_ARP) );
    fcntl(mySocket, F_SETFL, O_NONBLOCK);
    char *options;
    options = "eth0";
    setsockopt(mySocket, SOL_SOCKET, SO_BINDTODEVICE, options, 4);
    printf("Descriptor: %i\n", mySocket);

    while(1)
    {
        pollStruct[0].fd = mySocket;
        pollStruct[0].events = POLLIN;
        pollStruct[0].revents = 0;

        if( poll(pollStruct, 1, 0) == 1)
        {
            printf("New Frame Arrived: ");
            uint16_t frameLength = recvfrom( mySocket, receiveBuffer_, 1536, 0, NULL, NULL);

            printf("Destination MAC: ");
            for ( uint8_t i = 0; i < 6; ++i ) {
                printf("0x%x ", receiveBuffer_[i]);
            }

            printf("\nSource MAC: ");
            for ( uint8_t i = 0; i < 6; ++i ) {
                printf("0x%x ", receiveBuffer_[i + 6]);
            }

            printf("\nEtherType: ");
            for ( uint8_t i = 0; i < 2; ++i ) {
                printf("0x%x ", receiveBuffer_[i + 12]);
            }

            printf("\nPayload: ");
            for ( uint32_t i = 14; i < frameLength; ++i ) {
                printf("0x%x ", receiveBuffer_[i]);
            }
            printf("\n");

            //Clear buffer
            for ( uint32_t i = 0; i < frameLength; ++i )
                        receiveBuffer_[i] = 0;
        }
    }
}

我最初没有提到这个,但我正在尝试在Beaglebone Black上部署此代码。当我在使用GCC编译的Ubuntu的VM中运行该程序时,它可以按照我的预期工作。在接收/打印帧之后,程序在视觉上空闲直到新的到达。当我交叉编译程序并运行它时,程序会连续打印相同的数据包,直到新程序到达。由于我在receiverBuffer[]返回时清除recvfrom()recvfrom()似乎一旦将数据复制到我的缓冲区中就不会清除其内部缓冲区中的数据,因为它会不断复制数据。

1 个答案:

答案 0 :(得分:1)

我认为以下可能是一个原因 *不要在poll中设置revents.It是actullay一个输出参数 *在超时时使用一些正值。如果你想要无限的等待时间,请使用-1。参考民意调查手册页