0
votes

I am using UNIX domain datagram sockets to send records from multiple clients to a single server in a multithreaded program. Everything is done within one process; I'm sending records from multiple threads to a single thread that acts as the server. All threads are assigned to separate cores using their affinity masks.

It works fine with a single client, but now I am using multiple clients. The server will read data from the socket using select() to return file descriptors that are ready ("set"), then use recvfrom to get the records.

But first I need to write the file descriptors to the fd_set struct so I can use it with select(). I created fd_set as a global struct at the top of the C file that contains the programs to open client and server sockets and pass messages between them:

fd_set fdset;

I create client sockets in this way:

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;
}

The array retvals is passed in and returned with file descriptor and client address. But to be used with select() I need to insert the file descriptor in the fd_set when the socket is created (in the program above).

Normally that wouldn't be a problem if I knew the layout of fd_set. It's defined in 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;

but from that definition I can't tell what the fields are or how to get a file descriptor or array of file descriptors into fd_set.

So my question is: how can I get the file descriptors into fd_set so it can be used with select()?

1
Tha man pages clearly explain how you do this. You have to use the FD_SET macro.Thomas Jager

1 Answers

2
votes

The way to manipulate an fd_set is with the following macros (from the man page for select()):

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);

A new fd_set must be cleared before it is used:

FD_ZERO(&my_fd_set);

To set a file descriptor in an fd_set, do:

FD_SET(my_fd, &my_fd_set);

Similarly, to remove an fd from an fd_set, do:

FD_CLR(my_fd, &my_fd_set);

To test if a file descriptor is set in an fd_set (i.e. to test which descriptors returned ready):

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