【问题标题】:Can the `recvfrom` function be used to check whether there have been any previous data sent to a socket? Or does it need to be actively listening?可以使用`recvfrom`函数来检查是否有任何先前的数据发送到套接字?还是需要积极倾听?
【发布时间】:2017-02-20 15:58:34
【问题描述】:

我有一个 while(1) 循环,它使用 recvfrom 获取已从另一个进程 (P2) 发送到域套接字的数据。

while循环需要做两件事,首先监听来自P2的传入数据,其次运行另一个函数checkVoltage()

所以它的运行有点像这样:

while(true)
{
    listenOnSocket() /*listens for 100 u seconds*/
    checkVoltage();
}

我的问题是:listenOnSocket() 函数使用recvfrom 函数来检查来自另一个进程的输入。它花费 100usecs 监听,然后超时并继续运行 checkVoltage() 函数。所以它在listenOnSocket() 函数中花费了大约 99% 的时间。我的问题是,如果 P2 在 checkVoltage() 函数期间向套接字发送信息,则会导致错误,说明:sending datagram message: No such file or directory

有没有办法让这个循环检查以前发送到套接字的任何数据?这样如果P2在checkVoltage()函数中发送数据,就不会报错。

谢谢。

编辑:

所以listenOnSocket() 函数创建了一个名为FireControl 的套接字,当我运行P1(从P2 接收数据的程序)时,FireControl 文件消失了片刻然后又重新出现。如果 P2 在这短时间内向 P1 发送数据,则会导致上面提到的错误。

所以我想这意味着我应该将套接字的创建与recvfrom 函数分开,因为创建新套接字的时间很短 - 如果这有意义的话。

我是个笨蛋,我一开始就应该把他们分开!

EDIT2:这里是listenOnSocket()

command listenOnSocket(int timeout, float utimeout) /*Returns null payload when no input is detected*/
{
    command payload;
    int sock;
    socklen_t* length;
    struct sockaddr_un name;
    char buf[1024];

    struct timeval tv;
    tv.tv_sec = timeout;
    tv.tv_usec = utimeout;

    /* Create socket from which to read. */
    sock = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (sock < 0) 
    {
        perror("opening datagram socket");
        payload = nullPayload;
    }

    /* Create name. */
    name.sun_family = AF_UNIX;
    strcpy(name.sun_path, NAME);

    unlink(name.sun_path);

    /* Bind the UNIX domain address to the created socket */
    if (bind(sock, (struct sockaddr *) &name, sizeof(struct sockaddr_un))) 
    {
        perror("binding name to datagram socket\n");
        payload = nullPayload;
    }

    /*Socket has been created at NAME*/
    if (timeout != 0 || utimeout != 0)
    {
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
    }
    else
    {
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
    }
    /* Read from the socket */
    if (recvfrom(sock, &payload, sizeof(command), 0, (struct sockaddr *)&name, &length) < 0) /*Less than zero results from a timeout*/
    {
        payload = nullPayload;
    }

    unlink(NAME);   
    return payload;
}

这是调用它的循环:

while (1)
    {
        buffer = getADCValue();

        checkVoltage();

        temp = listenOnSocket(0, 100); /*Look for a new command*/
        doStuffWithTempIfItHasChanged();
        }
    }

【问题讨论】:

  • "sent to a domain socket" -> 给定标签,我可以假设你的意思是 UNIX 域套接字吗?
  • 另外,您确定您的套接字完全可以工作吗? AFAIK,你不应该被困在recvfrom 中以使 P2 的send/sendto 调用成功完成,如果套接字确实存在,则消息应该排队。
  • @zneak 是的,这是一个 unix 域套接字(在 Raspbian 上运行)。套接字确实可以工作,在另一段代码中我运行listenOnSocket 没有任何超时,并且程序在等待输入时位于recvfrom 函数上。
  • 现在向问题添加更多信息
  • 这是您问题的根源。 listenOnsocket() 总是删除并创建一个新的套接字。您应该只在输入服务器代码时创建一次套接字,然后在recvfrom() 上循环。这个创建和删除循环将丢弃任何在套接字中排队的东西。

标签: c sockets unix-socket


【解决方案1】:

我想这意味着我应该将套接字的创建与 recvfrom 函数分开,因为创建新套接字的时间很短,它不存在

没错。如果您每次在listenOnSocket() 套接字中打开和关闭套接字,(a)您将丢失任何排队但您没有读取的数据报,并且(b)在套接字关闭时发送将失败......课程。没有东西可以寄给他们。

【讨论】:

    【解决方案2】:

    一旦你绑定了套接字,数据报就会累积在一个缓冲区中,以后可以使用 recvfrom 读取。也就是说,如果缓冲区溢出,消息可能会被丢弃。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 2020-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多