代码之家  ›  专栏  ›  技术社区  ›  Mark

非阻塞套接字与select()驱动方法

  •  0
  • Mark  · 技术社区  · 4 年前

    netlink 与内核对话的套接字。我使用开源库提供的简单API libmnl .

    我的应用程序在netlink上设置某些选项,并订阅netlink事件(通知),解析它等等。所以第二个特性(事件通知)是异步的,目前我实现了一个简单的 select()

    ...
    fd_set rfd;
    struct timeval tv;
    int ret;
    
    while (1) {
       tv.tv_sec = 1;
       tv.tv_usec = 0;
       FD_ZERO(&rfd);
       /* fd - is a netlink socket */
       FD_SET(fd, &rfd);
    
       ret = select(fd + 1, &rfd, NULL, NULL, &tv);
       if (ret < 0) {
         perror("select()");
         continue;
       } else if (ret == 0) {
          printf("Timeout on fd %d", fd);
       } else if (FD_ISSET(fd, &rfd)) {
           /*
                count = recv(fd, buf ...)
                while (count > 0) {
                   parse 'buf' for netlink message, validate etc.
                   count = recv(fd, buf)
                }
    
           */
       }
    }
    

    所以我现在在观察里面的代码 else if (FD_ISSET(fd, &rfd)) { 第二个分支块 recv() 打电话。

    现在我想知道是否需要将netlink套接字设置为非阻塞( SOCK_NOBLOCK recv() -> message parse -> recv()

    0 回复  |  直到 4 年前
        1
  •  0
  •   Martin Rosenau    4 年前

    ... 如果我需要将netlink套接字设置为非阻塞…,那么我可能不需要 select() 完全。。。

    这正是非阻塞套接字的目的:而不是 if(FD_ISSET(...)) 你打电话来 recv() 并计算返回值。

    如果使用阻塞套接字,则不能调用 接收() 打过不止一次电话

    然而,

    ... 正如用户“kaylum”在其评论中所建议的,在任何情况下,您都会遇到另一个问题:

    不能保证同时提供一个完整的“消息”。套接字的另一端可能发送消息的第一部分,等待几秒钟,然后发送消息的第二部分。

    然而, 将告诉您至少有一个字节可用;它不会告诉您是否有完整的消息可用。

    如果要在内部循环中等待完整的消息( while(count > 0)

    如果您只想处理所有字节 已经 在内环中可用,然后条件 count > 0 这是错误的。相反,如果您正在使用阻塞套接字,则应该执行以下操作:

    else if(FD_ISSET(...))
    {
        while(FD_ISSET(...))
        {
            count = recv(...);
            if(count > 0)
            {
                ...
                select(...);
            }
            else FD_ZERO(...);
        }
    }