Socket Daten empfangen funktioniert nicht richtig - wo liegt der Fehler?

Status
Nicht offen für weitere Antworten.

Björn.J

Mitglied
Hallo zusammen,

ich lerne zur Zeit mit Hilfe von Head First Java, wie ich Netzwerkprogrammierung angehe. Ich habe auch ein kleines Projekt zum Lernen im Auge (eine Art Terminal), aber schon bei den Grundlagen komme ich nicht weiter. Ich habe wirklich schon einige Tutorials durchgearbeitet, aber geholfen hat mir das nicht.

Die Ausgangssituation ist die, dass ich ein Socket zu einem Server öffne. Ich erstelle dann zwei Threads und gebe diesen das Socket an. Der eine Thread soll in einer Endlosschleife einfach - sobald er etwas empfängt - diesen Text auf System.out ausgeben. Der andere Thread wartet 1 Sekunde und sendet einen Befehl an den Server, worauf dieser eigentlich reagieren müsste... und hier liegt das Problem.

Der EmpfängerThread erhält die Begrüßung vom Server und gibt diese aus. Dann sendet der zweite Thread einen Befehl an den Server, aber der EmpfängerThread gibt einfach nichts mehr aus. Die Daten werden auch korrekt gesendet, das habe ich mit Hilfe eines lokalen Mini-Servers getestet.

Die zwei Runnables sehen so aus:
Java:
package core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ReceiveDataRunnable implements Runnable {
	
	private Socket s;
	private InputStream in;

	public void run() {
		BufferedReader d = new BufferedReader(new InputStreamReader(in));
		
		 try {
	         while (true) {            
               System.out.println("Received: " + d.readLine());
	         }
	      } catch (Exception e) {}
	}

public void setSocket(Socket s) throws IOException {
		this.s = s;
		this.in = s.getInputStream();
	}

}

Java:
package core;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

public class SendDataRunnable implements Runnable {
	
	private Socket s;
	private PrintWriter writer;

	public void run() {
			try {
				Thread.sleep(1000);
				System.out.println("Sent: \"help\"");
				writer.write("help");
				writer.flush();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	}

	public void setSocket(Socket s) throws IOException {
		this.s = s;
		writer = new PrintWriter(s.getOutputStream());
	}

}

und das Hauptprogramm sieht so aus
Java:
package core;

import java.net.Socket;

public class TestSpace {
	public static void main(String[] args) {
		new TestSpace().go();
	}

	private void go() {
		
		try {
			Socket s = new Socket("news.usenetserver.com", 119);
			
			SendDataRunnable sdr = new SendDataRunnable();
			sdr.setSocket(s);
			
			ReceiveDataRunnable rdr = new ReceiveDataRunnable();
			rdr.setSocket(s);
			
			Thread sd = new Thread(rdr);
			Thread sc = new Thread(sdr);
		
			sd.start();
			sc.start();
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}		
}

Der Output auf der Konsole sieht so aus:

Received: 200 news.usenetserver.com Welcome! (fe04.ams2)
Sent: "help"

Und dann hörts auf. Wenn ich mich allerdings mit telnet mit dem selben Server verbinde und "help" eingebe, erhalte ich einige Zeilen Text. Das möchte ich durch das Programm auch erreichen.

Wenn jemand einen Hinweis hat, wo das Problem liegt, wäre ich sehr dankbar. Ich habe mitlerweile etliche Stunden damit verbracht, aber bin mittlerweile absolut ratlos...

Viele Grüße,
Björn
 
Zuletzt bearbeitet:
Auf Empfängerseite machst du ein "readLine()". Auf Senderseite sendest du aber keien Zeilenumbruch nach dem "help". Sende mal "help\n" oder "help\r\n" ...

- Alex
 
Hallo tuxedo,

mit "help\r\n" klappt es nun! Wahnsinn, ich habe 15 Stunden den Fehler gesucht und jetzt lag es an einem popeligen "\r". Mit "\n" hatte ich nämlich auch schon probiert.

Vielen Dank!!

Björn
 
Der Zeilenumbruch ist "plattformspezifisch".
Schau mal die Java System Properties durch. Da findest du den für deine Plattform üblichen Zeilenumbruch.

- Alex
 
Hallo Alex,

ich habe mir meine System-Properties mal ausgeben lassen und mein Line-Separator ist 0x0A = \n. (Weil Linux)
Der Server, auf den ich die Anfrage starte scheint aber demnach auf Windows zu laufen. Das erklärt jetzt auch, warum mein Testserver mir den richtigen Eingang von einzelnen Lines angegeben hat, es aber auf dem richtigen Server nicht funktioniert hat.

Gibt es auch eine Möglichkeit, abzufragen was der standartmäßige Line-Separator auf Serverseite ist? Oder kann/sollte ich mit "\r\n" immer auf Nummer sicher gehen?

Grüße,
Björn
 
Also wenn ich mich richtig an die ApiDoc erinnere dann funktioniert das Java-ReadLine() sowohl mit
Code:
\n
als auch mit
Code:
\r\n
. Sollte also keinen Unterschied machen.

Wenn ich deine Zeilen richtig interpretiere dann programmierst du gegen einen eigenen Testserver, willst die Anwendung aber später gegen einen nicht von dir stammenden Server laufen lassen?
Wenn ja: Da musst du die Doku des Servers konsultieren und schauen was der für ein Zeilenumbruch verlangt. Kann sein dass \r\n hardcodiert ist.

Was ist das denn für ein Server?

- Alex
 
Mein Programm soll ein einfacher Usenet-Client werden, also Nachrichten über das NNTP-Protokoll (Network News Transfer Protocol ? Wikipedia) empfangen und versenden können. Das ist einfach ein Projekt für mich zum Lernen.

Mein Testserver (der einfach auf einem Socket horcht und diese Strings ausgibt) funktionierte mit \n als Line-Separator, weil er ja bei mir auf meiner Linuxmaschine läuft.

Der Server, mit dem ich die Probleme hatte (news.usenetserver.com) war schon der Server, mit dem das Programm später mal laufen soll. Hier brauchte ich das "\r\n".

Jetzt muss ich mich mal erkundigen, ob das "\r\n" so in der NNTP-Dokumentation evtl. als Standard festgelegt ist.

Danke nochmal, jetzt kann ich endlich weitermachen. 🙂

Björn

PS: Aha! "A CRLF pair MUST terminate all commands." (Aus der RFC 3977 zu NNTP) ;-)
 
Zuletzt bearbeitet:
PS: Aha! "A CRLF pair MUST terminate all commands." (Aus der RFC 3977 zu NNTP) ;-)

Na das erklärt das ganze dann ja 🙂 Dein Java-Testserver müsste ja übrigens auch mit dem
Code:
\r\n
zurecht kommen so dass du getrost weitertesten kannst.

Kleine Anregung noch:

Mach die Kommunikation mit dem NNTP doch gleich zur schicken API unter GPL/LGPL/ ... Dann haben alle was davon ;-)

- Alex
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben