I am new to socket programming, and I am having trouble understanding how select()
and FD_SET()
works.
I modify an example from Beej's tutorial in an attempt to figure it out. What I want to do in the for loop is at each iterations I wait for 4 seconds. If a read is available, I would print "A key was pressed" and if it timeout, then it would print "Timed out." Then I would clear the set and repeat the process 9 more times. But it seems that once file descriptor 0 is set, it never gets unset even after a call to FD_ZERO()
and/or FD_CLR()
. In other words after I press a key in the first iteration of the loop the file descriptor is set for the rest of the iterations and no more waiting is done. So there must be something I am missing, but I don't know what.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT 4950
int main(int argc, char *argv[]) {
struct sockaddr_in their_addr; // connector's address information
struct hostent *he;
int numbytes;
int broadcast = 1;
if ((he=gethostbyname(argv[1])) == NULL) { // get the host info
perror("gethostbyname");
exit(1);
}
// this call is what allows broadcast packets to be sent:
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof broadcast) == -1) {
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
their_addr.sin_family = AF_INET; // host byte order
their_addr.sin_port = htons(SERVERPORT); // short, network byte order
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
struct timeval tv;
fd_set broadcastfds;
int i;
for(i=0; i < 10; i++) {
tv.tv_sec = 4;
tv.tv_usec = 500000;
FD_ZERO(&broadcastfds);
FD_CLR(0, &broadcastfds);
FD_SET(0, &broadcastfds);
if(select(0+1, &broadcastfds, NULL, NULL, &tv) == -1) perror("select");
if (FD_ISSET(0, &broadcastfds)) printf("A key was pressed!\n");
else printf("Timed out.\n");
fflush(stdout);
}
close(sockfd);
return 0;
}
You are using FD_SET
correctly. You are asking select()
to notify you when file descriptor 0 (standard input) is ready for reading. It does this. The problem is that you are not reading standard input to consume the input that is available. So when you loop back and call select()
again, standard input is still ready for reading and it returns immediately.
The correct way to use select()
(or poll()
, which is usually a better option) is:
select()
(or poll()
), not while servicing individual file descriptors.select()
or poll()
to register which file descriptors you are interested in.select()
or poll()
.P.S.: What does your UDP socket sockfd
have to do with anything? You open it but it doesn't get used for anything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With