Wie zu benutzen wählen Sie und FD_SET in socket Programmierung?
Ich bin neu auf socket-Programmierung, und ich habe Schwierigkeiten zu verstehen, wie select()
und FD_SET()
funktioniert.
Ich ändern, ein Beispiel von Beej ' s tutorial in einem Versuch, um es herauszufinden. Was ich tun möchte in der for-Schleife wird bei jedem Iterationen warte ich auf 4 Sekunden. Wenn ein Lesen verfügbar ist, ich würde print "Eine Taste wurde gedrückt" und wenn timeout, dann würde es drucken "Timed out." Dann würde ich klar den Satz und wiederholen Sie den Vorgang 9 weitere Male. Aber es scheint, dass, sobald Datei-Deskriptor 0 ist gesetzt, es wird nie gelöscht, auch nach einem Aufruf FD_ZERO()
- und/oder FD_CLR()
. In anderen Worten, nachdem ich eine Taste drücken, die in der ersten iteration der Schleife, die den Datei-descriptor für den rest der Iterationen und nicht mehr zu warten, ist fertig. Es muss also etwas sein, was ich bin fehlt, aber ich weiß nicht, was.
#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;
}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie mit
FD_SET
richtig. Sie Fragenselect()
um Sie zu Benachrichtigen, wenn die Datei-Deskriptor 0 (Standardeingabe) ist bereit zum Lesen. Es tut dies. Das problem ist, dass Sie nicht Lesen von der Standardeingabe zu konsumieren, die input -, die verfügbar ist. Also, wenn Sie loop-back-und call -select()
wieder, die standard-Eingabe ist immer noch bereit zum Lesen und es gibt sofort einen Wert zurück.Den richtigen Weg, um
select()
(oderpoll()
, die in der Regel eine bessere option ist):select()
(oderpoll()
), nicht während der Wartung einzelner Datei-Deskriptoren.select()
oderpoll()
zu registrieren, die Datei-Deskriptoren, die Sie interessiert sind in.select()
oderpoll()
.P. S.: Was macht der UDP-socket
sockfd
haben damit zu tun? Sie es öffnen, aber es wird nicht für alles verwendet.Das problem ist, dass Sie nie Lesen der Daten aus der Datei descriptor.
wählen Sie() Berichte Staat, keine Ereignisse.
Also nach dem ersten mal, wählen Sie() gibt, es gibt immer Daten zum Lesen zur Verfügung, so wählen Sie() berichtet, dass sofort.
PS. Wo immer Sie sind zu bekommen, dass der code aus, es sieht etwa 15 Jahre alt. poll() ist in der Regel bequemer als select () und getaddrinfo() ist bequemer als gethostbyname(). [Und Sie arbeiten besser, zu].