# Client + Server ObjectStream



## BigFish (26. Mai 2011)

Hallo Ihr,

ich habe gerade ein Programm geschrieben, indem es um Server-Client-Kommunikation geht.
Es soll möglich sein über einen Objekt-Stream Objekte von Server nach Client und umgekehrt zu verschicken.
Dazu habe ich mich der Thread-Programmierung bedient.
In der Main Methode erzeuge ich zwei (natürlich threadsichere) Queues, die an einen Thread weitergegeben werden. In diesem wird einmal der ServerListener  (ClientListener auf der anderen Seite) und ServerSender (ClientSender) erzeugt, an die auch wieder die Queues weitergegeben werden.
Senden soll dann einfach so funktionieren, dass ein Objekt der Klasse Message (meine Klasse) in eine Queue gesteckt wird, aus der aus dem richtigen Thread eingelesen und über den ObjectStream geschickt wird. 
Und ja das geht irgendwie nicht.

Also habe ich erstmal geguckt, ob die Threads überhaupt erzeugt werden.
Dafür habe ich einfach jeweils in den Listenern, als auch in den Sendern eine Ausgabe mit "Hallo ich bin der ServerListener (usw.)" gemacht. Nichts davon wird mir ausgegeben.
Und jetzt kommt das richtig merkwürdige: wenn ich das Serverprogramm auf einem richtigen Server per Terminal aufrufe, kann ich sogar Verbindung dazu aufbauen. Und das obwohl die Threads nicht funktionieren ?!
Hier mal beispielhaft der Code des Servers. Der des Clients ist analog:


```
class Spielserver {

	

	public static void main(String[] args) throws Exception {
		
		Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
		Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();

		Thread t = new Thread(new Server(6001, sendq, listenq));
		t.start();
		
		Message msg = new Message("Huhu");
		sendq.add(msg);


		
		System.out.println("laeuft");
		 
		
	}

}
```


```
public class Server implements Runnable{
	
private int port;
public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();


	public Server(int port, Queue<Message> sendq, Queue<Message> listenq){
		this.port=port;
		this.sendq = sendq;
		this.listenq = listenq;
		
	}
	
	public void run(){
		verbinde();
	}
	
	public void verbinde(){
        ServerSocket server = null;
        try {
            server = new ServerSocket(port); 
        } catch (IOException ioe) {
            System.err.println("Der Port " + port + " kann nicht benutzt werden!");
            System.exit(1);
        }
        
        Socket client = null;
        while(true) {
            try {
                client = server.accept();
            } catch (IOException ioe) {
                System.err.println("Accept failed.");
                System.err.println(ioe);
                System.exit(1);
            }
            
            try{
            // Starte einen neuen Thread auf dem dem Klienten zugehoert wird
            	
            	System.out.println("Threads werden erzeugt: Serverebene");
            Thread listener = new Thread(new ClientListener(client, listenq));
            listener.start();
            
            Thread sender = new Thread(new ClientSender(client, sendq));
            sender.start();
            } catch(IOException ioe) {
            	System.out.println("Fehler bei Thread-Erstellung");
            	System.exit(1);
            }
        }
    }
	
}
```


```
class ClientListener implements Runnable { //DER HOERT DEM KLIENTEN ZU!
    
    private ObjectInputStream in = null;
    private Object msg=null;
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();
    
  public ClientListener(Socket client, Queue<Message> listenq) throws IOException {
      
          in = new ObjectInputStream(client.getInputStream()); //Hiermit wird empfangen
  		  this.listenq = listenq;
  		  }
  
    

    public void run() {
    
    	try {
        	System.out.println("Ich bin der ClientListener!");
        	
     
            while (true) {
                try{
                msg = in.readObject();
                if(msg instanceof Message) { 
                	Message Nachricht = new Message(msg); 
                	listenq.add(Nachricht); 
                }
                else System.out.println("Keine gueltige Message");
                } catch(ClassNotFoundException cnfe) {}
               
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }

}
```


```
public class ClientSender implements Runnable{ //DER SENDET MESSAGES AN CLIENT
	
	private ObjectOutputStream oos = null;
	public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
	
	public ClientSender(Socket client, Queue<Message> sendq) throws IOException{
		oos=new ObjectOutputStream(client.getOutputStream()); //Hiermit wird gesendet
		this.sendq = sendq;
	}
	
	
	public void run(){
		System.out.println("Ich bin der ClientSender!");
			
		while(true){
			if(!sendq.isEmpty())
			try{
				oos.writeObject(sendq.remove());			
			} catch(IOException ioe) { }
			
		}
	}

}
```


Stellt gerne Fragen, wenn ich das nicht korrekt dokumentiert habe. Ich werde den ganzen Tag vor dem PC campen und versuchen dieses Problem zu lösen.

Grüße
BigFish


----------



## SlaterB (26. Mai 2011)

schade dass du keinen Client dazupostest, beim Nachbau habe ich aber glaube ich den Fehler gefunden, gibts häufiger:
auf beiden Seiten erstellst du erst jeweils den ObjectInputStream, 
dieser versucht aber bereits im Konstruktor etwas zu lesen und blockiert bis das gesendet wird,
-> beide Seiten warten, keiner sendet

Lösung: erstelle immer erst die Output-Variante, danach Input

edit: stände die Initialisierung wirklich im Thread, also nebenläufig, dann müsste es egal sein in welcher Reihenfolge die Threads gestartet werden, 
Konstruktor ist aber noch nicht nebenläufig

edit:
baue Wartezeiten in deine Schleifen ein, sonst wird Mio. Mal pro Sekunde in die Liste geschaut,
100% CPU-Belastung


----------



## BigFish (26. Mai 2011)

Also wenn ich dich richtig verstanden habe, dann müsste ich nur zuerst den ClientSender und DANN den ClientListener erstellen.
Das ergibt Sinn. Funktioniert aber nicht =)
Und danke für den Tipp mit den Wartezeiten!


----------



## SlaterB (26. Mai 2011)

inwiefern funktioniert es denn nicht?

hier mein Programm komplett,
nur Sender und Empfänger beim Server vertauscht brachte bereits die erste Ausgabe, 'Ich bin der ClientSender!' funktioniert,
damit die andere auch klappt ist natürlich beim Client der Verbindung ein ObjectOutputStream nötig, wie gesagt werden direkt gesendete Daten benötigt,
nachdem ich den ObjectOutputStream noch hinzugefügt habe erscheinen beide Listener-Ausgaben,

soweit das Ziel oder redest du schon von einem anderen Problem?
wobei ich natürlich nicht jeden simplen Schritt einzeln begleiten möchte, also sehr genau aussuchen was du fragst 


```
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        Runnable r = new Runnable()
            {
                public void run()
                {

                    Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
                    Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();

                    Thread t = new Thread(new Server(6001, sendq, listenq));
                    t.start();

                    Message msg = new Message("Huhu");
                    sendq.add(msg);
                    System.out.println("laeuft");

                }
            };
        new Thread(r).start();


        Thread.sleep(1000);

        Socket s = new Socket("localhost", 6001);
        new ObjectOutputStream(s.getOutputStream());
        Thread.sleep(1000);
    }
}


class Server
    implements Runnable
{

    private int port;
    public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();


    public Server(int port, Queue<Message> sendq, Queue<Message> listenq)
    {
        this.port = port;
        this.sendq = sendq;
        this.listenq = listenq;

    }

    public void run()
    {
        verbinde();
    }

    public void verbinde()
    {
        ServerSocket server = null;
        try
        {
            server = new ServerSocket(port);
        }
        catch (IOException ioe)
        {
            System.err.println("Der Port " + port + " kann nicht benutzt werden!");
            System.exit(1);
        }

        Socket client = null;
        while (true)
        {
            try
            {
                client = server.accept();
            }
            catch (IOException ioe)
            {
                System.err.println("Accept failed.");
                System.err.println(ioe);
                System.exit(1);
            }

            try
            {
                // Starte einen neuen Thread auf dem dem Klienten zugehoert wird

                System.out.println("Threads werden erzeugt: Serverebene");
                Thread sender = new Thread(new ClientSender(client, sendq));
                sender.start();
                
                Thread listener = new Thread(new ClientListener(client, listenq));
                listener.start();

            }
            catch (IOException ioe)
            {
                System.out.println("Fehler bei Thread-Erstellung");
                System.exit(1);
            }
        }
    }

}


class ClientListener
    implements Runnable
{ // DER HOERT DEM KLIENTEN ZU!

    private ObjectInputStream in = null;
    private Object msg = null;
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();

    public ClientListener(Socket client, Queue<Message> listenq)
        throws IOException
    {

        in = new ObjectInputStream(client.getInputStream()); // Hiermit wird empfangen
        this.listenq = listenq;
    }


    public void run()
    {

        try
        {
            System.out.println("Ich bin der ClientListener!");


            while (true)
            {
                try
                {
                    msg = in.readObject();
                    if (msg instanceof Message)
                    {
                        Message Nachricht = new Message(msg);
                        listenq.add(Nachricht);
                    }
                    else
                        System.out.println("Keine gueltige Message");
                }
                catch (ClassNotFoundException cnfe)
                {
                }

            }
        }
        catch (IOException e)
        {
            System.err.println(e);
        }
    }

}


class ClientSender
    implements Runnable
{ // DER SENDET MESSAGES AN CLIENT

    private ObjectOutputStream oos = null;
    public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();

    public ClientSender(Socket client, Queue<Message> sendq)
        throws IOException
    {
        oos = new ObjectOutputStream(client.getOutputStream()); // Hiermit wird gesendet
        this.sendq = sendq;
    }


    public void run()
    {
        System.out.println("Ich bin der ClientSender!");

        while (true)
        {
            if (!sendq.isEmpty()) try
            {
                oos.writeObject(sendq.remove());
            }
            catch (IOException ioe)
            {
            }

        }
    }

}


class Message
{
    Object st;

    public Message(Object st)
    {
        this.st = st;
    }

}
```
Ausgabe:

```
laeuft
Threads werden erzeugt: Serverebene
Ich bin der ClientSender!
Ich bin der ClientListener!
```


----------



## BigFish (26. Mai 2011)

Okay, dann wähle ich meine Frage mit bedacht ;-)...
Ich weiß schon wovon du redest und bin mit dem Thema vertraut!

Aber der Teil hier:


```
Socket s = new Socket("localhost", 6001);
        new ObjectOutputStream(s.getOutputStream());
        Thread.sleep(1000);
```

sieht für mich aus wie ein Client. 
Mit anderen Worten, dein Programm connected sich selbst oder seh ich das falsch?
Dann scheint es ja zu funktionieren. Ich hätte es aber gerne so, dass der Server wartet, bis eine Connection kommt.

Ist es nicht so, dass die Methode 
	
	
	
	





```
client.accept()
```
 innerhalb meines ersten Threads so lange wartet, bis ein Client zu dem Socket verbindet?
Wenn nein, gibt es eine Methode, die dies blockierend tut? 
Ich glaube das ist das Problem oder?


----------



## SlaterB (26. Mai 2011)

> Mit anderen Worten, dein Programm connected sich selbst oder seh ich das falsch?
richtig, als Simulation eines beliebigen Clients,
ist doch das normalste der Welt, sonst würde ja gar nichts passieren

> Ich hätte es aber gerne so, dass der Server wartet, bis eine Connection kommt.
wie du danach schon sagst und es auch hast ist accept() dafür da, funktioniert bei mir, funktioniert bei dir (oder wie genau nicht?), 
es gibt keine Alternative und kein sichtbares Problem dazu, was ist deine Frage?
welches Problem stellst du mit welchem Code fest, wo blockiert etwas zu wenig, zu viel, gar rückwirkend in der Zeit?

> Ich glaube das ist das Problem oder? 
welches Problem um alles in der Welt?!

im ursprünglichen Postings ging es um zwei Listener bei aufgebauter Client-Verbindung,
die Verbindung kommt erst nach beliebig langer Wartezeit zustande, dank accept(), 
dann gehts los und jetzt mit richtiger Reihenfolge/ richtiger Berücksichtigung der ObjectStreams geht das auch,
wo könnte hier ein Problem bestehen?


----------



## BigFish (26. Mai 2011)

Ok kleiner logischer Fehler meinerseits.
Es läuft, einfach nur durch das Vertauschen des Listeners und des Senders. 
Danke!


----------



## BigFish (26. Mai 2011)

Naja, so ganz läuft es immer noch nicht.
Der Client empfängt einfach die Nachrichten des Servers nicht. Andersrum habe ich es noch nicht getestet.
Das Problem liegt glaube ich in der Serialisierung.
Jedenfalls gibt es keine Exception, aber die Nachricht kommt einfach nicht an.

Client Sender // Der Sendet an den Client


```
public class ClientSender implements Runnable{ //DER SENDET MESSAGES AN CLIENT
	
	private ObjectOutputStream oos = null;
	public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
	
	public ClientSender(Socket client, Queue<Message> sendq) throws IOException{
		oos=new ObjectOutputStream(client.getOutputStream()); //Hiermit wird gesendet
		this.sendq = sendq;
	}
	
	
	public void run(){
		
			
		while(true){
			if(!sendq.isEmpty())
			try{
				System.out.println("Bis zur Queue ist es gekommen!");
				oos.writeObject(sendq.remove());	
				oos.flush();
			} catch(IOException ioe) { }
			
		}
	}

}
```

Wenn ich mit dem Client verbinde, befüllt er brav die Queue und die Ausgabe "Bis zur Queue ist es gekommen" entsteht.

Der ServerListener // der dem Server zuhört // Sieht so aus:


```
class ServerListener implements Runnable { //DER HOERT DEM SERVER ZU!
    private ObjectInputStream in = null;
    private Message msg=null;
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();


    public ServerListener(Socket server, Queue<Message> listenq) throws IOException {
       
    	in = new ObjectInputStream(server.getInputStream()); //Hiermit wird empfangen
    	this.listenq=listenq;
    }
    

    public void run() {    
        
        try {
             System.out.println("ServerListener");
            while (true) {
                try{
                msg = (Message) in.readObject();
                listenq.add(msg); 
                System.out.println("angekommen!");
                 /*if(msg instanceof Message) { 
                	listenq.add((Message) msg); 
                }
                else System.out.println("Keine gueltige Message"); */
                } catch(ClassNotFoundException cnfe) {} 
               
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}
```

Und bis hier kommt scheinbar die Nachricht nicht durch.

Mache ich beim Serialisieren einen Fehler?


----------



## SlaterB (26. Mai 2011)

ein Fehler ist immer, catch-Blöcke leer zu lassen,
ClassNotFoundException mag durchaus kommen wenn Server und Client eine unterschiedliche Vorstellung von der Message-Klasse haben,
z.B. unterschiedliches package,

geht die Übertragung von einfachen Strings?

bei mir klappts in einer Datei:

```
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        Runnable r = new Runnable()
            {
                public void run()
                {

                    Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
                    Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();

                    Thread t = new Thread(new Server(6001, sendq, listenq));
                    t.start();

                    System.out.println("laeuft");

                    sleep(2000);

                    System.out.println("erzeuge huhu");
                    Message msg = new Message("Huhu");
                    sendq.add(msg);

                }
            };
        new Thread(r).start();


        sleep(1000);
        System.out.println("starte Client");
        Socket s = new Socket("localhost", 6001);
        new ObjectOutputStream(s.getOutputStream());
        new Thread(new ServerListener(s, null)).start();
        sleep(1000);
        System.out.println("Ende main");
    }

    static void sleep(int ms)
    {
        try
        {
            Thread.sleep(ms);
        }
        catch (Exception e)
        {
        }
    }
}


class Server
    implements Runnable
{

    private int port;
    public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();


    public Server(int port, Queue<Message> sendq, Queue<Message> listenq)
    {
        this.port = port;
        this.sendq = sendq;
        this.listenq = listenq;

    }

    public void run()
    {
        verbinde();
    }

    public void verbinde()
    {
        ServerSocket server = null;
        try
        {
            server = new ServerSocket(port);
        }
        catch (IOException ioe)
        {
            System.err.println("Der Port " + port + " kann nicht benutzt werden!");
            System.exit(1);
        }

        Socket client = null;
        while (true)
        {
            try
            {
                client = server.accept();
            }
            catch (IOException ioe)
            {
                System.err.println("Accept failed.");
                System.err.println(ioe);
                System.exit(1);
            }

            try
            {
                // Starte einen neuen Thread auf dem dem Klienten zugehoert wird

                System.out.println("Threads werden erzeugt: Serverebene");
                Thread sender = new Thread(new ClientSender(client, sendq));
                sender.start();

                Thread listener = new Thread(new ClientListener(client, listenq));
                listener.start();

            }
            catch (IOException ioe)
            {
                System.out.println("Fehler bei Thread-Erstellung");
                System.exit(1);
            }
        }
    }

}


class ClientListener
    implements Runnable
{ // DER HOERT DEM KLIENTEN ZU!

    private ObjectInputStream in = null;
    private Object msg = null;
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();

    public ClientListener(Socket client, Queue<Message> listenq)
        throws IOException
    {

        in = new ObjectInputStream(client.getInputStream()); // Hiermit wird empfangen
        this.listenq = listenq;
    }


    public void run()
    {

        try
        {
            System.out.println("Ich bin der ClientListener!");


            while (true)
            {
                Test.sleep(100);
                try
                {
                    msg = in.readObject();
                    if (msg instanceof Message)
                    {
                        Message Nachricht = new Message(msg);
                        listenq.add(Nachricht);
                    }
                    else
                        System.out.println("Keine gueltige Message");
                }
                catch (ClassNotFoundException cnfe)
                {
                    cnfe.printStackTrace();
                }

            }
        }
        catch (IOException e)
        {
            System.err.println(e);
        }
    }

}


class ClientSender
    implements Runnable
{ // DER SENDET MESSAGES AN CLIENT

    private ObjectOutputStream oos = null;
    public Queue<Message> sendq = new ConcurrentLinkedQueue<Message>();

    public ClientSender(Socket client, Queue<Message> sendq)
        throws IOException
    {
        oos = new ObjectOutputStream(client.getOutputStream()); // Hiermit wird gesendet
        this.sendq = sendq;
    }


    public void run()
    {
        System.out.println("Ich bin der ClientSender!");

        while (true)
        {
            Test.sleep(100);
            if (!sendq.isEmpty()) try
            {
                oos.writeObject(sendq.remove());
            }
            catch (IOException ioe)
            {
                ioe.printStackTrace();
            }

        }
    }

}


class ServerListener
    implements Runnable
{ // DER HOERT DEM SERVER ZU!
    private ObjectInputStream in = null;
    private Message msg = null;
    public Queue<Message> listenq = new ConcurrentLinkedQueue<Message>();


    public ServerListener(Socket server, Queue<Message> listenq)
        throws IOException
    {

        in = new ObjectInputStream(server.getInputStream()); // Hiermit wird empfangen
        // this.listenq = listenq;
    }


    public void run()
    {

        try
        {
            System.out.println("ServerListener");
            while (true)
            {
                Test.sleep(100);
                try
                {
                    msg = (Message)in.readObject();
                    listenq.add(msg);
                    System.out.println("angekommen!");
                    /*
                     * if(msg instanceof Message) { listenq.add((Message) msg); } else
                     * System.out.println("Keine gueltige Message");
                     */
                }
                catch (ClassNotFoundException cnfe)
                {
                    cnfe.printStackTrace();
                }

            }
        }
        catch (IOException e)
        {
            System.err.println(e);
        }
    }
}


class Message
    implements Serializable
{
    Object st;

    public Message(Object st)
    {
        this.st = st;
    }
}
```


```
laeuft
starte Client
Threads werden erzeugt: Serverebene
Ich bin der ClientSender!
ServerListener
Ich bin der ClientListener!
erzeuge huhu
angekommen!
Ende main
```


----------



## BigFish (26. Mai 2011)

Ahja, guter Tipp mit den Exceptions ;-)...
Also der Serverlistener wirft eine "ClassNotFoundException".

Das verstehe ich aber nicht, weil er ganz normal Zugriff auf die gleiche Message-Klasse wie der Server hat.


----------



## BigFish (26. Mai 2011)

Da ich mir nicht sicher war, ob Objekt serialisierbar ist, habe ich die Message Klasse auch einmal mit einem String gefüllt. Das geht aber auch nicht.


----------



## BigFish (26. Mai 2011)

OK, package Namen vergessen bei der Serverkommunikation.
Habe mir selber geholfen =)


----------

