【问题标题】:C UNIX datagram sockets -- how to get file descriptor into fd_setC UNIX 数据报套接字——如何将文件描述符放入 fd_set
【发布时间】:2020-09-08 12:39:46
【问题描述】:

我正在使用 UNIX 域数据报套接字将记录从多个客户端发送到多线程程序中的单个服务器。一切都在一个过程中完成;我将记录从多个线程发送到充当服务器的单个线程。所有线程都使用它们的关联掩码分配给单独的核心。

它适用于单个客户端,但现在我使用多个客户端。服务器将使用 select() 从套接字读取数据以返回准备好的文件描述符(“set”),然后使用 recvfrom 获取记录。

但首先我需要将文件描述符写入 fd_set 结构,以便我可以将它与 select() 一起使用。我在 C 文件的顶部创建了 fd_set 作为全局结构,其中包含打开客户端和服务器套接字并在它们之间传递消息的程序:

fd_set fdset;

我以这种方式创建客户端套接字:

int64_t * create_socket_client(struct sockaddr_un claddr, int64_t retvals[])
{
    int sfd, j;
    size_t msgLen;
    ssize_t numBytes;
    char resp[BUF_SIZE];

    retvals[0] = 0;
    retvals[1] = 0;

    sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (sfd == -1)
        return retvals;

    memset(&claddr, 0, sizeof(struct sockaddr_un));
    claddr.sun_family = AF_UNIX;
    snprintf(claddr.sun_path, sizeof(claddr.sun_path),  "/tmp/ud_ucase_cl.%ld", (long) getpid());

    retvals[0] = sfd;
    retvals[1] = (int64_t)&claddr;

     return retvals;
}

数组 retvals 传入并与文件描述符和客户端地址一起返回。但是要与 select() 一起使用,我需要在创建套接字时(在上面的程序中)将文件描述符插入到 fd_set 中。

如果我知道 fd_set 的布局,通常不会有问题。它在 sys/select.h 中定义:

/* fd_set for select and pselect.  */
typedef struct
  {
    /* XPG4.2 requires this member name.  Otherwise avoid the name
       from the global namespace.  */
#ifdef __USE_XOPEN
    __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
    __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif
  } fd_set;

但是从那个定义我不能知道字段是什么或如何将文件描述符或文件描述符数组放入 fd_set。

所以我的问题是:如何将文件描述符放入 fd_set 以便与 select() 一起使用?

【问题讨论】:

  • 手册页清楚地解释了你是如何做到这一点的。您必须使用 FD_SET 宏。

标签: c linux sockets


【解决方案1】:

操作fd_set 的方法是使用以下宏(来自select()man 页面):

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

新的fd_set在使用前必须清除:

FD_ZERO(&my_fd_set);

要在fd_set 中设置文件描述符,请执行以下操作:

FD_SET(my_fd, &my_fd_set);

同样,要从 fd_set 中删除 fd,请执行以下操作:

FD_CLR(my_fd, &my_fd_set);

测试是否在fd_set 中设置了文件描述符(即测试哪些描述符返回就绪):

if (FD_ISSET(my_fd, &my_fd_set)) {
    // Take action on my_fd
}

【讨论】:

  • 这是所有正确信息,但不要使用fd_setselect。如果 fd 限制设置为高于 FD_SETSIZE(可由调用用户配置),该 API 很危险,并且会固有地导致缓冲区溢出,并且在各方面都不如现代的 poll API,后者也是 POSIX 标准的一部分.您应该使用poll 代替选择。它也更容易使用。
  • @R..GitHubSTOPHELPINGICE -- 感谢您的评论。我一直在阅读 select 和 poll 之间的区别(事实证明并不多),我很高兴你这么说,因为它可以帮助我做出选择。
猜你喜欢
  • 2020-10-31
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 2012-10-01
相关资源
最近更新 更多