Frage

Wir schreiben einen Client und einen Server zu tun (was ich dachte war) ziemlich einfache Netzwerk-Kommunikation. Mulitple Clients eine Verbindung mit dem Server, der dann sollte die Daten an alle anderen Clients senden.

Der Server befindet sich gerade in einer Sperr select Schleife für den Verkehr warten, und wenn es darum geht, sendet die Daten an die anderen Clients. Das scheint gut funktionieren.

Das Problem ist der Kunde. In Reaktion auf eine Lese wird, will es manchmal ein Schreiben tun.

Allerdings habe ich festgestellt, dass, wenn ich benutze:

 rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);

wird mein Code blockieren, bis neue Daten zu lesen ist. Aber manchmal (asynchron, von einem anderen Thread) werde ich neue Daten muß auf der Netzwerkkommunikation Thread zu schreiben. Also, ich möchte meine wählen regelmäßig aufwachen und lassen Sie mich prüfen, ob Daten zu schreiben sind, wie:

if (select(....) != -1)
{
  if (FD_SET(sockfd, &master_list))
     // handle data or disconnect
  else
     // look for data to write and write() / send() those.
}

Ich habe versucht Einstellung der zu Poll-Modus auswählen (oder lächerlich kurzes Timeouts) mit:

// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);

haben aber festgestellt, dass dann dann Client bekommt nie alle eingehenden Daten.

Ich habe auch versucht die Buchse Einstellung fd nicht blockierend sein, wie:

fcntl(sockfd, F_SETFL, O_NONBLOCK);

, aber das löst nicht das Problem:

  1. , wenn mein Kunde select() keine struct timeval hat, Daten Werke zu lesen, aber es deblockiert mich nie für beschreibbare Daten aussehen zu lassen.
  2. , wenn mein Kunde select() hat eine timeval es zu Umfrage zu bekommen, dann ist es nie Signale, dass es eingehende Daten zu lesen, und meine app gefriert denken gibt es keine Netzwerkverbindung hergestellt (trotz der Tatsache, dass alle anderen Funktionsaufrufe gelungen )

Alle Zeiger überhaupt, was könnte ich falsch tun? Ist es nicht möglich, read-write auf dem gleichen Sockel zu tun (ich kann nicht glauben, dass um wahr zu sein).

(EDIT: Die richtige Antwort, und Sache, die ich auf dem Server in Erinnerung, aber nicht auf dem Client, ist eine zweite fd_set zu haben, und kopiert Master_List vor jedem Anruf zu wählen ():

// declare and FD_ZERO read_fds:
// put sockfd in master_list

while (1)
{
   read_fds = master_list;
   select(...);

   if (FD_ISSET(read_fds))
     ....
   else
     // sleep or otherwise don't hog cpu resources
}

)

War es hilfreich?

Lösung

Alles sieht gut aus, mit Ausnahme der Linie, wo Sie if (FD_SET(sockfd, &master_list)) tun. Ich habe eine sehr ähnliche Codestruktur und ich FD_ISSET. Sie werden zu Test soll, wenn die Liste gesetzt wird, es nicht wieder zu setzen. Other than that, ich sehe nichts anderes.

Bearbeiten. Außerdem habe ich die folgenden für den Timeout:

timeval listening_timeout;
listening_timeout.tv_sec = timeout_in_seconds;
listening_timeout.tv_usec = 0;

Vielleicht gibt es ein Problem, wenn Sie es auf 0 gesetzt (wie Sie scheinen zu tun?)

EDIT2. Ich erinnerte mich, ich in ein seltsames Problem lief, als ich nicht den Lesesatz Löschte nach dem Verlassen wählen und bevor ich trat es wieder. Ich musste etwas tun, wie:

FD_ZERO(&sockfd);
FD_SET(sockfd, &rd);

, bevor ich select eintreten. Ich kann mich nicht erinnern, warum though.

Andere Tipps

Ich scheine einen Trick zu erinnern, über das Erstellen und einen Lese- / Schreib FileDescriptor zwischen dem Netzwerk-Thread und dem Haupt-Thread zu teilen, die die Deskriptoren in der Auswahl Aufruf hinzugefügt wird. Dieser fd hat einen Byte ihn vom Haupt-Thread geschrieben, wenn es etwas zu senden hat. Der Schreib weckt Netzwerk Thread aus dem ausgewählten Anruf und der Netzwerk-Thread greift dann die Daten aus einem gemeinsam genutzten Puffer und schreibt sie dann an das Netzwerk in der Auswahl wieder schlafen gehen.

Sorry, wenn das ist ein bisschen vage und der Code fehlt ... und mein Gedächtnis falsch sein .. so andere müssen möglicherweise weiter führen.

Ich habe nichts falsch mit Ihrem Code sehen, so sollte es funktionieren. Wenn Sie nicht bekommen können es funktioniert, ein Weg, um Arbeit um es wäre ein Rohr zu erstellen, indem Sie Ihre Lesegewinde und das Gewinde verwendet werden, die Dinge zum Schreiben vorbereitet, und fügen Sie das Lese Ende des Rohres zu Ihrem select Set. Dann, wenn der andere Thread bereit, Daten zu schreiben hat, sendet er nur etwas auf dem Rohr, Ihre Lese Faden wird vom select aufgeweckt, und es kann dann das Schreiben tun. Je nachdem, wie oft gibt es Daten zu lesen oder zu schreiben, diese auch effizienter sein könnten.

2 Themen sollten zu einem Zeitpunkt mit der gleichen Steckdose arbeiten können, so dass Ihr Haupt-Thread der Lage sein sollte zu einem Client, während der andere schläft in ausgewählten Warten auf eingehende Daten zu schreiben. Dies setzt natürlich voraus, dass beide Threads Zugriff auf den Client-Liste haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top