# String über Sockets versenden - ObjectOutputStream/ObjectInputStream



## HuRaHoRRe (9. Oktober 2007)

hi 

Ich habe ein kleines Problem, ich bin daran einen kleinen Client/Server chat zu schreiben...
Nun habe ich das versenden von Integers über Sockets fertiggebracht :/
Ich möchte nun aber Strings versenen und das geht mit Out/Input Stream anscheinend nicht....
Ich hab es nun nach der Suche nach einer Lösung im Internet mit ObjectInput/OutputStream
Probiert jedoch ohne Erfolg...

Ich hoffe jemand hat ne Ahnung was daran falsch ist:


```
public void run()
    {
           try{
           Socket server = new Socket("localhost", 1234);
             while( server.isConnected() )
             {
               ObjectInputStream in = new ObjectInputStream(server.getInputStream()); 
               ObjectOutputStream out = new ObjectOutputStream(server.getOutputStream());

               out.write(1);
               int zahlback = in.read();
               String zahl = Integer.toString(zahlback);
               textArea.setText(zahl);
               out.flush();
               in.close();
               out.close();
             }
           }
           catch(IOException e)
           {
               System.out.println(e);
           }
       }
```


----------



## zerix (9. Oktober 2007)

Hallo,

was funktioniert denn nicht?

MFG

zEriX


----------



## HuRaHoRRe (9. Oktober 2007)

Ich habe 2 Programme, das eine ist der Client mit Gui und das andere der Server mit Gui/Adminfunktion usw...

Nun habe ich es mit


```
InputStream in = server.getInputStream();
OutputStream out = server.getOutputStream();
```

fertiggebracht die 2 Integers auszutauschen und sie jeweils in der TextArea anzuzeigen.
Nun habe ich das ganze so wie bei meinem ersten Post umgestellt und nun wird nichts mehr in die TextArea geschrieben.


----------



## dto (9. Oktober 2007)

Hier ein kleines Beispiel.

SERVER:

```
public class Server {
    
    public Server() {
        try {
            java.net.ServerSocket soc = new java.net.ServerSocket(6000);            
            java.net.Socket in = soc.accept();
            java.io.InputStreamReader input = new java.io.InputStreamReader(in.getInputStream());
            
            int length=-1;
            char[] buffer = new char[4096];
            
            while(true){
                while(-1!=(length=input.read(buffer))){
                    System.out.println(
                            String.copyValueOf(buffer,0,length)
                    );
                }
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        new Server();
    }   
}
```

CLIENT:

```
public class Client {
    
    public Client() {
        try {
            java.net.Socket soc = new java.net.Socket("localhost",6000);
            java.io.OutputStream out = soc.getOutputStream();            
            
            while(true){
                
                System.out.print("Eingabe: ");
                
                String eingabe =
                    new java.io.BufferedReader(
                            new java.io.InputStreamReader(System.in)
                    ).readLine();
                
                out.write(eingabe.getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    
    public static void main(String[] args) {
        new Client();
    }
}
```

Wenn ich dir helfen konnte würde ich mich über ein Renommee freuen.


----------



## HuRaHoRRe (11. Oktober 2007)

Vielen Dank für dein Besipiel 

Hatte leider noch einige Sachen zu tun, weswegen ich nicht gleich antworten konnte.

Wenn die Nachricht im Thread und per Command Line versendet wird erhalte ich keine Fehler und der Server erhält die Nachricht und schreibt sie in die Textarea.

Soweit funktioniert es auch, nur habe ich es jetzt für meinen Zweck angepasst und für das Gui ein bisschen umgeschrieben.
Wenn ich das ganze nun so mache das die Nachricht beim klicken eines Buttons gesendet wird erhalte ich jedesmal eine "NullPointerException".

Ich werde wohl irgendwo einen Überlegungsfehler drin haben, aber ich komme im Moment leider nicht drauf wo das sein könnte.

beim klicken des Buttons wird die Methode "sendMessage" in der Client Kasse aufgerufen:

```
private void button_sendMessageActionPerformed(java.awt.event.ActionEvent evt) {                                                   
    // TODO add your handling code here:
        Client send = new Client(this.textArea_conversation,this.textField_sendMessage);
        send.sendMessage();
    }
```

Dann die Client Klasse mit sendMessage Methode:


```
/*
 * Client.java
 *
 * Created on 9. Oktober 2007, 10:54
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package client;

import java.io.*;
import java.net.*;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 *
 * @author lgwerm
 */
public class Client extends Thread{
    
    /** Creates a new instance of Client */
    private JTextArea textArea = null;
    private JTextField textField = null;
    private java.net.Socket soc = null;
    private java.io.OutputStream out = null;
    
    public Client(JTextArea textarea, JTextField textfield) 
    {
         this.textArea = textarea;
         this.textField = textfield;
    }
    public void run()
    {
       /*    
        try {                
            while(true){              
                System.out.print("Eingabe: ");
               
                String eingabe =
                    new java.io.BufferedReader(
                            new java.io.InputStreamReader(System.in)
                    ).readLine();             
                out.write(eingabe.getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        */
    }    
    public void connect() throws IOException
    {
         soc = new java.net.Socket("localhost",6000);
         out = soc.getOutputStream(); 
         
         this.start();
    }
    public void sendMessage() {
        
        String message = textField.getText();
        try {
            out.write(message.getBytes());     
        } catch (IOException ex) {
            ex.printStackTrace();
        }     
    }
}
```

Hoffe das mir noch mal jemand helfen kann bei  kommt man bei einer NullPointerException leider nicht gerade weit


----------



## Kulabac (12. Oktober 2007)

Hmm, sieht soweit eigentlich alles ganz gut aus. Keine Ahnung wo du da das Problem hast. Hätte ich glaub ich genauso gemacht. Das einzige wo ich drüber gestolpert bin, ist dieses String message = textField.getText(); - das kann laut API eine NullpointerException geben, wenn das zugrunde liegende Dokument null ist. Den Fall hatte ich aber noch nie. Vielleicht benutzt du einen falschen Konstruktor für dein JTextFeld?


----------



## HuRaHoRRe (12. Oktober 2007)

Das die NullPointerException ausgelöst werden kann wenn ein objekt den wert null hat habe ich auch schon in Erfahrung gebracht, weswegen ich das ganze im Debugger angeschaut habe.
Die Variable wird ganz normal gefüllt und hat den wert des Text Feldes richtig übernommen, ist also nicht null.

Oder hast du etwas anderes gemeint?

Edit: Ich poste am besten mal die ganze Fehlermeldung vielleicht kann man daraus was lesen, also ich kanns nicht ^^


```
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at client.Client.sendMessage(Client.java:63)
        at client.Gui.button_sendMessageActionPerformed(Gui.java:118)
        at client.Gui.access$000(Gui.java:15)
        at client.Gui$2.actionPerformed(Gui.java:61)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:6038)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
        at java.awt.Component.processEvent(Component.java:5803)
        at java.awt.Container.processEvent(Container.java:2058)
        at java.awt.Component.dispatchEventImpl(Component.java:4410)
        at java.awt.Container.dispatchEventImpl(Container.java:2116)
        at java.awt.Component.dispatchEvent(Component.java:4240)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
        at java.awt.Container.dispatchEventImpl(Container.java:2102)
        at java.awt.Window.dispatchEventImpl(Window.java:2429)
        at java.awt.Component.dispatchEvent(Component.java:4240)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
```


----------



## Kulabac (12. Oktober 2007)

Ja, ich meinte was anderes. JTextField erbt ja von JTextComponent und da kommt deine Methode getText() her. In der API steht "Returns the text contained in this TextComponent. If the underlying document is null, will give a NullPointerException. Note that text is not a bound property, so no PropertyChangeEvent is fired when it changes. To listen for changes to the text, use DocumentListener." - Mit anderen Worten das kann ne NullpointerException geben, wenn das Dokument null ist, selbst wenn die JTextComponent initialisiert wurde. Hatte ich aber noch nicht, also was dieses Dokument sein soll, weiß ich auch nicht.

JTextField hat verschiedene Konstruktoren. Darunter auch einen, dem man ein Dokument übergeben kann. Ich dachte du hättest den vielleicht versehentlich benutzt und da null übergeben. Ich hätte halt einfach versucht das JTextField mal probeweise mit new JTextField("irgendeinText") zu initalisieren und zu schauen, was passiert.

In deinem geposteten Code seh ich ja, dass alle Variablen initalisiert werden. Also da steht die NullpointerException nicht mit bei. Muss also woanders herkommen und das wäre so eine Idee wo es halt sein könnte.

Aber deine Nullpointer-Exception verrät doch genau in welcher Zeile der Fehler auftritt. Vielleicht würde es auch schon weiterhelfen, wenn du uns verrätst wo genau die auftritt 



Eine andere Idee wäre noch, dass du vielleicht vergessen hast, die connect-Methode aufzurufen  ?

Und (das hat jetzt aber nichts mit der NullPointerException zu tun) ich würde nach dem out.write noch ein out.flush(); machen, sonst wunderst du dich, dass die Daten nicht ankommen


----------



## HuRaHoRRe (12. Oktober 2007)

Habe meinen Code von oben editiert bevor ich deinen Post gesehen habe, vielleicht kannst du da was rauslesen, ich Teste das ganze jetzt einmal mit einer ganz normalen Variable.
Dann kann ich sehen ob es an dem Text Feld liegt.

Edit: Die Methode Connect rufe ich  beim Klicken auf einen Button auf, das funktioniert soweit, wenn ich die nachricht im thread sende dann funktioniert es ja auch.

Hab es nun mit einem ganz normalen String anstatt dem TextFeld probiert, funktioniert nicht.


----------



## Kulabac (12. Oktober 2007)

Zeile 63 ... d.h. entweder out ist null oder message ist null. Message kann eigentlich nicht null sein (weil ein leeres TextFeld ja auch immerhin "" enthält), bliebe also weiterhin die Idee, dass du die Connect-Methode nicht aufgerufen hast. Oder vielleicht hast du die aufgerufen und es tritt eine Exception auf, die du nicht bemerkst, weil du vergessen hast sie auszugeben?


----------



## HuRaHoRRe (12. Oktober 2007)

Stimmt out ist null.... :/
Nur wieso? ich habe die Variable ja in der Klasse definiert, bei der Methode connect(die ich aufrufe) wird sie dann gefüllt, was laut debugger auch funktioniert.
Nur in der Methode sendMessage ist sie wieder null....


----------



## Kulabac (12. Oktober 2007)

HuRaHoRRe hat gesagt.:


> Stimmt out ist null.... :/
> Nur wieso? ich habe die Variable ja in der Klasse definiert, bei der Methode connect(die ich aufrufe) wird sie dann gefüllt, was laut debugger auch funktioniert.
> Nur in der Methode sendMessage ist sie wieder null....



Also eine Idee hätte ich da noch: 


HuRaHoRRe hat gesagt.:


> beim klicken des Buttons wird die Methode "sendMessage" in der Client Kasse aufgerufen:
> 
> ```
> private void button_sendMessageActionPerformed(java.awt.event.ActionEvent evt) {
> ...


D.h. jedes Mal wenn du auf den Button klickst wird ein neuer Client erzeugt. Und hier seh ich halt nicht den Connect()-Aufruf. Oder überseh ich da was?


----------



## HuRaHoRRe (12. Oktober 2007)

Mhh nein der Connect Aufruf wird mit einem anderen Button in einer Menubar aufgerufen 

hier:


```
private void menuItem_connectServerActionPerformed(java.awt.event.ActionEvent evt) {                                                       
    // TODO add your handling code here:
        Client client = new Client(this.textArea_conversation,this.textField_sendMessage);
        try {
            client.connect();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
```

muss ich das connect etwa in einem Thread machen damit das die ganze Zeit Läuft und die Variable erhalten bleibt oder was?

Achja vielen Dank für deine Mühe bisher


----------



## Kulabac (12. Oktober 2007)

Also das Problem ist, dass du ständig neue Client-Objekte benutzt. Jedes neue Client-Objekt hat erstmal out auf null. Weil jedes Objekt hat ja seine eigenen Variablen.

Das ganze in einem Thread zu machen und nicht immer wieder neu zu erzeugen halte ich im Moment für die beste Idee (vor allem weil du den Socket ja öffnest und dann nicht wieder zumachst). Wenn du unbedingt ständig neue Client-Objekte erzeugen willst, müsste das auch gehen indem du die out-Variable static machst. (Ist jetzt wo der Rest vom Code schon steht am einfachsten). Aber das wäre unschön - also 1 Thread pro Server, der Daten empfangen soll ... ich denke so würde man das normalerweise machen.


----------



## HuRaHoRRe (12. Oktober 2007)

Das mit dem Static funktioniert 

Nur scheint es ja nicht gerade optimal zu sein.
Ich habe jetzt grad nicht so eine Ahnung wie ich es mit dem Thread machen müsste.


----------



## Kulabac (12. Oktober 2007)

Naja, jetzt wo ich so darüber nachdenke ... du sendest eine Nachricht indem du einen neuen Client erzeugst und wartest dann drauf, dass der Client vom GarbageCollector wieder gelöscht wird ... doch, kann man machen. Sollte auch nicht zu Problemen führen 

Allerdings bringt dir das nichts. Weil du startest die Clients, die die Nachrichten wirklich senden, ja nicht als Thread. Du rufst die send-Methode auf und wartest in deinem Hauptprogramm, dass das ganze mit Senden fertig ist. Bei dieser Art kannst du dir den Client auch sparen und die Nachricht direkt raussenden. Ist der gleiche Effekt. Normalerweise würde man den Client vielleicht benutzen um direkt weiterarbeiten zu können und um nicht evtl. TimeOut-Exceptions oder ähnliches abwarten zu müssen. Aber solange es wirklich nur ein Chat ist ... würde man das mit den Threads am besten sowieso ganz vergessen. Also Server und Client als eigenständige Programme schreiben und fertig.

dontschew hat ja schon geschrieben, wie man das machen würde.


----------



## HuRaHoRRe (12. Oktober 2007)

Ok das leuchtet schon ein nur müsste ich das jetzt irgendwie so hinkriegen das der Server alle empfangenen Nachrichten an alle verbundenen Clients zurückschickt.
Dass dann im CLientprogramm alle an den Server gesendeten Nachrichten angezeigt werden können.

Hast du oder sonst jemand eine Ahnung wie ich das machen kann, so eine Art Broadcast.


----------



## Kulabac (12. Oktober 2007)

Naja, ich hab leider gerade keine Zeit dir ein Programmierbeispiel zu geben ... aber Google sollte gerade bei Chat und Java massenhaft Ergebnisse ausspucken.

Broadcast würde ich nicht verwenden. Kann man zwar machen, aber in deinem Fall weißt du ja, welche Clients vorhanden sind (es steht ja eine Socket-Verbindung zu ihnen).
Also prinzipiell würde ich wie folgt vorgehen: Du hast im Server vermutlich auch einen ServerSocket geöffnet. Wenn dieser mit irgendwas verbunden wird, wird ein neuer Socket erzeugt. Dein ServerSocket sollte in einer Endlosschleife sein 
Außerdem musst du dir den neuen Socket irgendwo wegspeichern (Vector, ArrayList, was auch immer).
Dann musst du einen neuen Thread erzeugen (einen neuen pro Verbindung) und versuchst in einer Endlosschleife aus dem Socket zu lesen. Wenn Daten reinkommen durch den InputStream gibst du die am besten an den Hauptthread zurück und sendest die von da an alle anderen Clients. (Soll heißen, dass ich die Methode zum Versenden an alle Clients mit in den ersten Thread packen würde, der den ServerSocket erzeugt hat, weil dort die komplette Liste mit allen Clients liegen sollte). Der Thread zum Empfang der Nachrichten von einem Client braucht also einen Verweis auf den Hauptthread und Socket als Parameter.

Clientseitig brauchst du jetzt auch einen zweiten Thread. Dieser bekommt den InputStream vom Socket und versucht ununterbrochen (und in einer Endlosschleife) draus zu lesen (Lesen ist meistens eine blockierende Anweisung, deswegen ist hier der neue Thread nötig). Und das war's eigentlich auch schon. Das eingelesene muss natürlich noch irgendwo ausgegeben werden.

Hmm ... erklären war ich noch nie gut drin. Aber Google müsste zu dem Thema eigentlich auch genug ausspucken


----------



## HuRaHoRRe (12. Oktober 2007)

ok vielen Dank 

me @


----------

