Reputation: 2323
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.
My problem is when I use select() to retrieve records from client sockets that have records in the socket buffer. I am using the same basic setup I used with a single client socket (and it worked in that context), but now it hangs (apparently it blocks) when I call recvfrom. That's surprising because the select() function has already identified the socket as available for reading.
int select_clientsockets(int64_t srvrfd, int64_t * claddr, int fds_array[], int fd_count, void * recvbuf){
int fds_ready;
int abc;
int64_t cli_addr;
FD_ZERO(&fdset);
FD_SET(0,&fdset);
socklen_t * len = (socklen_t * ) sizeof(struct sockaddr_un);
fds_ready = select(3, &fdset, NULL, NULL, 0);
for (int i = 0; i < fd_count; i++){
fds_array[i] = 0;
if (FD_ISSET(i, &fdset)) {
fds_array[i] = 1;
cli_addr = claddr[i];
server_receive(srvrfd, recvbuf, 720, cli_addr);}
}
return 0;
}
The select function calls server_receive on clients where select says data are available:
int64_t server_receive(int64_t sfd, void * buf, int64_t msgLen, int64_t claddr)
{
socklen_t * len = (socklen_t * ) sizeof(struct sockaddr_un);
int numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) claddr, len);
if (numBytes == -1)
return 0;
return numBytes;
}
The client socket address is taken from the 3-element array "claddr" (for 3 client sockets) where the corresponding position for each client socket is filled in when the socket is created. At socket creation I also call FD_SET to set the client address into the fd_set. I think I should get the client socket address from fd_set instead, BUT they're both the same pointer value so I don't know why that would make a difference. For internet domain datagram sockets we can use getpeername() but I don't know if there is an analogous function for UNIX domain sockets -- or even if that's the problem.
Thanks very much for any help with this.
UPDATE:
Client fds are added to the global fdset struct on socket creation:
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());
FD_SET(sfd,&fdset);
retvals[0] = sfd;
retvals[1] = (int64_t)&claddr;
return retvals;
}
Upvotes: 0
Views: 394
Reputation: 182761
FD_ZERO(&fdset);
FD_SET(0,&fdset);
socklen_t * len = (socklen_t * ) sizeof(struct sockaddr_un);
fds_ready = select(3, &fdset, NULL, NULL, 0);
for (int i = 0; i < fd_count; i++){
fds_array[i] = 0;
if (FD_ISSET(i, &fdset)) {
Your code empties fdset
then adds only 0
to fdset
. So when you call select
and pass it fdset
, you are asking it only to check socket 0
for readiness.
You later check if sockets 0
to one less than fd_count
are in fdset
, but only zero could possibly be because it's the only one you asked about.
Where is the list of sockets you want to check for readiness?
Upvotes: 2