Zum Inhalt springen

Unvollständige TCP-Nachrichten (max. 4380 Byte)


Metaner

Empfohlene Beiträge

Hallo,

hierbei handelt es sich um eine Fortsetzung meines Postings Unvollständige Socket-Nachrichten (max. 4379 Byte) aus dem Java-Forum. Da das Problem nun doch nicht gelöst werden konnte und ich davon ausgehe, dass es kein Software/Java Problem ist, suche ich hier bei Euch Netzwerk-Experten nach Rat.

Problembeschreibung: Wir haben eine in SmallTalk geschriebene Anwendung die auf Port 8081 einen TCP/IP Listener erzeugt und auf eingehende Verbindungen wartet. Eine in Java geschrieben Programmerweiterung soll sich nun mit diesem TCP/IP Listener verbinden, einen Request senden (reine XML-Daten / ohne HTTP-Header o. ä.) und den Response entgegennehmen.

Im Rahmen eines Integrationstestes haben wir nun festgestellt das auf einigen Rechnern der Response (Antwort von SmallTalk an Java) exakt nach 4380 Byte abgeschnitten wird. Wir haben mit 6 Rechnern getestet wobei auf 3 Rechnern dieser Fehler (reproduzierbar) auftritt. Das merkwürdige ist, dass auch auf diesen 3 Rechnern es ab und zu dazu kommt, dass auch Nachrichten über 4380 Byte erfolgreich ankommen. Die Erfolgsquote schwankt zwischen den Rechnern aber erheblich (von ca. 5% -20% erfolgreiche Meldungen > 4380 Byte).

Was noch verwirrender ist, ist die Tatsache, dass wir 2 Rechner mit identischer Hard- und Software getestet haben. Auf einem Rechner funktioniert die Kommunikation problemlos wobei der andere Rechner das Problem mit den unvollständigen Nachrichten hat. :eek: Achja, dass die Nachrichten unvollständig ankommen, betrifft auch wirklich nur die Rückmeldung von SmallTalk an Java. Schickt der Java-Client einen Request mit einer Länge über 4380 Byte kommt dieser immer vollständig an. Nur die Rückmeldungen sind von diesem Problem betroffen.

Alle Rechner befinden sich im gleichen Netz (wobei das beim Test mit dem Loopback nicht entscheiden dürfte ... aber trotzdem der Hinweis). Außerdem haben wir keine Gemeinsamkeiten unter den 3 fehlerhaften Rechnern entdecken können (sowohl AMD als auch Intel, unterschiedliche Chipsätze etc.). Wir haben auch schon einen der Rechner, auf dem das Problem reproduziert werden kann, neu aufgesetzt. Doch auch das brachte keine Besserung. Alle Rechner laufen mit Windows XP (SP2).

Was wir jetzt festgestellt haben ist, dass das Problem nur dann auftritt, wenn beide Anwendungen auf dem selben Rechner laufen und über die Loopback-Adresse kommunizieren (z. B. 127.0.0.1:8081 ). Nur dann tritt das Problem auf den 3 Rechnern reproduzierbar auf. Wir haben auch schon die IP-Adresse 127.0.0.1 durch die IP-Adresse der Netzwerkkarte 10.xxx.xx.xxx ersetzt. Doch auch das brachte keine Besserung.

Werden allerdings SmallTalk-Anwendung und Java-Anwendung auf unterschiedliche Rechner gelegt z. B. SmallTalk startet TCP/IP-Listener auf der lokalen IP mit Port 8081 und der Java-Client wird von einem anderen Rechner im Netz gestartet und mit dem Listener verbunden, funktioniert die Kommunikation problemlos.D er Fehler tritt dann garnicht mehr auf. Wir haben auch schon TCP/IP Listener und Java-Client jeweils auf einen der 3 betroffenen Rechnern in diesen Test eingebunden. Der Fehler tritt dann ebenfalls nicht mehr auf.

Das Fazit bis dahin: Der Fehler tritt nur bei Verwendung der Loopback-Adresse auf wenn Server-Socket und Client-Socket auf dem gleichen System ausgeführt werden. Der Fehler tritt auch nur mit Nachrichten auf, die von SmallTalk an Java gesendet werden. Der Fehler tritt aber auch dann nicht in 100% der Fällen auf!

Weil wir uns das Problem nicht erklären können, haben wir dann Unterstützung aus unserer IT-Abteilung zugezogen. Mit unserer Analyse und den bisher durchgeführten Tests wurde dann eine Protokollierung des Netzwerkverkehrs durchgeführt (Software: Wireshark). Das Problem ist nur, dass sich die Kommunikation auf dem Loopback unter Windows nicht protokollieren läßt (haben auch schon einen Loopback-Adapter als Netzwerk-Device installiert). Wir haben dann als Gegenprobe (dass die Protokollierung grundsätzlich funktioniert) die Protokollierung der Nachrichten durchgeführt, wenn Client-Socket und Server-Socket auf getrennten System ausgeführt werden. Das klappte auch super. Dabei habe ich gesehen, dass die Gesamtnachricht in Paket mit je 1460 Byte aufgeteilt wird. Merkwürdig ist nun, dass die max. Länge der empfangenen Nachricht auf dem Problemrechnern genau 3 dieser Paketgrößen entspricht (3 x 1460 => 4380)? Steckt da ein System hinter? :confused:

In den letzten Tagen haben wir nun vergeblich versucht, die Kommunikation auf dem MS-Loopback protokolliert zu bekommen. Haben u. a. auch TCP-Monitor von Apache verwendet und diesen als "Software-Bridge" zwischen Client und Server-Socket eingebunden. Doch TCP-Monitor protokolliert nur HTTP Nachrichten. Da wir keinen HTTP Header in der Kommunikation verwenden, klappte auch dieser Versuch nicht.

Daher meine Frage/mein Hilferuf an Euch Experten: Kennt jemand dieses Problem bzw. hat damit einmal zu tun gehabt? Vielleicht kennt jemand von Euch eine Lösung, wie man den Loopback unter Windows XP protokollieren kann. Dass der Loopback unter Linux ohne Probleme "gesnifft" werden kann, wurde mir schon von unseren Admins gesagt. Nur leider sind der SmallTalk-Server als auch "Java-Client" nicht lauffähig unter Linux.

Zumindest danke ich Euch schon einmal für das Lesen dieser Problembeschreibung.

Gruß Jan

Link zu diesem Kommentar
Auf anderen Seiten teilen

Im Rahmen eines Integrationstestes haben wir nun festgestellt das auf einigen Rechnern der Response (Antwort von SmallTalk an Java) exakt nach 4380 Byte abgeschnitten wird.
Woraus schließt du das?

Die Tatsache, dass du von "TCP-Nachrichten" und "Socket-Nachrichten" sprichst, lässt mich vermuten, dass du erwartest, dass das, was du auf der einen Seite auf einmal reinsteckst, auch auf den anderen Seite auf einmal rauskommt. Das ist nicht der Fall. Auf Socket-Ebene gibt es keine "Nachrichten", nur einen Strom von Bytes. Es kann durchaus sein, dass du die Daten, die du mit einem einzigen send-Aufruf abgeschickt hast, mit mehreren recv-Aufrufen einsammeln musst.

Ob das passiert, hängt auch vom Timingverhalten der Programme ab. Das könnte auf das beobachtete Verhalten passen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Richtig! Auf der einen Seite wird (aus Sicht des Softwareentwicklers) ein SocketWrite-Stream mit Bytes gefüttert und anschließend (wenn die Nachricht komplett "befüllt" wurde) von SmallTalk abgeschickt. Dabei bediene ich mich eine TCP/IP Erweiterung in unserer Entwicklungsumgebung (Object Studio der Firma Cincom) die lt. Manual direkt auf die TCP/IP-API aufsetzt.

In Java wird, nachdem der Request abgeschickt wurde, auf die Rückmeldung "gewartet". Wird mit der Rückmeldung begonnen, wird der erzeugte InputStream solange Byte-weise ausgelesen, bis kein Zeichen mehr ankommt. Zum Test hatte ich einmal in dieser Schleife eine Systemprotokollierung eingebaut. Die hat mir gezeigt, dass nur 4380 Bytes gelesen wurden.

Das auf dem Transportweg die Nachricht in mehrere Paket aufgeteilt wird/werden muss ist mir klar. Aber das übernimmt für mich doch die Hardware bzw. eine andere (OSI-)-Schicht. Oder etwa nicht?

Zum besseren Verständnis poste ich einmal die Java-Methode, die den Request startet und den Response entgegen nimmt. Vielleicht habe ich ja doch eine fehlerhafte Implementierung?


	public MethodResponse execute(MethodRequest methodRequest) throws Exception {

		MethodResponse methodResponse = new MethodResponse(methodRequest);

		Socket socket = this.getSocket();


		try {


			ByteArrayOutputStream outputStream = Adapter.encode(methodRequest);

			socket.connect(this.getSocketAddress());

			OutputStream out = socket.getOutputStream();

			out.write(outputStream.toByteArray());

			InputStream in = socket.getInputStream();

		        in.read();


		        ByteArrayOutputStream aDecStream = new ByteArrayOutputStream();

		        while (in.available() > 0) {

		        	aDecStream.write(in.read());

		        }

		        Object result = ((MethodResponse)Adapter.decode(aDecStream)).getMethodResult();	       

		        methodResponse.setMethodResult(result);

		        if(result instanceof SmalltalkException){

		        	throw ((SmalltalkException)result);

	       		}

		} finally {

			if(socket != null)

				socket.close();

		}


		return methodResponse;

	}

Danke und Gruß

Jan

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das auf dem Transportweg die Nachricht in mehrere Paket aufgeteilt wird/werden muss ist mir klar. Aber das übernimmt für mich doch die Hardware bzw. eine andere (OSI-)-Schicht. Oder etwa nicht?
Doch, das mach TCP für dich, aber du scheinst zudem noch zu erwarten, dass das auf der Empfängerseite dann auch genau so wieder zusammengesetzt wird.

Das passiert aber nicht. Du liest mit einem recv-Aufruf (oder read oder wie auch immer) genau so viel aus dem Socket aus, wie eben gerade da ist. Es gibt keine "Nachrichten", nur Bytes. Wenn du ein nachrichtenbasiertes Protokoll über Sockets laufen lassen willst, musst du es schon selbst implementieren.

Zum besseren Verständnis poste ich einmal die Java-Methode, die den Request startet und den Response entgegen nimmt. Vielleicht habe ich ja doch eine fehlerhafte Implementierung?
Ich kenne diese API nicht, aber die Tatsache, dass da nirgends eine Längenprüfung zu sehen ist, bestärkt mich in meiner Vermutung.

Du bist selbst dafür verantwortlich, dass du eine vollständige "Nachricht" einliest. Es reicht nicht, dass du in.available() prüfst, weil das vermutlich zwischenzeitlich auch mal 0 liefern kann, wenn die Gegenstelle mit dem Senden nicht nachkommt (zum Beispiel eben genau dann, wenn Sender und Empfänger auf demselben Rechner laufen, und der Prozessor gerade den Empfänger bearbeitet).

Wenn der Empfänger nicht weiß, aus wievielen Bytes eine Nachricht besteht, musst du diese Information mitschicken, z.B. indem du der Nachricht die Länge voranstellst.

P.S.:

Kann es sein, dass du durch das erste read (außerhalb der Schleife) das erste Byte der Antwort wegwirfst?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Doch, das mach TCP für dich, aber du scheinst zudem noch zu erwarten, dass das auf der Empfängerseite dann auch genau so wieder zusammengesetzt wird.

Ja, dass hatte ich eigentlich erwartet. :beagolisc

Du bist selbst dafür verantwortlich, dass du eine vollständige "Nachricht" einliest. Es reicht nicht, dass du in.available() prüfst, weil das vermutlich zwischenzeitlich auch mal 0 liefern kann, wenn die Gegenstelle mit dem Senden nicht nachkommt (zum Beispiel eben genau dann, wenn Sender und Empfänger auf demselben Rechner laufen, und der Prozessor gerade den Empfänger bearbeitet).

Klingt plausibel. Würde tatsächlich erklären, warum es manchmal klappt aber meistens nicht. Soetwas in diese Richtung hatte ich schon vermutet (Timing) aber eher im Hinblick auf die Threads, die die Verarbeitung in SmallTalk und Java übernehmen.

Wenn der Empfänger nicht weiß, aus wievielen Bytes eine Nachricht besteht, musst du diese Information mitschicken, z.B. indem du der Nachricht die Länge voranstellst.

Dann werde ich mal versuchen, die Kommunikation um eine Längenprüfung zu erweitern. Bin mal gespannt, ob das zum Erfolg führt. :beagolisc

Kann es sein, dass du durch das erste read (außerhalb der Schleife) das erste Byte der Antwort wegwirfst?

::floet: Ähm, ja ... kann nicht nur. Ist sogar der Fall. Ich hatte das garnicht mehr auf dem Bildschirm. Als ich damals die SmallTalk-Erweiterung vorgenommen hatte, habe ich mich schon gewundert, warum in Java immer das erste Zeichen der XML-Nachricht "verschluckt" wurde. Weil SmallTalk zu diesem Zeitpunkt eh schon andere merkwürdige Sachen machte, hatte ich das als weitere Eigenheit von SmallTalk hingenommen und seither schicke ich jeder XML-Nachricht ein vorangestelltes (Char(32) -> Leerzeichen) mit. :upps

Zu meiner Rechtfertigung (warum ich das so gemacht hatte) war, dass ich bei der Programmierung in Java festgestellt hatte, dass beim ersten Aufruf von #read die Verarbeitung in Java an der Stelle angehalten wurde. Das fand ich ganz toll, da ich so sicherstellen kann, dass Java solange wartet, bis SmallTalk die Verarbeitung des Requests abgeschlossen hat und mit dem Senden der Antwort beginnt.

Erst einmal vielen Dank für Deine Unterstützung. Ich werde nun meine Sourcen überarbeiten und prüfen, ob dass den Fehler behebt. Sobald ich neue Erkenntnisses habe werde ich die hier posten. Ich melde mich in jedem Fall noch einmal.

Danke und Gruß

Jan

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

Merkwürdig ist nun, dass die max. Länge der empfangenen Nachricht auf dem Problemrechnern genau 3 dieser Paketgrößen entspricht (3 x 1460 => 4380)? Steckt da ein System hinter? :confused:

Das System heisst IPv4 over Ethernet.

Ethernet hat eine Framegrösse von 1518 wovon 18 Byte für Ethernet-Header & Co. wegfallen. Bleiben noch 1500 Byte. IPv4 belegt davon 40 Byte für seinen Overhead. Das heisst dein Data-Frame in IPv4 over Ethernet ist 1460 gross.

D.h. deine Small-Talk Anwendung packt alle Daten in 3 IP-Packete bevor es intern anfängt die nächsten 4380 Bytes zu befüllen.

Da es zu Problemen kommt selbst bei Verwendung der Loopback Adressen, kann mein ein Netzwerk-Problem ausschliessen. Der Fehler steckt in deiner Java-Anwendung oder ist ein Problem dem von dir verwendeten TCP/IP Socket. Ein "klassisches" Netzwerkproblem kann man ausschliessen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

:valen @ Klotzkopp : 1.000 Dank für Deinen Hinweis mit dem Timing und der daraus abgeleiteten Ursache für mein Problem. Das war der goldene Hinweis um das Problem zu lösen. Ich habe nun das Nachrichtenformat so geändert, dass jetzt (wie Du auch schon empfohlen hattest) die Nachrichtenlänge mitgegeben wird. Der Empfänger puzzelt nun die Nachricht wieder solange zusammen, bis das erwartete Ende erreicht ist. Die Kommunikation zwischen SmallTalk und Java funktioniert nun auch auf den "Problem"-Rechnern zu 100%.

Habe dabei auch gleich das mit dem überlesenen 1. Byte korrigiert. Damit wäre auch dieses Mysterium geklärt. :upps

@ardcore

Danke auch Dir für die Aufklärung in Bezug auf die Data-Frames. Das habe sogar ich verstanden. :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

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.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...