How to use select and FD_SET in socket programming?

I'm new to socket programming, and it's hard for me to understand how select() and FD_SET() .

I am modifying an example from the Bay textbook, trying to understand it. What I want to do in the for loop is at each iteration, I wait 4 seconds. If reading is available, I would print β€œThe key was pressed,” and if it will time out, then it will print β€œTimeout”. Then I cleaned the kit and repeated the process another 9 times. But it seems that after the file descriptor 0 is set, it will never be canceled even after calling FD_ZERO() and / or FD_CLR() . In other words, after I press the key in the first iteration of the loop, the file descriptor is set for the remaining iterations and is no longer executed. So something must be 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 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; } 
+6
source share
2 answers

You are using FD_SET correctly. You request select() to notify you when file descriptor 0 (standard input) is ready to read. He does it. The problem is that you are not reading standard input in order to consume available input. Therefore, when you go back again and call select() , the standard input is still ready to be read, and it immediately returns.

The correct way to use select() (or poll() , which is usually the best option):

  • Set all file descriptors involved in non-blocking mode. For most cases, you want this because you want to do all the blocking inside select() (or poll() ), rather than serving separate file descriptors.
  • Configure select() or poll() to register the file descriptors that interest you.
  • Call select() or poll() .
  • Respond to the notifications that it gives you by consuming input and recordable output.
  • Go to step 2.

PS: What should your sockfd UDP socket sockfd ? You open it, but you’re not used to it.

+3
source

The problem is that you never read data from a file descriptor.

select () reports status, not events.

So, after the first selection of select (), data is always available for reading, so select () reports this immediately.

PS. You have this code, it's about 15 years old. poll () is usually more convenient than select (), and getaddrinfo () is more convenient than gethostbyname (). [And they work better].

+3
source

Source: https://habr.com/ru/post/907789/


All Articles