2016-04-03 9 views
0

Also baue ich einen Chat-Server, jetzt versuche ich, alle Nachrichten vom Client zu echo. Momentan, sobald ich die Nachricht bekomme, sende ich sie innerhalb readData() zurück. Aber sobald ich es senden, benachrichtigt select() die write_fds und sendData() genannt wird, auch schon ich send() genanntOrdnungsgemäße Methode zum Senden von Daten bei Verwendung von select() und write_fds in C

Die meisten meiner Anrufe Daten innerhalb des readData() wäre zu senden.

  • Ist dies der richtige Weg select() und write_fds zu verwenden?
  • Wie kann ich select() benachrichtigen, dass ich Daten ohne zwei Anrufe an send() senden möchte?

Es scheint redundant zu mir mit zwei Anrufe zu send() zu beschäftigen.

int readData(int j){ 
    // get message from the client 
    recv(j, client_buffer , 6000 , 0); 
    // echo message to the client 
    send(j, client_buffer, strlen(client_buffer)); 
} 
int sendData(int j){ 
    send(j, buf, nbytes, 0); 
} 

for(;;){ 
    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 == listener){ 
       // handle new connections 
       addrlen = sizeof remoteaddr; 
       newfd = accept(listener, (struct sockaddr *)&addr, &addrlen); 
       FD_SET(newfd, &master); 
       if(newfd > fdmax) fdmax = newfd; 
      }else{ 
       // we got some data from a client 
       readData(i); 
      } 
     } 
     if(FD_ISSET(i, &write_fds)){ 
      if(i != listener){ 
       // send data when notified 
       sendData(i); 
      } 
     }  
    } 
} 
+0

1) (hier TCP vorausgesetzt) ​​send() und recv haben einen Rückgabewert. benutze es. Und beschäftigen Sie sich mit partiellen Lese-/Schreibvorgängen. 2) Sie können strlen() im Puffer nach dem Empfang nicht verwenden, da es nicht unbedingt NUL-terminiert ist. 3) Eine -1 Rückkehr von send/recv/select ist nicht immer ein Fehler. Es könnte sich um einen unterbrochenen Systemaufruf, einen EWOULDBLOCK oder auch um einen Out-of-Resource-Zustand handeln. 4) nach dem accept() möchten Sie wahrscheinlich das new_fd zu den gelesenen fd_fds hinzufügen. – wildplasser

+0

'TCP', das ist richtig. Danke, dass Sie das 'strlen()' hervorgehoben haben. Über den Rückgabewert, also sagst du, dass es immer zwei Aufrufe von 'send()' geben wird, aber ich muss nur verfolgen, wie viele Daten der erste Anruf gesendet hat und den Rest im zweiten oder dritten Anruf senden? –

+0

Ich habe nur auf die offensichtlichen Fehler hingewiesen. IMHO wird es niemals einen 2. oder 3. Aufruf geben, da das neue fd nicht im write fd_set ist und auch nicht im read_set. (beide sind Kopien des Master-Sets) – wildplasser

Antwort

0

würde ich nicht vorschlagen sendData() direkt innerhalb von readData() aufrufen. Sie sollten getrennt gehalten werden. Lassen Sie readData() die empfangenen Daten an den Anrufer zurück und lassen Sie den Anrufer entscheiden, was damit zu tun ist. Möchte der Anrufer Daten senden, kann er bei Bedarf sendData() anrufen.

Um das select() Problem zu beheben, müssen Sie einen pro-Socket-Puffer für ausgehende Daten erstellen. Stellen Sie sicher, dass der Socket im nicht blockierenden Modus ausgeführt wird.

  1. Wenn sendData() aufgerufen wird, wenn der Puffer leer ist, send() so viel von den Daten des Anrufers wie möglich. send() gibt zurück, wie viele Bytes tatsächlich akzeptiert wurden. Wenn send() einen Fehler oder EAGAIN meldet, beenden Sie das Senden und fügen Sie alle nicht gesendeten Daten an das Ende des Puffers an.

  2. Wenn sendData() aufgerufen wird, wenn der Puffer nicht leer ist, fügen Sie einfach die neuen Daten an das Ende des Puffers und Ausfahrt ohne send() überhaupt zu anrufen.

Wenn select() meldet eine Buchse beschreibbar ist, send(), was zur Zeit in dem Socket-Puffer zwischengespeichert wird, wenn überhaupt. Entfernen Sie für jede erfolgreiche send() die gemeldete Anzahl der Bytes von der Vorderseite des Puffers. Stoppen Sie das Senden, wenn der Puffer erschöpft ist oder send() fehlschlägt.

+0

Danke, jetzt sinnvoll. Übrigens, weißt du, was ein Puffer mit guter Größe für ausgehende Daten wäre, z. B. BUFSIZ? Oder sollte es dynamisch sein und die Größe ändern, d. H. "Realloc"? Ich bin gespannt, was hier üblich ist. –

+0

@PeteDarrow der ausgehende Puffer sollte dynamisch sein, da Sie nicht wissen, wie viele Daten am Ende zwischengespeichert werden müssen, aber Sie können sie in sinnvollen Schritten nach Bedarf neu anordnen. Zum Beispiel in 1kb-Schritten. Oder vielleicht in Delta-Mengen, wie 256 Bytes, dann 512 Bytes, dann 1 kB usw. Oder aufgerundet auf ein Vielfaches eines anständigen Wertes. Es hängt wirklich davon ab, wie viele Daten Sie senden werden. Versuchen Sie, es so oft wie möglich neu zuzuweisen, aber so oft wie möglich wiederzuverwenden. –

Verwandte Themen