2016-04-05 9 views
1

Ich muss etwas falsch machen bei der Einrichtung select() und write_fds. Momentan, wenn ich sendData() rufe, sendet es zum ersten Mal 117 Bytes (alles) aus dem Puffer. Dann wird es sofort wieder aufgerufen, auch wenn es keine Daten mehr gibt, die in den Puffer gesendet werden, und es ruft für immer sendData() an.Einrichten von Select() und Write_fds in C

Irgendeine Idee, was ich hier falsch mache?

int readData(int j){ 
    return recv(j, buf , nbytes , 0); 
} 
int sendData(int j){ 
    unsigned v = fcntl(j, F_GETFL, 0); 
    fcntl(j, F_SETFL, v | O_NONBLOCK); 

    return send(j, buf, nbytes, 0); 
} 

fd_set master; 
fd_set read_fds; 
fd_set write_fds; 
int fdmax;  
... 
FD_ZERO(&master); 
FD_SET(socket, &master); 
fdmax = socket; 

for(;;){ 
    FD_ZERO(&read_fds); 
    FD_ZERO(&write_fds); 

    read_fds = master; 
    write_fds = master; 
    if(select(fdmax+1, &read_fds, &write_fds, NULL, NULL) == -1){ 
     exit(4); 
    } 
    for(i = 0; i <= fdmax; i++){ 
     if(FD_ISSET(i, &read_fds)){ 
      if(i == socket){ 
       // handle new connections 
       addrlen = sizeof remoteaddr; 
       newfd = accept(socket, (struct sockaddr *)&addr, &addrlen); 
       FD_SET(newfd, &master); 
       if(newfd > fdmax) fdmax = newfd; 
      }else{ 
       // we got some data from a client 
       readData(i); 
      } 
     } else if(FD_ISSET(i, &write_fds)){ 
      if(i != socket){ 
       // send data when notified 
       sendData(i); 
      } 
     }  
    } 
} 
+2

Umm, stoppe den Aufruf von Code, den Sie nicht genannt wollen. –

+0

Es hat keinen Sinn, 'FD_ZERO' direkt aufzurufen, bevor Sie den gleichen fd-Satz von' master' überschreiben. – Barmar

+0

@Barmar Vielen Dank, dass Sie darauf hingewiesen haben. –

Antwort

2

Sie fragen wählen Sie benachrichtigt werden, wenn dort Platz im Netzwerk-Stack ist mehr Daten zu senden (das ist, was die write_fds werden überprüft). Da Sie nur 117 Bytes geschrieben haben, gibt es viel Platz, so dass es sofort zurückkehrt und Ihnen sagt, dass Sie mehr Daten schreiben müssen.

Da Sie nicht mehr Daten senden müssen, müssen Sie diesen Dateideskriptor aus dem write_fds-Set entfernen. Sie möchten es nur zu write_fds hinzufügen, wenn der Aufruf an send einen kurzen Schreibvorgang (nicht alle Daten schreiben) oder EWOULDBLOCK (vorausgesetzt, Sie haben es auf nicht blockierenden Modus festgelegt) zurückgegeben.

Das bringt das große Problem mit Ihrem Code mit sich - Sie rufen send/recv auf, ohne den Rückgabewert zu überprüfen, also haben Sie keine Ahnung, wie viele Daten tatsächlich gesendet oder empfangen wurden.

+0

Danke. Ich behalte den Rückgabewert von 'send/recv 'im Auge und gebe eine' -1 'und' EWOULDBLOCK 'zurück. Obwohl ich nicht sicher bin, verstehe ich den Teil, den Sie sagten, ich sollte die fd aus 'write_fds' und auf einen kurzen schreiben oder' EWOULDBLOCK' entfernen. Meinst du ein 'if (sended <= 0) FD_SET (i, & master); sonst FD_CLR (i, & master); '? –

+0

@PeteDarrow: Im obigen Code ist 'master' die Vereinigung von' read_fds' und 'write_fds' - im Allgemeinen möchten Sie sie getrennt verfolgen und verwalten. Also, was Sie wollen, ist etwas mehr wie 'If (sended

0

Steckdosen sind fast immer beschreibbar. Sie sollten nur dann auf einen Socket für die Schreibbarkeit auswählen, wenn Sie zuvor einen EAGAIN/EWOULDBLOCK von einem send() hatten, und Sie sollten damit aufhören, wenn der Schreibvorgang wiederholt und erfolgreich ausgeführt wurde.