Doppelter Sockethandle unter Linux ?



  • Ich habe ein Programm geschrieben, das mehrere TCP-Clientverbindungen simultan bedient. Es werden nur die Standardfunktionen connect(),read(),write(),poll(),shutdown(),close() verwendet. Da es sich um ein Kommunikationsmodul für ein Programm handelt, das den verbindungsauf- und abbau steuert, werden alle Verbindungen über einen einzigen Thread bedient (kein fork()).

    Dabei habe ich beobachtet, das gelegentlich Handles von der Socket doppelt vergeben werden 😡 und dadurch Verbindungen vertauscht werden können.

    Das habe ich unter Kernel 2.4 und Kernel 2.6 beobachtet.

    Hat jemand schon mal eine ähnliche Erfahrung gemacht ? Oder kennt gar jemand die Ursache ?



  • Das halte ich für unmöglich, dass der Kernel eine Socketnummer vergibt die vorher nicht mit close geschlossen wurde. Das wäre glaube ich schon aufgefallen 😉

    Wie belegst Du das?



  • Ich habe alle Socketoperationen (read,write,close,shutdown,connect) mitgelogt, auch die RC's dazu, es ist kein Fehler aufgetreten. Trotzdem bekomme ich (zwar sehr selten, aber es sollte nicht passieren) beim erzeugen des Socket mit der Funktion socket einen bereits existierenden Handle zurück (Habe da eine Prüfroutine eingebaut, die das überwacht). Nach dem Close werden die handles, solange sie nicht benutzt werden, nach dem Close auf 0xFFFF gesetzt.

    Ich gebe dir recht, das darf nicht passieren, aber laut meine logs passiert es.



  • imos schrieb:

    Nach dem Close werden die handles, solange sie nicht benutzt werden, nach dem Close auf 0xFFFF gesetzt.

    Was heisst solange sie nicht benutzt werden? Nach einem close darf der Kernel Dir diese Nummer wieder übergeben, da interessiert es ihn nicht ob Du sie noch benutzt 😉



  • Hi,

    Ich schreibe ein ähnliches Programm (TCP-Server). Vielleicht kannst du mir zeigen, wie ich mit Threads arbeiten kann.
    Im Moment versuche ich mich am fork()en. Meine Idee war es, dass sich die neuen Clients am Parent verbinden. Der Parent-Prozess sucht sich dann den Kind-Prozess (von mehreren) heraus, der im Moment die wenigsten Clients hat. Dann sendet der Parent-Prozess diesem Kind über eine Pipe den Wert des Sockets. Der Kind-Prozess speichert die ID dann in eine Variable (Array) und wartet dann auf eingehende Befehle des Clients. Hier kommt mein Problem:
    Die Socket-ID (integer-Wert) wird zwar erfolgreich zum Kind-Prozess übertragen, doch gibt es beim read() des Sockets einen Fehler: EBADF = Bad File Descriptor. Anscheinend ist die SocketID nicht mehr gültig. Wie kann das sein? Ich habe den Socket natürlich davor nicht geschlossen.



  • Das funktioniert so nicht. fork() startet einen neuen Prozess, keinen Thread. Ein Prozess hat eigene Filedescriptoren und eigenen Speicher, einzig nach fork() zeigen alle Filedescriptoren beider Prozesse auf dieselben Objekte. Ein gängiger Weg für Worker-Prozesse ist hier also, den Socket im Parent zu öffnen, dann zu fork()en und den Socket dann im Child zu verwenden (und im Parent zu schliessen).

    Andererseits wäre es auch ziemlich blöd, wenn ich beim Beschreiben des Filedescriptors "1" plötzlich auf der Konsole meines Administrators landen würde, oder? 😉



  • Das ist natürlich korrekt, also gilt ein FileHandle quasi nur für einen Prozess. Vielen Dank.
    Wie machen es dann große Programme wie z.B. Apache? Dort existieren beispielsweise auch nur 5-10 Kind-Prozesse. Trotzdem können sich "unbegrenzt" viele Clients verbinden. Wie geht das? Durch Threads? Und wenn ja, wie? 🙂 😕



  • OK folgendes Problem:

    Ich möchte jedem neuen Client einen eigenen Thread zuweisen.

    pthread_t threads[10];
    

    Nun möchte ich, dass wenn ein Client die Verbindung trennt, der Thread, der den Client "bearbeitet" hat, sich selbst aus dem Speicher entfernt und meinem Hauptprogramm "sagt", dass dieser Thread wieder frei ist. Mit pthread_join(...) wartet, soweit ich das richtig verstanden habe, das Hauptprogramm darauf, dass der Thread beendet wird. Das ist ja bei Client-Server-Anwendungen quatsch. Das hieße ja, dass sich das Programm so lange aufhängt, bis der Client die Verbindung trennt.

    Hat jemand eine Idee?



  • Schau mal nach pthread_detach, das macht ziemlich genau was Du möchtest 😉

    BTW:
    In Apache2 gibt es mehrere Modelle wie die Arbeit verteilt wird, u.a. auch Threads, aber auch Prozesse. Bei zweiterem werden dann eben keine Socketnummern übergeben. Wie das allerdings im Apache Worker-Modell gelöst ist weiss ich nicht 😉


Log in to reply