Nicht Blockierenden recv () - Sockets in C
Bin ich mit einer Endlosschleife in-buchsen, in denen, wenn es empfängt einige Daten, die er erhalten soll, oder wenn es will, zum senden von Daten, die es sendet. So etwas wie unten angegeben. Ich bin mit auswählen. Ich habe nur einen socket sd.
fd_set readsd;
int maxsd = readsd +1;
//all those actions of setting maxsd to the maximum fd +1 and FDSETing the FDs.
while(1)
{
FD_ZERO(&read_sd);
FD_SET(sd, &read_sd);
if(FD_ISSET(sd, &readsd))
{
//recv call
}
else
{
//send call
}
}
Soweit ich weiß, select wählt eine der socket-Deskriptoren, die auf die Daten der zuerst ankommt. Aber hier habe ich nur eine Buchse, und ich will recv wenn es einige Daten, oder ich möchte senden, sonst.
In diesem Fall ist der code, der oben angegeben Ordnung? Oder gibt es irgendeine andere Möglichkeit für mich, die ich nicht kennen?
- Da Sie nur eine Buchse zu sehen, ich verstehe nicht, wie Sie entscheiden, ob Sie senden soll oder nicht. Schließlich wählen Sie zurückkehren wird, wenn Daten angekommen und da Sie nur eine Steckdose-es ist das gleiche wie warten snchronously, es sei denn, es ist mehr, um Ihren code, mit dem Sie nicht zeigen, noch nicht. In dem obigen Beispiel, wenn Sie hinzufügen auswählen, es wird immer empfangen aber nie senden, wie Sie es geschrieben hat.
- Ja! Das ist, was ich sage. was ich Tat, war ich ein recv aufrufen, aber es blockiert Sie, bis es keine Daten zu senden. Da alle meine anderen Kunden mit demselben code, werden alle blockiert, bis er empfängt etwas. So Niemand sendet. Also, Was ich will zu tun ist, überprüfen, ob alle Daten empfangen, wenn Sie nicht gehen, um zu senden. Gibt es eine Möglichkeit?
- Ja, die Antwort von Evans. fcntl tragbar ist, so sollten Sie diesen verwenden. recv wird -1 zurück und errno wird EAGAIN oder EWOULDBLOCK, wenn es keine Daten zu Lesen. Wenn der Rückgabewert 0 ist der sockel wurde richtig geschlossen werden, sonst gibt es so viel, wie es derzeit zur Verfügung steht.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sehe ich keinen Anruf zu wählen. Auch, wenn "maxsd" ist so konzipiert, das erste argument von select, der Wert ist falsch : es muss die grösste Datei-Deskriptor +1. Trotzdem, Sie konnte einfach call recv mit der Flagge MSG_DONTWAIT, in welchem Fall es wird ein Fehler zurückgegeben, wenn es keine Daten zu Lesen.
MSG_DONTWAIT
ist nicht auf allen Plattformen. Es ist nicht angegeben POSIX und es ist nicht in der WINSOCK-Bibliothek.Darauf an... Erstens, Sie tatsächlich tun haben eine
select
nennen Sie in Ihrer richtigen code?Nun über die Sperrung... Wenn
select
kehrt mit Ihrer Steckschlüssel-Satz in der read-set, dann sind Sie garantiert, dass Sie können callrecv
ohne zu blockieren. Aber es gibt keine Garantien über die Höhe der zur Verfügung stehenden Daten. Wenn Sie UDP verwenden, dann gibt es mindestens eine (hoffentlich komplette) Paket, aber wenn Sie die TCP verwenden, erhalten Sie möglicherweise nur ein byte. Für einige Protokolle Nachricht mit Grenzen, die Sie möglicherweise nicht vollständigen Nachrichten, und Sie haben zu nennenrecv
in einer Schleife, um alle von der Nachricht, und das wird leider früher oder später verursachen dierecv
Anruf zu blockieren.Also kurz gesagt, mit
select
hilft, aber es hilft nicht in allen Fällen. Der einzige Weg, um tatsächlich zu garantieren, dass einrecv
Aufruf nicht blockieren wird, um den socket non-blocking.Ich bin nicht ganz sicher darüber, was Sie versuchen zu tun, so dass ich denken kann über zwei Optionen:
Setzen Sie einen socket, um nicht-blockierende
Da scheint, wie Sie nur eine Steckdose, können Sie den socket auf non-blocking-Modus mit
fcntl
aus und rufen Sie denrecv()
Einstellen wählen Sie timer
Mit
select
Sie können einen timer einstellen, erzwingen Sie die Rückkehr-nach einiger Zeit passiert auch wenn keine Daten empfangen.Ersten, ich finde keine
select
im code.Jedoch können Sie sich telefonisch
fcntl(fd, F_SETFL, flags | O_NONBLOCK)
ersten, um Ihre socket non-blocking. Prüfen Sie dann, oberrno == EWOULDBLOCK
wenn Sie nicht Lesen können, nichts vonrecv
. Sie brauchen nicht zu verwendenselect
in diesem Fall.