TCP select blocks ohne sendback

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Wir sind Opfer einer Spamattacke geworden. Der Provider hat uns daher vom Netz genommen. Wir hoffen, dass jetzt wieder alles rund läuft. - Sorry für den Ausfall.

  • TCP select blocks ohne sendback

    Ich versuche mich gerade erstmals an Server/Client-Anwendungen. Das Projekt ist in C geschrieben. Habe dazu entsprechend dem Lehrbuch eine TCP-Verbindung erstellt, deren Scckets ich serverseitig ohne threads sondern in einer Schleife mit select() auf Aktivität prüfe.

    Wenn ein Socket aktiv wird empfange ich die Nachricht und gebe testweise die Nachricht mit printf() aus. Sofern ich nach jedem receive() einer Nachricht dem Client etwas zurückschicke läuft die Sache prima. Wenn ich auf das zurückschicken verzichte, dann blockiert das select() beim zweiten Aufruf (nach dem Empfang der ersten Nachricht) und es ist kein weiteres receive() möglich. Das select() erwacht erst wieder wenn der Client beendet wird. Allerdings kommt dann nur mehr ein receive() mit Länge 0, das die Beendigung der Verbindung durch den Client mitteilt.

    Gehört das so oder stimmt noch etwas nicht mit meinem Code ? Kennt sich hier jemand mit sowas aus ?

    Danke für jeden Tipp!
  • Thomas schrieb:

    Ich versuche mich gerade erstmals an Server/Client-Anwendungen. Das Projekt ist in C geschrieben. Habe dazu entsprechend dem Lehrbuch eine TCP-Verbindung erstellt, deren Scckets ich serverseitig ohne threads sondern in einer Schleife mit select() auf Aktivität prüfe.

    Wenn ein Socket aktiv wird empfange ich die Nachricht und gebe testweise die Nachricht mit printf() aus. Sofern ich nach jedem receive() einer Nachricht dem Client etwas zurückschicke läuft die Sache prima. Wenn ich auf das zurückschicken verzichte, dann blockiert das select() beim zweiten Aufruf (nach dem Empfang der ersten Nachricht) und es ist kein weiteres receive() möglich. Das select() erwacht erst wieder wenn der Client beendet wird. Allerdings kommt dann nur mehr ein receive() mit Länge 0, das die Beendigung der Verbindung durch den Client mitteilt.

    Gehört das so oder stimmt noch etwas nicht mit meinem Code ? Kennt sich hier jemand mit sowas aus ?

    Danke für jeden Tipp!
    Hallo Thomas,

    Du solltest an dieser Stelle lieber einen Thread verwenden. Serverseitig blockiert Deine Schleife ansonsten evtl. weitere Aktivitäten.

    Das Verhalten ist, wie Du es beschrieben hast, völlig i.O.. Du müsstet bevor Du etwas sendest, nachfragen ob der Empfänger bereit ist zu empfangen.
    Alternativ kannst Du auch zyklisch ein "Hallo wach" versenden, damit verhinderst Du, dass die Verbindung quasi "schlafen" gelegt wird.

    Um sicherzustellen, dass der Netzwerktraffic nicht allzu sehr zunimmt und andere Threads ebenfalls Daten empfangen und senden können, wird dieses Verfahren (wie von Dir beschrieben) angewendet.

    Du musst Dir dies so vorstellen: Eine Telefonleitung an deren beiden Enden mehrere Teilnehmer (Telefone) angeschlossen sind. Telefonieren nun zwei Teilnehmer miteinander, dann wäre die Leitung für alle anderen nicht mehr nutzbar. Um dem aus dem Weg zu gehen wird an jedem Ende ein sogenannter Multiplexer eingesetzt. Dieser schaltet binnen kürzester Zeit zyklisch alle aktiven Leitungen durch. Hierdurch können mehrere Teilnehmen quasi gleichzeitig telefonieren. Merken jedoch aufgrund der minimalen Unterbrechungen nicht, dass sie die Leitung nicht exklusiv für sich nutzen. Nicht mehr aktive Gespräche werden dabei nicht beachtet, da ja kein Informationsfluss während dieser Pausen stattfindet.

    Dies ist nun nicht der vollständige Prozess der sich dahinter verbirgt, sollte aber ausreichen um die Methode zu verstehen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von OSXDev () aus folgendem Grund: Korrektur

  • @ OSXDev:

    Einen eigenen Thread dafür hab ich. Ist schon deshalb nötig, weil bei mir der Server das UI hat und nicht der Client.
    Das Multiplexing hab ich soweit verstanden. So möchte ich es auch haben. Was da im Hintergrund läuft scheint mir hingegen etwas dubios.

    Hab nochmal rumgetestet und gesehen, dass der Server genau dann empfängt wenn der Client nach dem senden ein receive() anfordert. Das receive im server liefert also nur dann etwas wenn der client auch ein receive aufruft. Umgemünzt auf das Beispiel mit den Telefonaten würde das bedeuten, dass der Angerufene solange nichts hört bis der Anrufer "Verstanden ?" fragt. Dachte eigentlich der Sender und der Empfänger können unabhängig voneinander senden und empfangen. Die Reihenfolge der Messages bleibt doch erhalten und nur das ist wichtig. Nur so können die beiden unabhängig voneinander werken, oder ?

    So wie es derzeit läuft müsste der Server zwei Antworten auf eine Anfrage senden. Nämlich eine für den Empfang der Anfrage (weil der Client darauf wartet und sonst nicht weitermachen kann) und später eine für das Ergebnis der Anfrage. Wobei die zweite Antwort wiederum vom Client bestätigt werden muss (weil der Server sonst nicht weitermacht). Es macht doch wenig Sinn sowas händisch zu implementieren und wäre wesentlich besser im TCP aufgeoben. Beide Seiten sollen senden wenn sie etwas mitzuteilen haben und empfangen wenn sich dazu bereit sind. Wie kann man denn einen Empfänger fragen ob er bereit ist ?

    Hmm, ich glaub ich habs noch nicht verstanden...

    @manoh
    Code stammt aus dem Buch "Linux-Unix Programmierung" und ist auch in diversen anderen Beispielen gleich.
  • Thomas schrieb:

    @ OSXDev:

    ...

    Hab nochmal rumgetestet und gesehen, dass der Server genau dann empfängt wenn der Client nach dem senden ein receive() anfordert. Das receive im server liefert also nur dann etwas wenn der client auch ein receive aufruft. Umgemünzt auf das Beispiel mit den Telefonaten würde das bedeuten, dass der Angerufene solange nichts hört bis der Anrufer "Verstanden ?" fragt. Dachte eigentlich der Sender und der Empfänger können unabhängig voneinander senden und empfangen. Die Reihenfolge der Messages bleibt doch erhalten und nur das ist wichtig. Nur so können die beiden unabhängig voneinander werken, oder ?

    So wie es derzeit läuft müsste der Server zwei Antworten auf eine Anfrage senden. Nämlich eine für den Empfang der Anfrage (weil der Client darauf wartet und sonst nicht weitermachen kann) und später eine für das Ergebnis der Anfrage. Wobei die zweite Antwort wiederum vom Client bestätigt werden muss (weil der Server sonst nicht weitermacht). Es macht doch wenig Sinn sowas händisch zu implementieren und wäre wesentlich besser im TCP aufgeoben. Beide Seiten sollen senden wenn sie etwas mitzuteilen haben und empfangen wenn sich dazu bereit sind. Wie kann man denn einen Empfänger fragen ob er bereit ist ?

    ...
    Du hast das Handshake-Verfahren doch genauestens beschrieben, wenn auch die Wortwahl etwas unglücklich gewählt scheint. Wahrscheinlich liegt darin Deine Herausforderung.

    1. Connect zwischen Client und Server etabliert
    2. Client/Server vergewissert sich beim Server/Client ob dieser empfangsbereit ist (wenn an dieser Stelle bereits Daten gesendet werden; empfängt der Server diese ohne auf diese Anfrage zu bestehen)
    3. Client/Server erhält Bestätigung über die Empfangsbereitschaft des Server/Client und sendet dann seine Daten; ansonsten Fehlerauswertung
    3a. Client/Server oder vice versa bestätigen den ordnungsgemäßen Empfang der Daten (nicht immer der Fall)

    4. Es werden keine Daten/Anfragen an den Server/Client bzw. vice versa an den Client/Server gestellt. Connect besteht weiterhin, ruht also.

    5. Client/Server bzw. Server/Client will Daten senden; in diesem Fall geht es nun wieder bei Punkt 2. weiter.

    6. Genügend Daten ausgetauscht -> nicht vergessen den Connect ordnungsgemäß zu schließen.

    Hierdurch ist sichergestellt, dass Client und Server unabhängig Daten untereinander austauschen können.

    Nachtrag: In der Regel wird der Connect vom Client aufgebaut. Nicht vergessen, der Server kann ebenfalls ein Connect zum Client etablieren. :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von OSXDev () aus folgendem Grund: Nachtrag

  • Hast Du schon mal überprüft, ob der Client das Paket auch raus schickt, wenn Du denkst? Z.B. mit Wireshark mal mitgesnifft.

    Also select funktioniert. Habe ich ja selber schon verwendet. Kannst mal den entsprechenden Code raustrennen und nur das eine testen.


    Thomas schrieb:

    Wie kann man denn einen Empfänger fragen ob er bereit ist ?
    Wenn der Empfänger Buffer voll ist, das bekommt man mit. Müsste aber auch nachgucken welcher Fehler oder was das wieder war.
  • Thomas schrieb:

    @ OSXDev:

    ...


    So wie es derzeit läuft müsste der Server zwei Antworten auf eine Anfrage senden. Nämlich eine für den Empfang der Anfrage (weil der Client darauf wartet und sonst nicht weitermachen kann) und später eine für das Ergebnis der Anfrage. Wobei die zweite Antwort wiederum vom Client bestätigt werden muss (weil der Server sonst nicht weitermacht). Es macht doch wenig Sinn sowas händisch zu implementieren und wäre wesentlich besser im TCP aufgeoben. Beide Seiten sollen senden wenn sie etwas mitzuteilen haben und empfangen wenn sich dazu bereit sind. Wie kann man denn einen Empfänger fragen ob er bereit ist

    ...


    Besser Du verwendest grundsätzlich die Begriffe Sender und Empfänger. Da Server und Client beide Funktionalitäten in sich vereinen.

    Realisiert wird dies mit listen() und accept(). Beispiele und weitere Erklärungen hierfür findest Du bestimmt in Deinem Buch.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von OSXDev () aus folgendem Grund: Konkretisierung