Socket Thread handling / Reader init

Buckwild

Mitglied
Hallo,

hoffe ich bin hier im richtigen unterforum.

ich habe zur übung ein kleines client-server programm geschrieben mit dem ich eigendlich ganz zufrieden bin.

also es passiert nichts weiter als das der client einen string an den server schickt, dieser verändert wird und an den client zurück geschickt wird.

jetzt hab ich mir zur aufgabe gemacht das ganze mit hilfe von threads zum laufen zu bringen. dazu möchte ich erst die server-verbindung (da diese blockiert) und den server-reader in eigenen threads laufen lassen.

die client seite verläuft ja dann im großen und ganzen analog.

jetzt habe ich das problem das mein reader nicht initialisiert wird und ich eine NullPointerException bekomme. ich kann mir aber nicht erklären warum. vielleicht überseh ich einfach was. daher ist auch noch kein writer implementiert.

hier meine klassen:

GoServer: Stellt die Verbindung her

Java:
package server2;

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

public class GoServer implements Runnable {

	static ServerSocket ss = null;
	static Socket s = null;
	
	private Thread thread;
	
	public GoServer() {	
		thread = new Thread(this, "GoServer");
	}
	
	public void start() {
		thread.start();
	}
	
	public void join() throws InterruptedException {
		thread.join();
	}
	
	public void run() {
		try {
			ss = new ServerSocket(9999);
		} catch (IOException e) {
			e.printStackTrace();
		}
		while(true){	
			try {
				System.out.println("Waitin for client...");
				s = ss.accept();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if(GoServer.s != null){
					try {
						Thread.sleep(500);
						s.close();
						System.out.println("Client disconnected.");
					} catch (IOException e) {
						e.printStackTrace();
					} catch (InterruptedException e){
						e.printStackTrace();
					}
				}
			}				
		}
	}
}

ReadServer: soll den String vom client lesen

Java:
package server2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ReadServer implements Runnable {
	
	static String get;
	private Thread thread;
	
	public ReadServer() {
		thread = new Thread (this, "Reader");
	}
	
	public void start() {
		thread.start();
	}
	
	public void join() throws InterruptedException {
		thread.join();
	}
	
	public void run(){
		try {
			BufferedReader in;
			in = new BufferedReader(new InputStreamReader(GoServer.s.getInputStream()));
			get = in.readLine(); // nicht schön aber läuft

		} catch (IOException e) {
			e.printStackTrace();
		}
		
		System.out.println("From Client: " + get);
		
	}
}

Ich hab versucht den Reader an verschiedenen stellen in dieser klasse zu initialisiern aber es schlägt jedesmal fehl. ich vermute mal das die verbindung noch nicht steht wenn "GoServer.s.getInputStream()" ausgeführt wird. hab das mit diversen sleep()s versucht zu umgehn aba bisher ohne erfolg.


Die main:
Java:
package server2;

public class Control {

	public static void main(String[] args) {

		GoServer go = new GoServer();
		go.start();

		ReadServer read = new ReadServer();
		read.start();

		try {
			go.join();
			read.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

wahrscheinlich liegt irgendein simpler fehler vor den ich mir nicht erklären kann. aber vielleicht könnt ihr mir einen tip geben.
Wäre super.
 
Das hier scheint mir nicht richtig:
Java:
static Socket s = null;
Das führt dazu, dass Du nur ein Socket benutzen kannst. Du bekommst aber bei jeder neuen Verbindung eines Clients mit Deinem ServerSocket ein neues. Dieses kannst Du dann bspw. als Konstruktorparameter an einen jeweils neu zu erstellenden Handler-Thread übergeben. Im Java-Tutorial ist das ganz gut inkl. Beispielcode erläutert (Writing the Server Side of a Socket (The Java™ Tutorials > Custom Networking > All About Sockets))
 
du spielst auf static an richtig?
nun mein server wird sich letztendlich nur mit einem client dauerhaft verbinden. natürlich könnt ich das auch anders deklarieren aber es ist für mich nicht nötig.
 
du spielst auf static an richtig?
nun mein server wird sich letztendlich nur mit einem client dauerhaft verbinden. natürlich könnt ich das auch anders deklarieren aber es ist für mich nicht nötig.
Wen ich den Rest Deines Codes richtig interpretiere, soll doch auch der Client in Threads laufen? Auch, wenn Du von nur einem (physischen) Client mehrere Verbindungen aufmachst, führt das zu unterschiedlichen Sockets. Außerdem, mach es doch einfach von Anfang an richtig. Dann hast du keinen Änderungsaufwand, wenn es doch mal mehr Clients werden sollen.
 
also ich hab mir das tutorial "java chat selbst gemacht" gegeben und hab mein programm nun zum laufen gebracht...

tjo ich versteh zwar warum es läuft aber nicht warum mein geposteter code nicht! funktioniert.

alles was ich geändert hab ist das ich die verbindung (serversocket, socket) in den konstruktor der klasse ReadServer übergebe um mit dieser den stream zu initialisieren. die instanz dieser klasse wird in der run-methode von GoServer erzeugt, wodurch meine main auch etwas schlanker geworden ist.

aber warum funktioniert das nicht wenn ich mit dem aufruf ..GoServer.s.getInputStream()..

das müsste doch auch funktionieren ( was es in meiner vorherigen version des Programms auch getan hat) ist nur eine andere art der übergabe.

irgendwie ist mir mein fehler noch nicht ganz klar. könnte mir das jmd erklären??

achja die sockets sind nicht mehr static... war ein guter tipp nillehammer das spart mir später graue haare
 
wenn man das Programm einfach so startet, dann kommt ReadServer.run() unmittelbar dran (oder wie ist der Plan?)
und will die Socket-Variablen verwenden, die ist aber noch null, falls nicht nanosekunden-genau getimt
und mit freundlicher Unterstützung der Java-Thread-Verwaltung zufällig auch schon eine Client-Verbindung aufgebaut wurde

das ist so offensichtlich, wie kann da eine Frage bestehen?
ws dachtest du würde passieren?

in den seriösen Beispielen wird sicherlich erst nach Aufbau einer Verbindung ein Thread zum Lesen erstellt oder sonstwie auf den erst dann vorhandenen Socket zugegriffen,
auch das ist doch ein sehr einfach zu verfolgender logischer Programmablauf?
 
das es an der nebenläufigkeit und dem zeitpunkt der initialisierung liegt dachte ich mir schon. aber laut dem debugger hat er die verbindung aufgebaut bevor der reader initialisiert wurde. ich hab auch mit sleep() die threads schlafen gelegt bis die verbindung bestanden hat. trotzdem hats nich hingehaun.

daher ja auch meine frage weil ichs nich ganz gerafft hab.
 
was du irgendwo mit Debuggern steuerst und sleeps(), die bisher im Quellcode fehlen,
zumindest der Reader wird ja nicht gestoppt, ist schwer von außen nachzuvollziehen..

ein zusätzlicher Punkt zum bisherigen ist, dass der Client-Socket nach Quellcode relativ bald geschlossen wird,
allerdings sind 500ms schon ein Mindestwert der einen Erfolg denkbar macht und zu spät gibt es glaube ich auch keine NullPointerException,
und außerdem hast du dich ja genau um diese Pausen usw. angeblich gekümmert


wie auch immer, der richtige Ablauf ist klar, die NullPointerException ziemlich deutlich mit falschen Ablauf verbunden,
im Programm wäre richtiger, sicherer Ablauf leicht einzubauen,
was du auf anderen unbekannten Wege erreichst ist nicht wirklich zu kommentieren,
ich habe fertig 😉
 

Zurück
Oben