laladipsipo Geschrieben 4. August 2008 Geschrieben 4. August 2008 Hallo, Ich habe eine socket Schittstelle unter Linux unter Verwendung der normalen POSIX sockets implementiert. Auf der anderen Seite holt ein QT socket Client die Daten ab. Die Daten können mehrere Megabyte betragen und werden unter Verwendung eines TCP/IP sockets versendet. Bei Tests ist aufegefallen, dass der Linux system call "write" nicht korrekt funktioniert, wenn der socket vorher in den "non blocking mode" versetzt wurde. Wird die "write" Funktion mit einem großen Datenbuffer (z.B. 132kByte) im blockierenden Modus aufgerufen, so segmentiert das OS die Daten korrekt und alle Daten werden vom Client empfangen. Da ich aber in meinem Sender nicht warten kann, versetze ich den socket in den "non blocking mode". In diesem Fall werden bei Verwendung des gleichen write Befehls nur etwa 49152 Byte versendet. Danach werden vom Server keine weiteren Daten gesendet. Ich denke, dass es sich bei den ersten 49152 Byte um den ersten Transmit Buffer des TCP/IP Stacks handelt. Mir ist jedoch nicht klar, warum nur der erste Buffer gesendet wird. Das Verhalten ändert sich auch dann nicht, wenn man nach Aufruf des "write" Befehls mehrere Sekunden wartet. Ich hätte erwartet, dass der TCP/IP Stack auch im nicht blockierenden Modus alle Daten versendet, wenn man den socket ansonsten in Ruhe lässt. Immerhin teste ich den socket vor dem nächsten Zugriff mit einem select Statement ab, ob er zum Senden neuer Daten bereit wäre. Ist das ein absichtlich so implementiertes Verhalten oder vielleicht noch ein Bug im TCP/IP Stack? System: openSUSE 10.2, Kernel 2.6.18, gcc 4.1.2 Zitieren
flashpixx Geschrieben 4. August 2008 Geschrieben 4. August 2008 Hallo, wäre es nicht sinnvoller bei den Daten UDP zu verwenden, wenn Dein Sender kontinuierlich Daten liefert? Phil Zitieren
laladipsipo Geschrieben 4. August 2008 Autor Geschrieben 4. August 2008 Das habe ich probiert. Da ich aber keine Performance Unterschiede zwischen UDP und TCP bemerkt habe, habe ich mich für TCP entschieden, eben weil es die Daten für mich segmentiert und ich keinen eigenen Protokolloverhead vorhalten muss, um für eine sichere Datenübertragung zu sorgen Zitieren
flashpixx Geschrieben 4. August 2008 Geschrieben 4. August 2008 Ich bin von Deiner Aussage "Der Sender kann nicht warten" ausgegangen, denn für mich hört sich das nach einem Streaming an. Bei so etwas würde ich definitiv UDP einsetzen. Ich gehe davon aus, dass Deine Vermutung mit einem Bug falsch ist, denn es wäre sicherlich längst bekannt. Bitte wirklich einmal diesen Paragraphen lesen: Wie man Fragen richtig stellt: eine Anleitung wie man Fragen erfolgreich in Usenet, Mailing Listen und Webforen stellt. Ich würde eher darauf tippen, dass Dein Konzept nicht gut genug ausgearbeitet ist, denn im Grunde steht in Deinem Post "geht nicht" und das ist nicht aussagekräftig. Überdenke Dein Konzept oder poste dieses mit allen relevanten Details, die notwendig sind, um Deine Problemstellung nachvollziehen zu können Phil Zitieren
laladipsipo Geschrieben 4. August 2008 Autor Geschrieben 4. August 2008 (bearbeitet) Hallo, Tut mir leid, wenn ich dich verärgert habe. Ich denke aber, dass meine Problembeschreibung ausreichend ist. Ich habe auch Tests mit UDP gemacht. Allerdings ist es für die Übertragung entscheidend, dass die Daten komplett und in der richtigen Reihenfolge übertragen werden. Diese Arbeit möchte ich mir vom TCP Protokoll abnehmen lassen. Bei UDP hätte ich das oben genannte Problem ja gar nicht, da ich selbst meine Daten segmentieren muss. Das ist mir klar. Als Resultat müsste ich dann aber einen komplizierten Protokolloverhead implementieren, der mir die sichere Datenübertragung garantiert. Das eigentliche Problem ist, dass ich mit dem gleichen "write" System call im blockierendem und nicht blockierendem Modus unterschiedliches Verhalten habe: Fall 1: (socket im blocking mode) -write wird aufgerufen -system call blockiert, bis alle Daten übertragen wurden. -dabei werden mehere Transmits mit der maximalen Transmitbuffergröße von 49152 (auf meinem System) Byte gemacht. -return value ist Anzahl der zu sendenden Bytes. errno ist 0 Fall 2: (socket im non blocking mode) -write wird aufgerufen -system call blockiert nicht. Die aufrufende Funktion pausiert aber nach dem write Kommando für 30 Selunden (also genug zeit, die Daten zu senden) -dabei werden einmalig 49152 Byte gesendet, egal wie lange ich vor dem nächsten Aufruf warte -return value ist jetzt nur 49152. errno ist aber trotzdem 0 Ich hoffe, dass macht es klarer. Mein Problem ist, dass die Aufrufende Funtkion im Thread kontext läuft und das Gesamtprogramm nicht warten kann, bis alle Daten gesendet sind. Ich hätte erwartet, dass dieses vom Network Subsystem automatisch geleistet wird. Vielleicht liege ich da ja auch falsch. Ich habe oben in keinem fall geschrieben "geht nicht", sondern wollte viel mehr wissen, ob meine Erwartung falsch ist. Dann kann ich dass Problem umgehen, in dem ich einen zweiten Thread aufsetze, der den socket im blockierenden Modus betreibt. Bevor ich diesen Aufwand treibe, möchte ich aber sicher sein, dass die erste Variante nicht funktioniert. Bearbeitet 4. August 2008 von laladipsipo Zitieren
laladipsipo Geschrieben 4. August 2008 Autor Geschrieben 4. August 2008 Naja, scheint sich geklärt zu haben: If the O_NONBLOCK flag is set using fcntl() (defined in <sys/fcntl.h> and explained in fcntl(2) and fcntl(5)), POSIX-style nonblocking I/O is enabled. In this case, the send() request completes in one of three ways: If there is enough space available in the system to buffer all of the data, send() completes successfully, having written out all of the data, and returns the number of bytes written.If there is not enough space in the buffer to write out the entire request, send() completes successfully, having written as much data as possible, and returns the number of bytes it was able to write.If there is no space in the system to buffer any of the data, send() completes, having written no data, and returns -1, with errno set to[EAGAIN]. Quelle: HP Developers pages. Die Beschreibung gilt dort zwar nicht direkt für Linux, aber Posix ist ja ein übergreifender Standard. Zitieren
flashpixx Geschrieben 4. August 2008 Geschrieben 4. August 2008 Tut mir leid, wenn ich dich verärgert habe. Ich denke aber, dass meine Problembeschreibung ausreichend ist. Das nicht, nur dass Du mit der Aussage "ich hab nen Bug gefunden" sehr vorsichtig sein solltest. Mein Problem ist, dass die Aufrufende Funtkion im Thread kontext läuft und das Gesamtprogramm nicht warten kann, bis alle Daten gesendet sind. Ich hätte erwartet, dass dieses vom Network Subsystem automatisch geleistet wird. Vielleicht liege ich da ja auch falsch. Ich habe oben in keinem fall geschrieben "geht nicht", sondern wollte viel mehr wissen, ob meine Erwartung falsch ist. Dann kann ich dass Problem umgehen, in dem ich einen zweiten Thread aufsetze, der den socket im blockierenden Modus betreibt. Bevor ich diesen Aufwand treibe, möchte ich aber sicher sein, dass die erste Variante nicht funktioniert. Also ich denke dass eben das Konzept falsch ist und es nicht an der Codierung hakt. Wenn Du Transportsicherheit brauchst, dann nimm TCP, wenn Du Streaming brauchst UDP. Im Moment versuchst Du meiner Ansicht nach UDP mit TCP zu mixen, nämlich die Fähigkeit von Streamining aus UDP mit der Transportsicherheit von TCP. Ich denke Du musst an die Problemstellung ran und da Du auf TCP setzen willst, musst Du Deine Struktur, die Dir die Daten passend zum Versand vorbereitet ändern, so dass sie mit TCP arbeitet. Ich denke es ist weder eine Sache oder gar ein Fehler des Socket oder Deiner eigentlichen Übertragungsroutinen, sondern eben viel mehr der gewaltsame Versuch Fehler in der Vorverarbeitung durch das Protokoll / Schnittstelle zu beheben. Wenn Du aus mehreren Threads über das Netzwerk Daten sendest, warum synchronisierst Du sie nicht, sammelst dann die sychronisierten Daten und bereitest sie passend für den Versand auf und schickst sie dann rüber Phil Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.