# Wiedereinmal Sockets ;-)



## Scruffy (13. Mai 2008)

Ich muß eine Lösung entwerfen und realisieren bei der ein Server Datensätze von hunderten von Clients empfängt und diese dann in eine Datenbank schreibt. Leider komme ich nicht über das Login der Clients hinaus. Ich habe ein recht seltsames Problem:
Ich habe (zum Testen) einen SocketServer und einen Socket-Client geschrieben. Diese sollen abwechselnd miteinander kommunizieren. Wenn ich versuche mich mit dem Testclient einfach mit dem Server zu verbinden und die Übertragung hinzubekommen, stockt der Server schon beim ersten in.readLine(); Wenn ich mich aber per Telnet mit dem Server verbinde und die Strings eintippe funktioniert der Server einwandfrei! Kann mir einer einen Tipp für die Ursache geben?


```
public class Server {

    public static final int PORT = 8765;

    public static void main(String[] args) {
        int cnt = 0;
        try {
            System.out.println("Warte auf Verbindungen auf Port "+PORT+"...");
            ServerSocket echod = new ServerSocket(PORT);
            while (true) {
                Socket socket = echod.accept();
                (new ConnectionThread(++cnt, socket)).start();
            }
        } catch (IOException e) {
            System.err.println(e.toString());
            System.exit(1);
        }
    }
}
```


```
public class ConnectionThread extends Thread {

    private int name;
    private Socket socket;

    public ConnectionThread(int name, Socket socket) {
        this.setDaemon(true);

        this.name = name;
        this.socket = socket;
    }

    @Override
    public void run() {
        String msg = "Server: Verbindung " + name;
        System.out.println(msg + " hergestellt");
        try {
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(is));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(os));

            System.out.println("Step #1");

            String benutzer = in.readLine();

            out.write("GOT USERNAME");
            out.newLine();
            out.flush();

            String passwort = in.readLine();

            System.out.println("Step #1.2");
            out.write("GOT PASSWORD");
            out.newLine();
            out.flush();

            System.out.println("Step #2");

            System.out.println("Benutzername: " + benutzer);
            System.out.println("Passwort: " + passwort);

            System.out.println("Step #3");

            if ((benutzer.equalsIgnoreCase("test")) && (passwort.equalsIgnoreCase("123"))) {
                out.write("OK");
                out.newLine();
                out.flush();
                System.out.println("Step #3.1");
            } else {
                out.write("IGNORE");
                out.newLine();
                out.flush();
                System.out.println("Step #3.2");
            }

            System.out.println("Step #4");

            System.out.println("Verbindung " + name + " wird beendet");

            in.close();
            out.close();
        } catch (IOException e) {
            System.err.println(e.toString());
        } finally {
            try {
                socket.close();
            } catch (IOException ex) {
                System.err.println(ex.toString());
            }
        }
    }
}
```


```
public class Client {

    public static void main(String[] args) {
        Socket server = null;

        try {
            System.out.println("Open socket...");
            server = new Socket("172.20.50.89", 8765);
            
            System.out.println("Initilize streams...");
            InputStream is = server.getInputStream();
            OutputStream os = server.getOutputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(is));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(os));

            System.out.print("Write username... ");
            out.write("test");
            out.flush();
            System.out.println("written");
            
            System.out.println("Waiting for answer... --> "+in.readLine());
            
            System.out.print("Write password...");
            out.write("123");
            out.flush();
            System.out.println("written");
            
            System.out.println("Waiting for answer... --> "+in.readLine());
            String antwort = in.readLine();
            
            System.out.println("Answer server: "+in.readLine());
            
            if (antwort.equalsIgnoreCase("OK")) {
                System.out.println("Write dataset...");
                out.write("Schicke Datensatz!");
                out.flush();
            }

            System.out.println("Write close...");
            out.write("Beende Verbindung!");
            in.close();
            out.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (server != null) {
                try {
                    System.out.println("Close connection...");
                    server.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
```

Laßt euch von den System.out.println(...) nicht stören, ich habe diese zum debugging eingebaut. Und bitte keine Vorschläge, daß ich es mit RMI lösen soll: Die Clients müssen auch in der Lage sein, Daten auf der lokalen Festplatte zwischen zu speichern, fall mal keine Verbindung zum Server besteht.


----------



## SlaterB (13. Mai 2008)

erstmal grobe Schätzung:

beim Server hast du überall sauber
out.write("GOT USERNAME"); 
            out.newLine(); 
            out.flush(); 

beim Client dagegen
out.write("test"); 
            out.flush(); 

fällt dir was auf, worauf der Server mit 
 String benutzer = in.readLine(); 
warten könnte?


----------



## Scruffy (13. Mai 2008)

Eine Zeile weiter steht beim Client 

```
System.out.println("Waiting for answer... --> "+in.readLine());
```
Also wartet er dort auf eine Antwort vom Server.


----------



## SlaterB (13. Mai 2008)

ich bezog mich auf deinen Satz
>  stockt der Server schon beim ersten in.readLine(); 

wenn der Server wartet, dann kann er auch keine Antwort an den Client senden 

wichtig ist also, ob der Server die erste Nachricht empfängt oder nicht


----------



## Scruffy (13. Mai 2008)

Der Server wartet zuerst auf eine Eingabe. Wie gesagt, mit Telnet klappt das alles wunderbar. Nur mit dem Java Client hab ich Probleme...


----------



## SlaterB (13. Mai 2008)

gut, das hätten wir geklärt, zurück zu meinem Posting,
wie gesagt verwendet der Server zum Senden korrekt drei CodeZeilen,
der Client dagegen nur zwei, eine fehlt,

schau doch mal nach


----------



## Scruffy (13. Mai 2008)

Jo, Tatsache! Es fehlte das in.newLine(); Danke für das wegwischen der Tomaten auf den Augen! ;-)


----------



## lhein (14. Mai 2008)

Schau Dir mal xSocket an. Das nutzt NIO Klassen und bietet schon ein funktionierendes Framework in das Du einfach Deine Handler einklinken kannst. Warum immer das Rad neu erfinden?

lhe


----------



## SlaterB (14. Mai 2008)

wozu in der Schule rechnen lernen, gibt doch Taschenrechner  :roll:


----------



## lhein (14. Mai 2008)

Der Vergleich hinkt. 

1. Wenn ich ein Projekt zu stemmen habe, dann will ich nicht bei Null anfangen, da ich vermutlich auch einen gewissen Zeitdruck habe.

2. Warum soll ich etwas selber bauen, wenn es ein schon fertiges, getestetes und zudem freies Framework für meine Anforderungen gibt?

3. um bei den hinkenden Vergleichen zu bleiben müssten dann alle Restaurants der Welt schliessen, weil ja jeder selbst kocht.


----------



## SlaterB (14. Mai 2008)

>  müssten dann alle Restaurants der Welt schliessen

nene, dass passt nur zu 'alle Taschenrechner auf der Welt wegschmeißen, weil alle selber rechnen'
aber das sage ich ja nicht, die Taschenrechner genau wie die Library sind sehr sinnvolle Dinge,

trotzdem ist das 'per Hand'-Verfahren genauso sinnvoll,
zum Verständnis und Erlernen der Techniken, 
sowohl bei Sockets wie auch beim Rechnen und selbst beim Kochen 

und auch dann wenn man nicht mal bei Null anfängt, also die Kommunikation unterhalb der Sockets oder die Herstellung der Lebensmittel ignoriert
(bei der Mathematik ist es (zumindest für mich) etwas schwerer, die Grundlagen zu benennen  )


----------



## lhein (14. Mai 2008)

Das stellt ja auch niemand in Frage. 
Die Lib bietet jedoch eine Möglichkeit, den Entwicklungsprozess der Anwendung erheblich zu beschleunigen. Nicht mehr und nicht weniger sollte mein Posting aussagen.

lhe


----------



## Dandro (14. Mai 2008)

@lhe

kennst du Apache MINA? Das ist auch ein super Framework für die NIO. Kann es allerdings jetzt so adhoc nicht mit xSocket vergleichen, da ich damit noch nicht gearbeitet habe.


----------



## lhein (14. Mai 2008)

Ich hab davon gehört, aber noch nie verwendet. Sieht auf den ersten Blick mächtiger aus


----------



## Dandro (14. Mai 2008)

Wie gesagt kann es mit xSocket nicht vergleichen, aber da ich die MINA schonmal verwendet habe, kann ich sagen, dass die Arbeit damit total angenehm ist. Der größte Vorteil ist, dass man sich nicht mehr zwischen UDP und TCP kümmern muss, das wird nämlich "oben" gleich behandelt, obwohl UDP ja bekanntermaßen Verbindungslos ist.

Ich kann es nur empfehlen, auch weil sich jetzt zur 2ten Version einige Sachen gebessert haben.


----------



## Patte (15. Mai 2008)

das geht auch bei xSocket. Dort gibt es die Interfaces IDataSink und IDataSource, welche sowohl von UDP-Seite, als auch von der TCP-Seite implementiert wird. 

Der große Unterschied zwischen MINA und xSocket ist, dass du bei xSocket auf der TCP-Seite eine Connection zum lesen und schreiben der Daten verwendest. xSocket puffert dann intern die mögliche Fragmentierung von Daten auf der Netzwerkebene, und stellt dir Methoden bereit um beispielsweise aufgrund von Delimiter Daten zu lesen -> readStringByDelimiter(...), ...

Gegenüber diesem Stream-orientierten Ansatz bei TCP verfolgt MINA das Konzept von Messages. D.h. du musst unter Umständen die Netzwerkfragmentierung in deinem Programmcode selbst behandeln (je nach dem MINA CODEC, denn du verwendest). MINA selbst sieht seine Stärke in der Anzahl der unterstützten CODEC. Die Frage ist, ob diese für deine Problemstellung überhaupt benötigst.

Ich habe schon mit beiden Frameworks gearbeitet (und auch mit Grizzly, was mir gar nicht gefallen hat), und muss sagen, dass xSocket für mein Problem die elegantere Lösung war. 

Patte


----------

