# String von Client zu Server kommt nicht an



## Turing0001 (23. Mrz 2021)

Hallo Leute,

ich sehe wohl mal wieder den Wald vor lauter Bäumen nicht mehr. Ich habe einen einfachen Client und einen einfachen Server geschrieben. Der Client sendet einen
SQL Befehl als String an einen Server, der das Ganze weiterleitet an eine SQLITE-Datenbank und das Resultset dann mittels einer ArrayList an den Client zurückschickt. Das Zurüsckschicken funktioniert, die Daten werden angezeigt, wenn ich den SQL-Befehl innerhalb des Servers erzeuge. Der von Client gesendete String scheint dort aber nicht anzukommen, vielleicht mache ich da einen prinzipiellen Dnkfehler. Könnte mal jemand drüberschauen und mir sagen warum der String nicht ankommt beim Server? Vielen Dank schon mal vorab.
Hier zunächst der Client:


```
package mypackage;

import java.io.*;
import java.net.*;
import java.util.ArrayList;




public class ClientDB {
    
     private InetSocketAddress address;
     PrintWriter writer;
    
    public void los()
    {
        
        try
        {
        
          address = new InetSocketAddress("localhost",4243);
          Socket s = new Socket();
          s.connect(address, 3000); // Verbinde Dich mit dem Server, maximale Wartezeit: 3 Sekunden
          writer = new PrintWriter(s.getOutputStream());
          ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
          writer.println("select * from leute");
          writer.flush();
          ArrayList <String> al = (ArrayList<String>)(ois.readObject());
          System.out.println(al.toString());
        
        
          ois.close();
          s.close();
          writer.close();
        }
          
       catch(IOException ex) {ex.printStackTrace();}
       catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // Client starten:
        
        ClientDB client1 = new ClientDB();
        client1.los();
    }
}
```


Und nun noch der Server:



```
package mypackage;

import java.io.*;
import java.net.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import javax.swing.JOptionPane;



public class ServerDB {
    
    Connection conn;//Schnittstelle um Verbindung zur DB herzustellen
    Statement stmt;
    ResultSet rSet;
    BufferedReader reader;
    

    public void los()
    {
        try
        {
            ServerSocket servsock = new ServerSocket(4243); // Verbindungsschnittstelle auf Port 4243 erstellen
            while(true)
            {
                System.out.println("Hallo hier ist der Server!");
                Socket sock = servsock.accept(); // Warten auf "Anruf" von einem Client. accept() blockiert bis ein Client "anruft"

                InputStreamReader isReader = new InputStreamReader (sock.getInputStream());
                reader = new BufferedReader(isReader);
                String nachricht = null;
                System.out.println("Bin hier");
                
                while((nachricht = reader.readLine()) != null)
                {
                     System.out.println("Empfangene Nachricht: " + nachricht);
                }
        
              
                JOptionPane.showMessageDialog(null, "Nachricht: " + nachricht);
              
               DriverManager.setLogWriter(new PrintWriter(System.out));
               Class.forName("org.sqlite.JDBC");
               System.out.println("Treiber geladen");
               String url = "jdbc:sqlite::resource:"+ "MyDB.db";
               conn = DriverManager.getConnection(url,"",""); // Verbindungsobjekt erstellen
                  System.out.println("Verbindung steht" );
                  stmt = conn.createStatement();
                  rSet = stmt.executeQuery(nachricht); // Schicke den SQL-Befehl an die Datenbank und nimm das Ergebnis entgegen
                  ResultSetMetaData md = rSet.getMetaData(); // Ermittele Meta-Daten des ResultSets
                  int columns = md.getColumnCount();
                  System.out.println("Anzahl der Spalten: " + columns + " \n");
                  ArrayList <String> tabledat = new ArrayList<String>();
                  while(rSet.next()) { // Solange noch Ergebnisdatensätze da sind...
                
                for(int i=1; i<=columns; ++i) {
                     // Durchlaufe alle Spalten der aktuellen Zeile des ResultSets
                    tabledat.add(rSet.getString(i)); // Aktuellen Eintrag des ResultSets in ArrayList speichern
                    
                }
            }
                  
                  
                  
                  
                  
               OutputStream os = sock.getOutputStream();
               ObjectOutputStream oos = new ObjectOutputStream(os);
               oos.writeObject(tabledat);
               oos.flush();
               oos.close();
               servsock.close();
            }
            
        }
        
        catch (IOException ex)
        {ex.printStackTrace();}
        catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {           
            CloseDB(stmt,conn); // Datenbankverbindung schließen
        }   
    
    
  
}
    
    public void CloseDB(Statement stmt, Connection conn )
    {
        try {
            stmt.close();
            conn.close();
        } catch(Exception e) {
            //
        }
    }
    public static void main(String[] args) {
        // Starte den Server:
        
        ServerDB serv = new ServerDB();
        serv.los();
    }
}
```


----------



## fhoffmann (23. Mrz 2021)

Wird die Nachricht denn auf der Konsole (des Servers) ausgegeben?

```
while((nachricht = reader.readLine()) != null)
                {
                     System.out.println("Empfangene Nachricht: " + nachricht);
                }
```
.
Diese while-Schleife endet erst, wenn der Client die Verbindung schließt. Das tut er aber nicht, weil er noch auf eine Antwort wartet


----------



## Turing0001 (23. Mrz 2021)

Hallo fhoffmann,

nein, auf der Konsole erscheint gar nichts.


----------



## fhoffmann (23. Mrz 2021)

Turing0001 hat gesagt.:


> nein, auf der Konsole erscheint gar nichts.


Erscheint denn "Bin hier" ?


----------



## kneitzel (23. Mrz 2021)

Turing0001 hat gesagt.:


> nein, auf der Konsole erscheint gar nichts.


Das sollte aber - ich habe Deinen Code einfach mal 1:1 kopiert und siehe da: Auf der Konsole erscheint genau das erwartete:

```
C:\Projects\Java-Tests\src>java ServerDB.java
Hallo hier ist der Server!
Bin hier
```

Wobei die erste Zeile nach dem Start kommt und die zweite Zeile sobald der Client gestartet wird.

Daher ist das Problem genau das, was @fhoffmann bereits geschrieben hat: Dein Server liest so lange Zeilen ein, bis die Verbindung beendet wird.


----------



## fhoffmann (23. Mrz 2021)

Ich würde aber als Ausgabe erwarten:

```
Hallo hier ist der Server!
Bin hier
Empfangene Nachricht: select * from leute
```


----------



## Turing0001 (23. Mrz 2021)

Hallo kneitzel,

vielen Dank für die Antwort. "Bin hier" erscheint natürlich. Ich habe es auch schon ohne Schleife versucht, einfach nur nachricht = reader.readLine(),
leider auch ohne Erfolg. Wie sollte es denn richtig lauten damit der String beim Server ankommt? Ich wäre für jeden Hinweis dankbar.


----------



## kneitzel (23. Mrz 2021)

Klar - da habe ich nicht gut genug hingeschaut. Das Problem ist, dass der Client einen ObjectInputStream erzeugt:

```
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
```
Dieser erwartet natürlich sofort die Initialisierung, d.h. es werden ein paar erste Bytes gelesen und auf die wartet der Client.

Also entweder das erst erzeugen, wenn die Nachricht gesendet wurde:

```
writer = new PrintWriter(s.getOutputStream());
            writer.println("select * from leute");
            writer.flush();
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
            ArrayList <String> al = (ArrayList<String>)(ois.readObject());
            System.out.println(al.toString());
```

Oder dafür sorgen, dass der Server die Initialisierung sofort macht:


```
System.out.println("Bin hier");

                OutputStream os = sock.getOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(os);
                oos.flush();
                
                if((nachricht = reader.readLine()) != null)
                {
                    System.out.println("Empfangene Nachricht: " + nachricht);
                }
```

Beides behebt die Problematik - aber nur eins von beidem ist notwendig.


----------



## fhoffmann (23. Mrz 2021)

@Turing0001 : Wenn das mit einem Client nun klappt, solltest du den Server danach so umschreiben, dass sich auch mehr als ein Client anmelden kann. Und es sollte möglich sein, dass ein Client mehr als eine Nachricht schickt (ohne sich neu anzumelden).
Dabei hast du zwei Probleme:
- die Methode "accept()" blockiert, bis sich ein Client angemeldet hat.
- die Methode "readLine()" blockiert, bis der Client eine Nachricht geschickt hat.
Beide Probleme kannst du durch Threads lösen:
- Es gibt einen eigenen Thread, in dem auf Anmeldungen von Clients gewartet wird (also die Methode "accept()" aufgerufen wird).
- Jedesmal, wenn sich ein Client anmeldet, wird ein neuer Thread gestartet, der auf Nachrichten des Clients wartet (also "readLine()" aufruft).
(Das zweite Problem kann man auch mit den Klassen aus "java.nio" lösen - wenn du aber nicht zu viele Clients hast, tut ein eigener Thread pro Client nicht weh.)


----------



## Turing0001 (23. Mrz 2021)

kneitzel hat gesagt.:


> Klar - da habe ich nicht gut genug hingeschaut. Das Problem ist, dass der Client einen ObjectInputStream erzeugt:
> 
> ```
> ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
> ...


Hallo Kneitel,

das war es! Vielen, vielen Dank!!!!  Die Problematik war mir nicht recht bewusst, aber Du hast natürlich absolut recht!


----------



## Turing0001 (23. Mrz 2021)

fhoffmann hat gesagt.:


> @Turing0001 : Wenn das mit einem Client nun klappt, solltest du den Server danach so umschreiben, dass sich auch mehr als ein Client anmelden kann. Und es sollte möglich sein, dass ein Client mehr als eine Nachricht schickt (ohne sich neu anzumelden).
> Dabei hast du zwei Probleme:
> - die Methode "accept()" blockiert, bis sich ein Client angemeldet hat.
> - die Methode "readLine()" blockiert, bis der Client eine Nachricht geschickt hat.
> ...


Hallo fhoffmann,

vielen Dank für die Nachricht. Ich habe vor vielen Jahren mal ein einfaches Chatprogramm geschrieben, bei dem sich beliebige Clients bei einem Server anmelden  und Nachrichten senden konnten, die dann entweder an alle Teilnehmer oder nur bestimmte weitergeleitet wurden.
Ich hatte das damals so gelöst, dass bei jeder Anmeldung ein neuer Thread auf einem anonymen Port erzeugt wird für eine permanente Kommunikation mit dem Client. Die entsprechenden PrintWriter-Objekte hatte ich in einer ArrayList gespeichert, sodass beim Eintreffen einer neuen Nachricht einfach nur die ArrayList mit einen Iterator durchgelaufen werden musste um die Nachricht an alle weiterzuleiten. Hat prima funktioniert. Ist aber schon etwa 15 Jahre her, seitdem habe ich nichts mehr mit Java gemacht und bin daher ziemlich eingerostet. Ich versuche gerade mich wieder in die Materie reinzuwursteln, es kommt alles allmählich wieder, aber der Reboot dauert ein wenig. Aber ich fange an, dieses Forum zu mögen. Ich mag den respektvollen Umgang miteinander, bei anderen Foren wird man oft zuerst einaml beleidigt bevor man eine vernünftige Antwort bekommt. Wir werden wohl in nächster Zeiz noch häufiger kommunizieren, ich freue mich schon darauf.Vielen Dank nochmals für die Hilfe.


----------



## Turing0001 (7. Aug 2021)

Hallo Ihr Javaner,

jetzt muss ich das Thema doch nochmal aufgreifen. Das Programm funktioniert wunderbar innerhalb meines lokalen Netzwerkes. Jetzt experimentiere ich gerade mit meiner WAN-Ip. Hier habe ich wieder dasselbe Problem, dass der Server mir zwar die Meldung ausgibt "Bin hier", aber der SQL-String nicht ankommt. Auf meinem zweiten Rechner habe ich für Port 4243 natürlich in meinem Router eine Portweiterleitung eingerichtet, welche auch funktioniert, wie ich bereits mit anderen Programmen getestet habe (einfaches Chat-Programm). Was übersehe ich hier? Oder isteckt da ein prinzipieller Fehler dahinter? Vielen Dank schon vorab wieder für eure Mühen.


----------



## Jw456 (7. Aug 2021)

Hallo die Portweiterleitung brauchst du für den Recner der der Server ist.


----------



## Turing0001 (7. Aug 2021)

Jw456 hat gesagt.:


> Hallo die Portweiterleitung brauchst du für den Recner der der Server ist.


Ja, natürlich, das habe ich ja auch gemacht, sonst würde das Chat-Programm ja auch nicht funktionieren.


----------



## Jw456 (7. Aug 2021)

PS der Router kann nur eine weiterleitung für einen Port zu eine IP machen.
ich würde auch nicht loclhost beim client benutzen sondern die IP Adresse der Netzwerkkarte die der rechner im Lan hatt.
auf diese adresse schickt der Router die antwort vom server.


----------



## Turing0001 (7. Aug 2021)

Ja, das habe ich auch gemacht, das"localhost" ist von einer früheren Version, meistens verwende ich die IP-Adresse. Wie gesagt, innerhalb meines lokalen Netzwerks aus 3 Rechnern funktioniert ja auch alles wunderbar. Aber sowie ich über die WAN-IP versuche Kontakt aufzunehmen, kommt der String nicht an und sowohl der Client als auch der Server liefern mir nach einigen Sekunden eine Fehlermeldung:
Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat


----------



## Jw456 (7. Aug 2021)

Da scheint mir was mit dem Routing nicht zu stimmen.

Hast du es mal echt von außen versucht. Also von einen anderen Internetanschluss.

Du hast nur den Port im Router freigegeben mehr nicht oder?


----------



## Jw456 (7. Aug 2021)

WAN-IP was ist das die die du in netz hast?


----------



## Turing0001 (7. Aug 2021)

Nein, von außen habe ich es noch nicht versucht, aber das Chat-Programm funktioniert, daher weiß ich das die Portweiterleitung funktionieren muss. Einige meiner Bekannten haben den Chat-Client bei sich installiert und die Kommunikation verlief reibungslos.


----------



## Turing0001 (7. Aug 2021)

Ja, das ist meine Netz-IP


----------



## Jw456 (7. Aug 2021)

Turing0001 hat gesagt.:


> Nein, von außen habe ich es noch nicht versucht, aber das Chat-Programm funktioniert, daher weiß ich das die Portweiterleitung funktionieren muss. Einige meiner Bekannten haben den Chat-Client bei sich installiert und die Kommunikation verlief reibungslos.


dann sind es ja auch echte  wan verbindungen .



Der Client schickt es an die Wan-IP durch die Port Weiterleitung im Router kommt es auf den Server Rechner an. Der schickt die Antwort auf seine IP im Lokalen Netz.
Dein Client wartet auf der Wan IP auf seine Antwort.


----------



## Turing0001 (7. Aug 2021)

Hallo Jw456,

ich glaube ich verstehe was Du meinst. Aber wie kann ich das Problem beheben? Ich stehe da gerade auf dem Schlauch. Was aber merkwürdig ist: Ich hatte ein Testprogramm geschrieben, welches mir von einem Server ein serialisiertes Objekt des Typs Punkt (eigene Testklasse) zu meinem Client zusendet. Die Kommunikation läuft ebenfalls über  die WAN-IP und funktioniert einwandfrei, der Code ist nahezu identisch, die Daten kommen beim Client an, werden zurückgecastet und korrekt angezeigt. Daher meine Verwirrung.


----------



## kneitzel (7. Aug 2021)

Turing0001 hat gesagt.:


> Ja, das habe ich auch gemacht, das"localhost" ist von einer früheren Version, meistens verwende ich die IP-Adresse. Wie gesagt, innerhalb meines lokalen Netzwerks aus 3 Rechnern funktioniert ja auch alles wunderbar. Aber sowie ich über die WAN-IP versuche Kontakt aufzunehmen, kommt der String nicht an und sowohl der Client als auch der Server liefern mir nach einigen Sekunden eine Fehlermeldung:
> Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat


Das müsstest Du noch einmal etwas erläutern. Was ist das genaue Verhalten?
- Du lässt den Server Laufen
-> Verbindungen lokal funktionieren
-> Verbindungen von Bekannten auf die WAN IP funktionieren?
-> Verbindungen von dir selbst auf die WAN IP funktionieren nicht?



Jw456 hat gesagt.:


> Der Client schickt es an die Wan-IP durch die Port Weiterleitung im Router kommt es auf den Server Rechner an. Der schickt die Antwort auf seine IP im Lokalen Netz.
> Dein Client wartet auf der Wan IP auf seine Antwort.


Nein, das stimmt so nicht. Der Router ist nicht nur ein einfacher Router(Der Pakete von a nach b weiter leitet) sondern er schreibt die Adressen auch um (Network Address Translation - NAT). Daher gehen die Pakete vom Server auch über den Router an den Client zurück.



Turing0001 hat gesagt.:


> ich glaube ich verstehe was Du meinst. Aber wie kann ich das Problem beheben? Ich stehe da gerade auf dem Schlauch. Was aber merkwürdig ist: Ich hatte ein Testprogramm geschrieben, welches mir von einem Server ein serialisiertes Objekt des Typs Punkt (eigene Testklasse) zu meinem Client zusendet. Die Kommunikation läuft ebenfalls über  die WAN-IP und funktioniert einwandfrei, der Code ist nahezu identisch, die Daten kommen beim Client an, werden zurückgecastet und korrekt angezeigt. Daher meine Verwirrung.


Du hast diesbezüglich kein Problem und musst daher auch nichts in dem Bereich beheben.


----------



## Jw456 (7. Aug 2021)

Wenn du im Client die lokale IP benutzt müsste es gehen auch von außen von einen zweite Internet Anschuss. 
Wenn der Port für den Server offen ist.



Du willst es ja mit nur einen Internet Anschluss simulieren.
Der Server Rechner müsste eine Bridges haben die eine Port (4243) Weiterleitung zur Wan-IP macht.


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Das müsstest Du noch einmal etwas erläutern. Was ist das genaue Verhalten?
> - Du lässt den Server Laufen
> -> Verbindungen lokal funktionieren
> -> Verbindungen von Bekannten auf die WAN IP funktionieren?
> ...


er will es local bei sich simmuliren


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

schön von Dir zu hören.
Server läuft, Client wird gestartet. Bei clientseitigem Zugriff via lokaler Server-IP-Adresse ist alles klar, die Daten werden aus der Datenbank vom Server ermittelt, an den Client zurückgeschickt und korrekt dargestellt. Ändere ich aber im Client die lokale Serveradresse von meinem zweiten Rechner (der mitder Portweiterleitung) in die WAN-IP um, erscheint nach einigen Sekunden obige Fehlermeldung. Bei meinem Chat-Programm tritt der Fehler nicht auf. Da liegt der Server auch wieder auf meinem zweiten Rechner und sowohl ich als auch meine Bekannten können problemlos über die WAN-IP kommunizieren.


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Nein, das stimmt so nicht. Der Router ist nicht nur ein einfacher Router(Der Pakete von a nach b weiter leitet) sondern er schreibt die Adressen auch um (Network Address Translation - NAT). Daher gehen die Pakete vom Server auch über den Router an den Client zurück.


er hat im cleint die Wan-IP  angegeben.
wenn von der Wan_IP was kommt wo soll der Router es hinn schiken -> port weiterleitung zum server


----------



## Turing0001 (7. Aug 2021)

Korrektur: Habe gerade nochmal das Chat-Programm getestet und bekomme dort nun plötzlich denselben Fehler. Merkwürdig!
Scheint doch eher ein Problem beim Router zu sein. Ich werde das nachher nochmal checken.


----------



## kneitzel (7. Aug 2021)

Turing0001 hat gesagt.:


> Server läuft, Client wird gestartet. Bei clientseitigem Zugriff via lokaler Server-IP-Adresse ist alles klar, die Daten werden aus der Datenbank vom Server ermittelt, an den Client zurückgeschickt und korrekt dargestellt. Ändere ich aber im Client die lokale Serveradresse von meinem zweiten Rechner (der mitder Portweiterleitung) in die WAN-IP um, erscheint nach einigen Sekunden obige Fehlermeldung. Bei meinem Chat-Programm tritt der Fehler nicht auf. Da liegt der Server auch wieder auf meinem zweiten Rechner und sowohl ich als auch meine Bekannten können problemlos über die WAN-IP kommunizieren.


Ok, also der Chat Server funktioniert auch per WAN. der neue Server funktioniert aber nicht. Die Information, dass Deine Freunde sich verbinden konnten, bezieht sich nur auf den Chat Server.

Interessant ist, dass die erste Verbindungsanfrage zu funktioniert scheint. Damit dürften typische Probleme wie Firewall und Co nicht die Ursache sein (Zumindest nicht in den üblichen Einstellungen).

Da es lokal funktioniert, dürfte der Code prinzipiell korrekt sein. Kannst Du aber vorsichtshalber doch den jeweiligen Code für die Verbindungen auf Server und Client Seite zeigen?



Jw456 hat gesagt.:


> er hat im cleint die Wan-IP  angegeben.
> wenn von der Wan_IP was kommt wo soll der Router es hinn schiken -> port weiterleitung zum server


Der Client schickt es zum Router, der Router macht eine NAT und schickt das Paket dann an den Server. Der Server antwortet dem Router (Denn in dem Paket, das der Server bekommen hat, steht ja eine Adresse vom Router), dieser empfängt das Paket, führt wieder eine NAT durch und schickt das Paket an den Client.


----------



## Turing0001 (7. Aug 2021)

Habe es gerade nochmal mit einem anderen Programm getestet. Solange ich nur Daten von Server anfordere funktioniert es. Wenn ich aber Daten vom Client an den Server sende und auf Rückantwort warte, gibt es plötzlich Probleme, die es vorher nicht gab. Ich poste mal nochmal den vollständigen Code von meinem Client und dem Server. Ich bitte das Chaos schon im Voraus zu entschuldigen


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Der Client schickt es zum Router, der Router macht eine NAT und schickt das Paket dann an den Server. Der Server antwortet dem Router (Denn in dem Paket, das der Server bekommen hat, steht ja eine Adresse vom Router), dieser empfängt das Paket, führt wieder eine NAT durch und schickt das Paket an den Client.


ja aber der ceint hat keine Locale ip sondern die Wan-IP was falsch ist.

seine Freunde wo es geht benutzen bestimmt eine version mit localer Cliint IP, und klar da geht es auch von ausen mit offnen port am server.


----------



## Turing0001 (7. Aug 2021)

Hier noch mal der Client (die IP-Adresse ist hier natürlich die lokale im Netz, mit der es funktioniert)


```
package mypackage;

import java.io.*;
import java.net.*;
import java.util.ArrayList;




public class ClientDB {
    
     private InetSocketAddress address;
     PrintWriter writer;
    
    public void los()
    {
        
        try
        {
        
            
         address = new InetSocketAddress("192.168.2.101",4243);
          Socket s = new Socket();
          s.connect(address, 1000); // Verbinde Dich mit dem Server, maximale Wartezeit: 3 Sekunden
          
          // Erstellen eines Printwriters, da hier Texte und keine binären Rohdaten gesendet werden:
          
          writer = new PrintWriter(s.getOutputStream());
          writer.println("select * from leute"); // SQL-Befehl an Server absenden
          try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
          writer.flush();
          
          // Empfangen werden vom Server aber binäre Rohdaten, also wird ObjectInputStream benötigt:
          
          ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
          
    
          // Ausgabe der ArrayList mit dem ResultSet der Datenbank in einem String
          // nachdem die Rohdaten zunächst wieder in eine ArrayList von Typ String
          // zurückverwandelt wurden
          
          System.out.println("Ausgabe der Daten:");
          ArrayList <String> al = (ArrayList<String>)(ois.readObject());
          System.out.println(al.toString());
        
        
//          ois.close();
//          s.close();
//          writer.close();
        }
          
       catch(IOException ex) {ex.printStackTrace();}
       catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // Client starten:
        
        ClientDB client1 = new ClientDB();
        client1.los();
    }
}
```


Und hier noch der Server:



```
package mypackage;

import java.io.*;
import java.net.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import javax.swing.JOptionPane;



public class ServerDB {
    
    Connection conn;//Schnittstelle um Verbindung zur DB herzustellen
    Statement stmt;
    ResultSet rSet;
    BufferedReader reader;
    

    public void los()
    {
        try
        {
            ServerSocket servsock = new ServerSocket(4243); // Verbindungsschnittstelle auf Port 4243 erstellen
            while(true)
            {
                System.out.println("Hallo hier ist der Server!");
                Socket sock = servsock.accept(); // Warten auf "Anruf" von einem Client. accept() blockiert bis ein Client "anruft"
                
                // Empfange einen String (= SQL Befehl) vom Client:
                
                InputStreamReader isReader = new InputStreamReader (sock.getInputStream());
                reader = new BufferedReader(isReader);
                String nachricht = null;
                System.out.println("Bin hier");
                

        
                nachricht = reader.readLine(); // Lesen des SQL Befehls
            
                System.out.println("Empfangene Nachricht: " + nachricht);
                //JOptionPane.showMessageDialog(null, "Nachricht: " + nachricht);
                System.out.println("Empfangene Nachricht nochmal: " + nachricht);
                // Ab hier wieder wie gehabt Verbindung zur Datenbank:
                
               DriverManager.setLogWriter(new PrintWriter(System.out));
               Class.forName("org.sqlite.JDBC");
               System.out.println("Treiber geladen");
               String url = "jdbc:sqlite::resource:"+ "MyDB.db";
               conn = DriverManager.getConnection(url,"",""); // Verbindungsobjekt erstellen
                  System.out.println("Verbindung steht" );
                  stmt = conn.createStatement();
                  rSet = stmt.executeQuery(nachricht); // Schicke den SQL-Befehl an die Datenbank und nimm das Ergebnis entgegen
                  ResultSetMetaData md = rSet.getMetaData(); // Ermittele Meta-Daten des ResultSets
                  int columns = md.getColumnCount();
                  System.out.println("Anzahl der Spalten: " + columns + " \n");
                  
                  ArrayList <String> tabledat = new ArrayList<String>();
                  
                  while(rSet.next()) { // Solange noch Ergebnisdatensätze da sind...
                
                for(int i=1; i<=columns; ++i) {
                     // Durchlaufe alle Spalten der aktuellen Zeile des ResultSets
                    tabledat.add(rSet.getString(i)); // Aktuellen Eintrag des ResultSets in ArrayList speichern
                    
                }
            }
                  
                  
                  
                  // Ergebnis der Datenbankabfrage wir wieder als binärer Datenstrom zum
                  // Client zurückgeschickt
                  
                  OutputStream os = sock.getOutputStream();
                  ObjectOutputStream oos = new ObjectOutputStream(os);
                  
               oos.writeObject(tabledat);
               oos.flush();
              
               oos.close();
               servsock.close();
            }
            
        }
        
        catch (IOException ex)
        {ex.printStackTrace();}
        catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {           
            CloseDB(stmt,conn); // Datenbankverbindung schließen
        }   
    
    
  
}
    
    public void CloseDB(Statement stmt, Connection conn )
    {
        try {
            stmt.close();
            conn.close();
        } catch(Exception e) {
            //
        }
    }
    public static void main(String[] args) {
        // Starte den Server:
        
        ServerDB serv = new ServerDB();
        serv.los();
    }
}
```

Vielen Dank für eure Hilfe!


----------



## Jw456 (7. Aug 2021)

wenn du die locale IP benutzt 
address = new InetSocketAddress("192.168.2.101",4243);

könnte es doch an der WireFall ligen.

ich habe dich so verstanden das du im Client die öffentliche Adresse "Wan-IP" eingetragen hast .


----------



## Turing0001 (7. Aug 2021)

Ja, habe ich auch. Aber mit den oben erwähnten Testprogrammen funktioniert es ja, zumindest solange die Kommunikation (Senden von Daten) nur von Server zu Client läuft. Sowie die Kommunikation bidirektional wird, gibt es die erwähnten Probleme.


----------



## Jw456 (7. Aug 2021)

Turing0001 hat gesagt.:


> Hier noch mal der Client (die IP-Adresse ist hier natürlich die lokale im Netz, mit der es funktioniert)






Turing0001 hat gesagt.:


> Ja, habe ich auch. Aber mit den oben erwähnten Testprogrammen funktioniert es ja, zumindest solange die Kommunikation (Senden von Daten) nur von Server zu Client läuft. Sowie die Kommunikation bidirektional wird, gibt es die erwähnten Probleme.



also geht es mit localer IP  auch nicht bidirektional?


----------



## kneitzel (7. Aug 2021)

Jw456 hat gesagt.:


> ja aber der ceint hat keine Locale ip sondern die Wan-IP was falsch ist.
> 
> seine Freunde wo es geht benutzen bestimmt eine version mit localer Cliint IP, und klar da geht es auch von ausen mit offnen port am server.


Bitte: Beschäftige Dich mit den Grundlagen ehe Du Dich zu irgendwelchen Aussagen hinreissen lässt.

@Turing0001 So leid es mir tut, aber mein Ratschlag wäre, hier die Aussagen von @Jw456 erst einmal zu ignorieren. Die können Dich nicht weiter bringen. Die TCP/IP Verbindung funktioniert ja auch, sonst gäbe es keine Verbindung und Dein "Solange ich nur Daten von Server anfordere funktioniert es." zeigt es ja auch.

Ich hoffe, dass ich so in 30 Minuten dazu komme, mir den Code im Detail anzusehen.


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Bitte: Beschäftige Dich mit den Grundlagen ehe Du Dich zu irgendwelchen Aussagen hinreissen lässt.


ich glaube du liest manchmal auch nicht richtig


----------



## Turing0001 (7. Aug 2021)

Mit lokaler IP-Adresse funktioniert imlokalen Netz alles, auch das Chat-Programm, welches vor einigen Monaten auch noch mit der WAN-IP gelaufen ist, daher bin ich ja so verwirrt. Ich werde aber auch nochmal den Router checken. Meine WAN-IP hatte sich seit damals nach einem Reset verändert, vielleicht hat es da im Router etwas durcheinander gewürfelt, mal sehen.


----------



## kneitzel (7. Aug 2021)

Turing0001 hat gesagt.:


> Solange ich nur Daten von Server anfordere funktioniert es. Wenn ich aber Daten vom Client an den Server sende und auf Rückantwort warte, gibt es plötzlich Probleme, die es vorher nicht gab.


Also wenn ich mir die ClientDB und ServerDB Klassen ansehe, dann sieht es erst einmal so aus, als ob du da doch nur den Part "Daten von Server anfordern" hast. Sprich: Das, was Du da gezeigt hast, funktioniert. Habe ich das richtig verstanden?

Die Frage wäre also: Welcher Code funktioniert nicht. Ich habe da evtl. noch nicht alles so 100% verstanden.

Generell gefällt mir die Struktur da aber auch noch nicht so richtig. Ich würde da zu ein paar Änderungen raten, die ich erst einmal kurz skizzieren möchte:
- Der Server hat mehrere Threads: Der erste Thread startet den ServerSocket und wartet dann auf neue Verbindungen. Für jede neue Verbindung wird dann ein eigener Thread gestartet.
- Die Verbindung ist generell Bidirektional. Server / Client warten generell auf Nachrichten um diese dann zu bearbeiten.

Wie so ein Rahmen aussehen könnte, werde ich Dir nachher einmal anhand des umgestellten Codes einmal zeigen und dann an Hand des konkreten Codes es etwas ausführlicher erläutern.

Dabei noch ein paar Punkte, die Du im Hinterkopf behalten solltest: 
- Du erlabst Zugriffe von außen - das ist prinzipiell kritisch, denn die Ports werden ständig gescannt und es wird massiv Verbindungen geben. Das sehe ich zumindest bei den Ports, auf denen ich einen Tomcat und einen Terminalserver nach außen laufen lasse. Und bei sowas rate ich zu zusätzlichen Maßnahmen (ich erlaube z.B. nur Verbindungen aus D und F).
- Das ist dann eine Multi Threaded Variante mit Sockets - das ist eigentlich veraltet. Aktuell wäre sowas asynchron mit den Channeln aus java.nio umzusetzen. Aber für einzelne Anfragen ist das ok.


----------



## kneitzel (7. Aug 2021)

Jw456 hat gesagt.:


> ich glaube du liest manchmal auch nicht richtig


Was ist an deinen wirren Aussagen etwas "richtig" zu lesen? Ich habe den Ablauf grob skizziert. Das kann man auch noch weiter aufdröseln, damit Du den TCP/IP Verlauf verstehst. Man könnte auch per wireguard Pakete scannen und dann schauen: Was geht denn von Client an Router und dann von Router an Server (und umgekehrt).

Du könntest aber auch einfach alles nachlesen - das sind keine Geheimnisse sondern es ist alles offen und gut dokumentiert zu finden. Und darauf werde ich im Detail jetzt hier nicht weiter eingehen, denn für den TE ist dies nicht relevant.


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,
das obige Programm funktioniert nur im lokalen Netz. Gebe ich im Client aber die WAN-IP statt der lokalen IP des Servers ein, kommt nach einigen Sekunden die oben erwähnte Fehlermeldung


----------



## Jw456 (7. Aug 2021)

stimmt deine Wan IP? Prüfe es .

du hast wohl eine feste Wan IP?


----------



## Jw456 (7. Aug 2021)

Turing0001 hat gesagt.:


> Hallo Kneitzel,
> das obige Programm funktioniert nur im lokalen Netz. Gebe ich im Client aber die WAN-IP statt der lokalen IP des Servers ein, kommt nach einigen Sekunden die oben erwähnte Fehlermeldung




bitte einen Kumpel sich von ausen sich auf deinen server zu verbinden. zum testen.


----------



## Turing0001 (7. Aug 2021)

Das meinte ich ja. Mit der lokalen IP des Servers, etwa 192.168.2.101 geht es, aber mit der WAN-IP nicht (mehr). Porteinstellungen stimmen noch, habe ich gerade überprüft.


----------



## Turing0001 (7. Aug 2021)

Meine WAN-IP möchte ich natürlich nicht öffentlich posten, zusammen mit dem weitergeleiteten Port wäre mir das etwas zu riskant...


----------



## Jw456 (7. Aug 2021)

Turing0001 hat gesagt.:


> Meine WAN-IP möchte ich natürlich nicht öffentlich posten, zusammen mit dem weitergeleiteten Port wäre mir das etwas zu riskant...


musst du auch nicht du solltest testen  ob die öffentliche ip auch auch die ist die du beim Client eingetragen hast.
und ob du überhaupt eine IP V4 adresse als öffentliche hast.








						Wie ist meine IP-Adresse?
					

Auf wieistmeineip.de findest Du schnell und einfach heraus, mit welcher IP-Adresse Du online bist. Außerdem: Ausführlicher DSL-Speedtest mit vielen Statistiken zu Deinem DSL-Anschluss.




					www.wieistmeineip.de


----------



## kneitzel (7. Aug 2021)

Turing0001 hat gesagt.:


> Hallo Kneitzel,
> das obige Programm funktioniert nur im lokalen Netz. Gebe ich im Client aber die WAN-IP statt der lokalen IP des Servers ein, kommt nach einigen Sekunden die oben erwähnte Fehlermeldung


Die Meldungen kommen aber beim Server und beim Client? Und nicht nur beim Client? (So hast Du es ja geschrieben gehabt: "sowohl der Client als auch der Server liefern mir nach einigen Sekunden eine Fehlermeldung:"

Kannst Du die genaue Ausgabe sowohl vom Client als auch vom Server einmal bereit stellen? Also incl. aller Ausgaben, die du so indem Code gemacht hast.


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

hier die Fehlermeldung des Clients:

java.net.SocketException: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat
    at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:325)
    at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:981)
    at java.base/java.ibjectInputStream$PeekInputStream.read(ObjectInputStream.java:2914)
    at java.base/java.ibjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2930)
    at java.base/java.ibjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3427)
    at java.base/java.ibjectInputStream.readStreamHeader(ObjectInputStream.java:962)
    at java.base/java.ibjectInputStream.<init>(ObjectInputStream.java:405)
    at mypackage.ClientDB.los(ClientDB.java:41)
    at mypackage.ClientDB.main(ClientDB.java:73)


und hier die des Servers:

java.net.SocketException: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat
    at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:325)
    at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:981)
    at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
    at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
    at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
    at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
    at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
    at mypackage.ServerDB.los(ServerDB.java:48)
    at mypackage.ServerDB.main(ServerDB.java:132)

Vielen Dank für Deine Mühe


----------



## kneitzel (7. Aug 2021)

Das Problem passt nicht ganz zu dem Code. Das Problem kommt daher, dass der Server derzeit noch auf eine Textzeile vom Client wartet. Dieser Request läuft dann irgendwann in einen Timeout.

Der Client selbst öffnen einen ObjectInputStream und will bei der Initialisierung ein paar erste Bytes lesen. Diese kommen aber leider nicht (da der Server ja selbst noch wartet).

Das ist aber nicht das Verhalten des Codes, den Du gepostet hast 

Generell ist es so, dass man sich auf eine "Kommunikationsart" festlegen sollte. Also entweder mann schickt nur Text oder man nutzt Object Streams oder man macht irgend was eigenes ...

Dann öffne ich gerne die Streams direkt, damit diese dann verwendbar sind. Da di Kommunikation blockierend ist, bekommt jeder Socket einen eigenen Thread. Wenn etwas kommt (beim Server), dann wird darauf reagiert.

Das habe ich mal kurz skizziert in folgendem Code. Das ist natürlich nicht komplett, denn der Server sollte alle seine Clients kennen und so. Aber das ignorieren wir mal einfach. Und da Du komplexe Dinge gerne per Object Stream versendest, basiert alles auf ObjectStream (Ein String ist ja auch ein Objekt - kann also versendet werden!)

Eine Nachricht, die empfangen wird auf Server Seite ist dann eine ReceivedMessage und bekommt - ähnlich wie man das von Events in Swing und Co kennt, auch den Sender mit:

```
package mypackage.server;

public class ReceivedMessage {
    private ClientSocketHandler handler;
    private Object message;

    public ClientSocketHandler getHandler() {
        return handler;
    }

    public Object getMessage() {
        return message;
    }

    public ReceivedMessage() {
    }

    public ReceivedMessage(ClientSocketHandler handler, Object message) {
        this.handler = handler;
        this.message = message;
    }
}
```

Einen Client Socket will gehandhabt werden. Das ist dann einfach mal folgende Klasse geworden:

```
package mypackage.server;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.function.Consumer;

public class ClientSocketHandler {

    private final Socket clientSocket;
    private final ObjectInputStream in;
    private final ObjectOutputStream out;

    private Consumer<ReceivedMessage> objectHandler;

    private volatile boolean running;

    public ClientSocketHandler(final Socket clientSocket) throws IOException {
        this.clientSocket = clientSocket;
        in = new ObjectInputStream(clientSocket.getInputStream());
        out = new ObjectOutputStream(clientSocket.getOutputStream());
        running = true;
    }

    public void start() {
        new Thread(this::receiveMessages).start();
    }

    public void sendMessage(Object obj) throws IOException {
        out.writeObject(obj);
    }

    public void receiveMessages() {
        while (running) {
            try {
                Object obj = in.readObject();
                if (objectHandler != null) objectHandler.accept(new ReceivedMessage(this, obj));
            } catch (EOFException eofe) {
              System.out.println("Connection closed ...");
              running = false;
            } catch (IOException ioe) {
                ioe.printStackTrace();
                System.out.println("Could not read from socket, closing!");
                running = false;
            } catch (ClassNotFoundException cnfe) {
                System.out.println("Message discarded, class not found: " + cnfe.getMessage());
            }
        }
        safeClose(in);
        safeClose(out);
        safeClose(clientSocket);
    }

    private void safeClose(AutoCloseable closeable) {
        if (closeable == null) return;
        try {
            closeable.close();
        } catch (Exception ex) {}
    }

    public void setObjectHandler(Consumer<ReceivedMessage> objectHandler) {
        this.objectHandler = objectHandler;
    }
}
```

Ist schnell umschrieben: Bekommt einen Socket, öffnet darauf die Object Streams. Man kann eine Routine hinterlegen, die Nachrichten dann verarbeitet. Und man kann das natürlich noch starten.

Ein einfacher Server sieht dann so aus:

```
package mypackage.server;

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

public class Server {
    private final int port;
    private boolean running;
    private ServerSocket serverSocket;

    public Server (final int port) {
        this.port = port;
    }

    public void open() {
        if (running) return;

        new Thread(this::acceptNewConnections).start();
    }

    private void handleMessage(ReceivedMessage msg) {
        System.out.println(msg.getMessage());
        try {
            msg.getHandler().sendMessage("Empfangen: " + msg.getMessage());
        } catch (IOException ex) {
            System.out.println("Unable to send message back!");
            ex.printStackTrace();
        }
    }

    private void acceptNewConnections() {
        try {
            serverSocket = new ServerSocket(port);
            System.out.println("Waiting on Port " + port);
            running = true;
        } catch (IOException ex) {
            System.out.println("Unable to open port!");
            ex.printStackTrace();
        }

        while (running) {
            try {
                Socket client = serverSocket.accept();
                System.out.println("Client connected ...");
                ClientSocketHandler handler = new ClientSocketHandler(client);
                handler.setObjectHandler(this::handleMessage);
                handler.start();
                // die einzelnen Handler werden in der Regel auch noch verwaltet!
            } catch (IOException ex) {
                System.out.println("Exception when accepting a new Client.");
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Server server = new Server(4243);
        server.open();
    }
}
```
Also in erster Linie ein Thread, der auf neue Clients wartet, die Verbindungen annimmt und dann entsprechende Handler erstellt.
Der ObjectHandler (fällt mir gerade auf, dass das blöd ist. Sollte besser NewMessageHandler heissen) ist hier einfach minimal aufgebaut. Die nachricht wird ausgegeben und ein String zurück gesendet.

Mal einfach eine angepasste Klasse, die mit dem Server umgehen kann:

```
package mypackage.client;

import java.io.*;
import java.net.*;
import java.util.ArrayList;

public class ClientDB {

    private InetSocketAddress address;
    ObjectOutputStream out;

    public void los()
    {
        try
        {
            address = new InetSocketAddress("127.0.0.1",4243);
            Socket s = new Socket();
            s.connect(address, 1000); // Verbinde Dich mit dem Server, maximale Wartezeit: 3 Sekunden
            out = new ObjectOutputStream(s.getOutputStream());
            out.writeObject("select * from leute"); // SQL-Befehl an Server absenden
            out.flush();

            // Empfangen werden vom Server aber binäre Rohdaten, also wird ObjectInputStream benötigt:

            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

            // Ausgabe der ArrayList mit dem ResultSet der Datenbank in einem String
            // nachdem die Rohdaten zunächst wieder in eine ArrayList von Typ String
            // zurückverwandelt wurden

            System.out.println("Ausgabe der Daten:");
            Object msg = ois.readObject();
            System.out.println(msg);


//          ois.close();
//          s.close();
//          writer.close();
        }

        catch(IOException ex) {ex.printStackTrace();}
        catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // Client starten:

        ClientDB client1 = new ClientDB();
        client1.los();
    }
}
```

Am Client habe ich kaum was gemacht - da könnte man dann noch einiges optimieren.

Was man da z.B. machen könnte:
- Man erstellt einfach Nachrichten Klassen. Also von mir aus sowas wie eine SQLQuery Klasse.
- Der NewMessageHandler prüft dann: Ist die msg vom Typ SQLQuery? -> SQL Query ausführen.

So kann man dann viele Nachrichten-Klassen bauen, die dann behandelt werden. 

Man könnte dazu sogar etwas bauen wie eine Map, die als Key den Klassennamen hat und als Value dann ein Consumer<> oder so.

Also ganz klar: Das war nur ein Anfang und man kann einiges mehr ausbauen!


----------



## Jw456 (7. Aug 2021)

lasse mal das weg dein server wird auch gleich geschlossen auch wenn du nur local bist.

// servsock.close();


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Das Problem passt nicht ganz zu dem Code. Das Problem kommt daher, dass der Server derzeit noch auf eine Textzeile vom Client wartet. Dieser Request läuft dann irgendwann in einen Timeout.
> 
> Der Client selbst öffnen einen ObjectInputStream und will bei der Initialisierung ein paar erste Bytes lesen. Diese kommen aber leider nicht (da der Server ja selbst noch wartet).
> 
> ...


alles richtig. 
Du erklärst aber nicht warum es lokal geht aber mit öffentlicher IP nicht.


Ich habe seinen Code mal mit öffentlicher und lokaler IP getestet ging beides.
Server und Client auf derselben Maschine, nur der Server blendet sich nach einer Verbindung.


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

danke für Deine Mühe, ich werde es mal in Ruhe anschauen. Gerne hätte ich aber gewusst, warum mein Code nicht läuft. Vielleicht hier noch mal zum Vergleich mein Chatclient und mein Chatserver, welche nun via WAN-IP auch nicht mehr funktionierern, obwohl das Ganze mit mehreren Clients vor einigen Monaten beim Test einwandfrei mit einigen Bekannten funktionierte. Vielleicht hast Du die Tage ja mal Zeit es Dir anzuschauen. Hat den Vorteil dass Du den Code 1.1 übernehmen und direkt bei Dir testen kanst und ich wüsste, warum dieser Code plötzlich nicht mehr funktioniert:

Hier der Client:


```
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
 
public class EinfacherChatClientA {
     JTextArea eingehend;
    JTextField ausgehend;
    BufferedReader reader;
    PrintWriter writer;
    Socket sock;
 
public static void main(String[] args) {
    EinfacherChatClientA client = new EinfacherChatClientA();
    client.los(); // Chatclient starten
}
 
public void los() {
    JFrame frame = new JFrame ("Lächerlich einfacher Chat-Client");
    JPanel hauptPanel = new JPanel () ;
    eingehend = new JTextArea(15,20);
    eingehend.setLineWrap(true);
    eingehend.setWrapStyleWord(true);
    eingehend.setEditable(false);
    JScrollPane fScroller = new JScrollPane(eingehend);
    fScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    fScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    ausgehend = new JTextField(20);
    JButton sendenButton = new JButton ("Senden");
    sendenButton.addActionListener(new SendenButtonListener());
    hauptPanel.add(fScroller);
    hauptPanel.add(ausgehend);
    hauptPanel.add(sendenButton);
   
    netzwerkEinrichten(); // Verbindung zum Server herstellen
   
    Thread readerThread = new Thread(new EingehendReader()); // Thread erzeugen für dauerhafte Kommunikation mit Server
    readerThread.start();
   
    frame.getContentPane().add(BorderLayout.CENTER, hauptPanel);
    frame.setSize(400,500);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
 
private void netzwerkEinrichten() {
    try {
            sock = new Socket("192.180.2.101", 4243); // Verbindung zum Server auf Port 4243
            InputStreamReader streamReader = new InputStreamReader(sock.getInputStream()); // Eingabestrom vom Server holen (Input-Leitung)
            reader = new BufferedReader(streamReader);
            writer = new PrintWriter(sock.getOutputStream()); // Ausgabestrom zum Server holen (Output-Leitung)
            System.out.println("Netzwerkverbindung steht. Port des Servers:  " + sock.getPort() + " Serveradresse: " + sock.getInetAddress());
           
    } catch (IOException ex) {
      ex.printStackTrace();
    }
}
private class SendenButtonListener implements ActionListener {  // Text der verschickt werden soll lesen und absenden
    public void actionPerformed(ActionEvent ev) {
    try{
            writer.println(ausgehend.getText());
            writer.flush(); // Writer/Tastaturpuffer leeren.
 
        } catch(Exception ex) {
          ex.printStackTrace();
        }
        ausgehend.setText(""); // Eingabefeld löschen
        ausgehend.requestFocus();
        }
    }
   
    class EingehendReader implements Runnable // Permanent hören, ob eine Nachricht vom Server kommt
    {
        public void run()
        {
            String nachricht;
            try
            {
                while((nachricht=reader.readLine()) != null) // Liest vom Server bis null (=Ende der Nachricht) zurückgegeben wird
                {
                    System.out.println("Gelesen: " + nachricht); // Nachricht in TextArea anzeigen
                    eingehend.append(nachricht + "\n");
                }
               
            }
            catch(Exception ex){ex.printStackTrace();}
        }
   
    }
}
```


Hier nun noch der Server:



```
import java.io.*;
import java.net.*;
import java.util.*;
 
public class SehrEinfacherChatServer {
 
    ArrayList clientAusgabeStröme;
 //--------------------------------------------------------------------------------------
 
    public class ClientHandler implements Runnable { // Permanent auf neuen Client warten, also Thread benötigt
        BufferedReader reader;
        Socket sock;
       
        public ClientHandler (Socket clientSocket) { // Eingabestrom vom Client holen
            try {
                sock = clientSocket;
                InputStreamReader isReader = new InputStreamReader (sock.getInputStream());
                reader = new BufferedReader(isReader);
                PrintWriter writer = new PrintWriter(sock.getOutputStream());
                clientAusgabeStröme.add(writer); // Writerobjekt in ArrayList speichern, damit jederzeit Nachricht an Client gesendet werden kann

           
            } catch(Exception ex) {ex.printStackTrace();}
        } // Konstruktor schließen
       
        public void run() { // permanent auf Nachricht von einem Client warten
            String nachricht;
            try {
                while ((nachricht = reader.readLine()) !=null) {
                    System.out.println("gelesen: " + nachricht);
                    esAllenWeitersagen(nachricht); // Eingehende Nachricht eines Clients an alle anderen Clients weiterleiten
                } // Ende der while-Schleife
            } catch(Exception ex) {ex.printStackTrace();System.out.println("Fehler beim Lesen vom Client!");}
        } // run schließen
    } // innere Klasse schließen
   
    //-------------------------------------------------------------------------------------
   
    public static void main (String[] args) {
        new SehrEinfacherChatServer().los(); // Serverprogramm starten
    }
    // los() erzeugt ein Serversocket und wartet permanent auf Anfrage eines neuen Client
   
    public void los() {
        clientAusgabeStröme = new ArrayList();
       
        try {
            ServerSocket serverSock = new ServerSocket(4243);
            System.out.println("Hier ist der Chat-Server auf Port 4243!");
           
            while(true) { // Auf Anfrage von neuem Client warten...
                Socket clientSocket = serverSock.accept();//Erzeuge neuen Socket für Client der gerade angefragt hat
                InetAddress ip=clientSocket.getInetAddress();
                String adr=ip.getHostName();//oder getHostAddress()
                int portnr = clientSocket.getPort();//bzw. getLocalPort auf Serverseite
                System.out.println("Hostname und Port des Clients: " + adr + " " + portnr);
                //PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
                //clientAusgabeStröme.add(writer);
                Thread t = new Thread(new ClientHandler(clientSocket)); // Neuen Thread erzeugen für permanente Kommunikation mit diesem Client...
                t.start(); //...und diesen Thread starten
                System.out.println("Habe eine Verbindung");
            }
            // wenn wir hier angelangt sind, haben wir eine Verbindung
       
        }catch(Exception ex) {
         ex.printStackTrace();
        }
    }
   
    //--------------------------------------------------------
    // Eingegangene Nachricht eines Clients an alle anderen Clients weiterleiten.
    // Dazu alle Writer-Objekte in der ArrayList durchlaufen und für jedes die write() Funktion aufrufen:
   
    public void esAllenWeitersagen(String nachricht) {
       
        Iterator<PrintWriter> it = clientAusgabeStröme.iterator(); // Durchlauf mit einem Iterator ( ähnlichz zu for-each-Schleife)
        while(it.hasNext()) {
            try {
                PrintWriter writer = (PrintWriter) it.next();
                writer.println(nachricht);
                writer.flush();
            } catch(Exception ex) {
              ex.printStackTrace();
            }
        } // Ende der while-Schleife
    } // esAllenWeitersagen schließen
} // Klasse schließen
```

LG


----------



## kneitzel (7. Aug 2021)

Turing0001 hat gesagt.:


> Gerne hätte ich aber gewusst, warum mein Code nicht läuft.





Jw456 hat gesagt.:


> Du erklärst aber nicht warum es lokal geht aber mit öffentlicher IP nicht.



Ich habe meine Vermutung diesbezüglich doch geäußert:


> Das Problem passt nicht ganz zu dem Code.



Meine Vermutung ist, dass Du bei der Anpassung ggf. noch etwas mehr angepasst hast. Schickt der Client denn immer noch die Nachricht? Sprich: Bist Du wirklich sicher, dass bei den Tests von Dir dieser Code noch vorhanden war:

```
writer = new PrintWriter(s.getOutputStream());
          writer.println("select * from leute"); // SQL-Befehl an Server absenden
          try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
          writer.flush();
```

Die folgende Aussage passt diesbezüglich ja auch:


Turing0001 hat gesagt.:


> Aber mit den oben erwähnten Testprogrammen funktioniert es ja, zumindest solange die Kommunikation (Senden von Daten) nur von Server zu Client läuft. Sowie die Kommunikation bidirektional wird, gibt es die erwähnten Probleme.


==> Irgendwas ging und mit einer Anpassung kommt es dann zu den Problemen.

Wie gesagt: Viele Informationen, die im Thread gegeben wurden, passen nicht zusammen. Zusammen mit irgendwelchen wilden Vermutungen rund um TCP/IP ist es sehr schwer, ein genaues Bild zu bekommen - zumal ja während der Diskussion der Code bestimmt nicht unverändert bleibt


----------



## Jw456 (7. Aug 2021)

sorry falsche datei kommt gleich


----------



## Jw456 (7. Aug 2021)

```
public class ServerDB {

    Connection conn;//Schnittstelle um Verbindung zur DB herzustellen
    Statement stmt;
    ResultSet rSet;
    BufferedReader reader;


    public void los()
    {
        try
        {
            ServerSocket servsock = new ServerSocket(4243); // Verbindungsschnittstelle auf Port 4243 erstellen
            while(true)
            {
                System.out.println("Hallo hier ist der Server!");
                Socket sock = servsock.accept(); // Warten auf "Anruf" von einem Client. accept() blockiert bis ein Client "anruft"

                // Empfange einen String (= SQL Befehl) vom Client:

                InputStreamReader isReader = new InputStreamReader (sock.getInputStream());
                reader = new BufferedReader(isReader);
                String nachricht = null;
                System.out.println("Bin hier");



                nachricht = reader.readLine(); // Lesen des SQL Befehls

                System.out.println("Empfangene Nachricht: " + nachricht);
                //JOptionPane.showMessageDialog(null, "Nachricht: " + nachricht);
                System.out.println("Empfangene Nachricht nochmal: " + nachricht);
                // Ab hier wieder wie gehabt Verbindung zur Datenbank:

               /* DriverManager.setLogWriter(new PrintWriter(System.out));
                Class.forName("org.sqlite.JDBC");
                System.out.println("Treiber geladen");
                String url = "jdbc:sqlite::resource:"+ "MyDB.db";
                conn = DriverManager.getConnection(url,"",""); // Verbindungsobjekt erstellen
                System.out.println("Verbindung steht" );
                stmt = conn.createStatement();
                rSet = stmt.executeQuery(nachricht); // Schicke den SQL-Befehl an die Datenbank und nimm das Ergebnis entgegen
                ResultSetMetaData md = rSet.getMetaData(); // Ermittele Meta-Daten des ResultSets
                int columns = md.getColumnCount();
                System.out.println("Anzahl der Spalten: " + columns + " \n");*/

                ArrayList <String> tabledat = new ArrayList<String>();
                tabledat.add("Hallo1 /n");
                tabledat.add("hallo2 /n");

                /*while(rSet.next()) { // Solange noch Ergebnisdatensätze da sind...

                    for(int i=1; i<=columns; ++i) {
                        // Durchlaufe alle Spalten der aktuellen Zeile des ResultSets
                        tabledat.add(rSet.getString(i)); // Aktuellen Eintrag des ResultSets in ArrayList speichern

                    }
                }*/





                // Ergebnis der Datenbankabfrage wir wieder als binärer Datenstrom zum
                // Client zurückgeschickt

                OutputStream os = sock.getOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(os);

                oos.writeObject(tabledat);
                oos.flush();

                oos.close();
               // servsock.close();
            }

        }

        catch (IOException ex)
        {
            ex.printStackTrace();
            System.out.println("Fehler : " + ex);

        }

        finally {
            CloseDB(stmt,conn); // Datenbankverbindung schließen
        }



    }

    public void CloseDB(Statement stmt, Connection conn )
    {
        try {
            stmt.close();
            conn.close();
        } catch(Exception e) {
            //
        }
    }
    public static void main(String[] args) {
        // Starte den Server:

        ServerDB serv = new ServerDB();
        serv.los();
    }
}
```


----------



## Jw456 (7. Aug 2021)

Client wurde nicht verändert
nur die IP


----------



## Jw456 (7. Aug 2021)

Turing0001 hat gesagt.:


> Habe es gerade nochmal mit einem anderen Programm getestet. Solange ich nur Daten von Server anfordere funktioniert es. Wenn ich aber Daten vom Client an den Server sende und auf Rückantwort warte, gibt es plötzlich Probleme, die es vorher nicht gab. Ich poste mal nochmal den vollständigen Code von meinem Client und dem Server. Ich bitte das Chaos schon im Voraus zu entschuldigen


verstehe ich das richtig du hast hier in diesem fall Server und Client auf der gleichen Maschine laufen.


----------



## Turing0001 (7. Aug 2021)

Hallo JW456,

immer noch das gleiche Problem. Nein, Client und Server liegen auf verschiedenen Rechnern. Für den Rechner mit dem Server ist die Portweiterleitung eingerichtet.


----------



## Turing0001 (7. Aug 2021)

Hier auch nochmal ein Client/Server-Programm, mit welchem das Ganze funktioniert. Client liegt wieder auf Rechner 1, Server auf Rechner 2 mit der Portweiterleitung. Im Client kann also sowohl die lokale IP-Adresse von Rechner 2 eingetragen werden, als auch die WAN-IP und es funzt.

Client:


```
import java.io.*;
import java.net.*;

public class client {
    
    private InetSocketAddress address;
    
    public void los()
    {
        
        try
        {
        
          address = new InetSocketAddress("192.168.2.101",4243);
          Socket s = new Socket();
          s.connect(address, 3000); // Verbinde Dich mit dem Server, maximale Wartezeit: 3 Sekunden
          // Socket s = new Socket("192.168.2.101",4243); //Socketverbindung zum Hostost erzeugen
          InputStreamReader lies = new InputStreamReader(s.getInputStream()); // Lies die Daten vom Serversocket
          BufferedReader reader = new BufferedReader(lies);
          //Daten mit einem Reader lesen wie bei Dateien:
          
          String text = reader.readLine();
          System.out.println("Tipp des Tages: " + text);
          reader.close();
          s.close();
        }
          
       catch(IOException ex) {ex.printStackTrace();}
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // Client starten:
        
        client client1 = new client();
        client1.los();
    }
}
```


Hier noch der Server:


```
import java.io.*;
import java.net.*;

public class server {
    
    String[] tippListe={"Weniger Chips und Schokolade essen!","Kaufen Sie sich was schönes!","Sagen Sie heute die Wahrheit","Mehr Programmieren Üben!","Knuddeln Sie Ihren Partner!"};
    public void los()
    {
        try
        {
            ServerSocket servsock = new ServerSocket(4243); // Verbindungsschnittstelle auf Port 4243 erstellen
            while(true)
            {
               System.out.println("Hallo hier ist der Server!");
               Socket sock = servsock.accept(); // Warten auf "Anruf" von einem Client. accept() blockiert bis ein Client "anruft"
               PrintWriter writer = new PrintWriter(sock.getOutputStream()); // Ausgabedatenleitung zum Clientsocket aufbauen...
               String tipp = getTipp();
               writer.println(tipp); // ... und die Daten an den Client senden
               System.out.println("Clientadresse: " + sock.getInetAddress() + "  Portnummer: "+ sock.getPort() + " " + "Lokaler Port: " + sock.getLocalPort());
               writer.close(); // Ausgabedatenleitung wieder schließen
               //servsock.close();
               System.out.println(tipp);
            }
            
        }
        catch (IOException ex){ex.printStackTrace();}
    }
    
    private String getTipp()
    {
        int zufall = (int)(Math.random()*tippListe.length);
        return tippListe[zufall];
    }

    
    public static void main(String[] args) {
        // Starte den Server:
        
        server serv = new server();
        serv.los();
    }
}
```


Ich verstehe langsam die (Java)Welt nicht mehr.


----------



## kneitzel (7. Aug 2021)

Du bist also wirklich 100% sicher, dass der Code, den du für den Client gezeigt hast, wirklich genau so ist? Du also garantiert an den Server mit einem PrintWriter und println mit anschließendem flush etwas an den Server gesendet hast? 

Was sind das für zwei Systeme (Betriebssystem)? Welche Java Version nutzt du jeweils? Wie genau startest Du Server und Client? Und da Du das Default Encoding nutzt: führ mal das folgende Programm auf beiden Systemen aus:

```
import java.nio.charset.Charset;

public class PrintDefaultCharset {
    public static void main(String[] args) {
        System.out.println(Charset.defaultCharset());
    }
}
```


----------



## kneitzel (7. Aug 2021)

Eine Frage drängt sich mir noch auf - unabhängig von dem Problem:

Sollen das nur einfache Spiel-Projekte sein? Was will Du dabei lernen oder vertiefen?

Generell ist das, was Du da derzeit machst, nicht wirklich etwas, das man noch machen würde.
a) In der Regel verwendet man "höhere" Protokolle, also Protokolle, die auf dem, was Du da machst, aufsetzen und extrem viel bieten. So ist z.B. das HTTP Protokoll sehr verbreitet. Und da könnte man viele Dinge, die Du da machst, direkt als WebService schreiben. Und wenn ich da so ein select sehe: REST bietet sich da an - da wäre dann ein "select * from user" einfach ein Request, alle User aufzulisten.

b) Wenn man ein eigenes Protokoll haben möchte, dann macht es Sinn, auf eine Lib zuzugreifen, die einem schon sehr viel bietet. https://netty.io/ wäre da z.B. eine Library mit der man da schnell und einfach etwas aufbauen kann.

Ansonsten kann man das aber natürlich auch weiter vertiefen - eine Möglichkeit, da alles in mehrere Klassen zu unterteilen, hast Du ja jetzt, aber gerad wenn es um Ports nach außen geht, dann kommt da einiges mit ins Spiel - vor allem Security:
- Zum einen will man alles verschlüsseln, also SSL / TLS kommen da ins Spiel. 
- Zum Anderen dann noch eine Autorisierung - das ist eher einfach.


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

bei beiden die Ausgabe windows-1252
Hast Du den Chatclient/Chatserver schon mal testen können? Und Du hast recht, den DBServer hatte ich nochmals verändert. Soll ich den Code für Client und Server nochmals einstellen? Ich möchte unbedingt wissen, warum meine Version nicht funktioniert, auch wenn die Codequalität natürlich sehr zu wünschen übrig lässt und Du mit Deiner Kritik recht hast. Vor allem die Sache mitdem Chatprogramm will mir nicht inden Kopf. Es hat sich lediglich dei WAN-IP geändert, der Code ist genauso wie vorher, auch die Einstellung der statischen Portweiterleitung im Router ist unverändert.


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

momentan ist mein Ziel, wieder in die Java-Programmierung reinzukommen, nach langer Absesenheit. Spieleprogrammierung ist ein Ziel, korrekt, aber erst einmal die Basics auffrischen und vertiefen. Teilweise weiss ich aber nicht recht, wo ich da anfangen soll, es gibt so viele Baustellen und meine Zeit ist begrenzt.


----------



## Jw456 (7. Aug 2021)

dein code wird schon an dieser zeile  hängen  bleiben 

ArrayList clientAusgabeStröme;

ArraList ohne DatenTyp.


----------



## kneitzel (7. Aug 2021)

Jw456 hat gesagt.:


> dein code wird schon an dieser zeile  hängen  bleiben
> 
> ArrayList clientAusgabeStröme;
> 
> ArraList ohne DatenTyp.


Nein, dann nutzt er die Klasse halt ohne Generics. Nicht schön, aber das funktioniert auch.


----------



## Turing0001 (7. Aug 2021)

Hallo JW456,

nein, das ist nicht die Ursache. In einer zweiten Version habe ich dei ArrayList parametrisiert, das macht aber keinen Unterschied. Und wie gesagt, im lokalen Netz mit 3 Rechnern läuft das Ganze ja einwandfrei und bis vor einiger Zeit auch mit meiner WAN-IP, nun plötzlich nicht mehr.


----------



## kneitzel (7. Aug 2021)

Turing0001 hat gesagt.:


> Hallo Kneitzel,
> 
> bei beiden die Ausgabe windows-1252
> Hast Du den Chatclient/Chatserver schon mal testen können? Und Du hast recht, den DBServer hatte ich nochmals verändert. Soll ich den Code für Client und Server nochmals einstellen? Ich möchte unbedingt wissen, warum meine Version nicht funktioniert, auch wenn die Codequalität natürlich sehr zu wünschen übrig lässt und Du mit Deiner Kritik recht hast. Vor allem die Sache mitdem Chatprogramm will mir nicht inden Kopf. Es hat sich lediglich dei WAN-IP geändert, der Code ist genauso wie vorher, auch die Einstellung der statischen Portweiterleitung im Router ist unverändert.


Ja, bitte Server und Client in der Version einstellen, in der der Fehler gekommen ist. Und dazu bitte die ganze Ausgabe, also auch incl. ggf. getätigter Ausgaben.


----------



## Jw456 (7. Aug 2021)

Turing0001 hat gesagt.:


> Hallo JW456,
> 
> nein, das ist nicht die Ursache. In einer zweiten Version habe ich dei ArrayList parametrisiert, das macht aber keinen Unterschied. Und wie gesagt, im lokalen Netz mit 3 Rechnern läuft das Ganze ja einwandfrei und bis vor einiger Zeit auch mit meiner WAN-IP, nun plötzlich nicht mehr.



ArrayList clientAusgabeStröme;
       //dann kommt das
public void los() {
    clientAusgabeStröme = new ArrayList();

wo sind die Spitzen Klammern im post #59 beim server?


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Nein, dann nutzt er die Klasse halt ohne Generics. Nicht schön, aber das funktioniert auch.


bei mir nicht bekomme fehler
error: illegal character: '\u00b6'
    ArrayList  clientAusgabeStröme;


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

Sie wünschen, wir liefern.

Client:


```
package mypackage;

import java.io.*;
import java.net.*;
import java.util.ArrayList;




public class ClientDB {
    
     private InetSocketAddress address;
     PrintWriter writer;
    
    public void los()
    {
        
        try
        {
        
            
         address = new InetSocketAddress("192.168.2.101",4243);// Hier natürlich die WAN-IP angeben
        
          Socket s = new Socket();
          s.connect(address, 3000); // Verbinde Dich mit dem Server, maximale Wartezeit: 3 Sekunden
          
          // Erstellen eines Printwriters, da hier Texte und keine binären Rohdaten gesendet werden:
          
          writer = new PrintWriter(s.getOutputStream());
          writer.println("select * from leute"); // SQL-Befehl an Server absenden
          try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
          writer.flush();
          
          // Empfangen werden vom Server aber binäre Rohdaten, also wird ObjectInputStream benötigt:
          
          ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
          
    
          // Ausgabe der ArrayList mit dem ResultSet der Datenbank in einem String
          // nachdem die Rohdaten zunächst wieder in eine ArrayList von Typ String
          // zurückverwandelt wurden
          
          System.out.println("Ausgabe der Daten:");
          ArrayList <String> al = (ArrayList<String>)(ois.readObject());
          System.out.println(al.toString());
        
        
//          ois.close();
//          s.close();
//          writer.close();
        }
          
       catch(IOException ex) {ex.printStackTrace();}
       catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // Client starten:
        
        ClientDB client1 = new ClientDB();
        client1.los();
    }
}
```

Client Fehlermeldung:

java.net.SocketException: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat
    at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:325)
    at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:981)
    at java.base/java.ibjectInputStream$PeekInputStream.read(ObjectInputStream.java:2914)
    at java.base/java.ibjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2930)
    at java.base/java.ibjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3427)
    at java.base/java.ibjectInputStream.readStreamHeader(ObjectInputStream.java:962)
    at java.base/java.ibjectInputStream.<init>(ObjectInputStream.java:405)
    at mypackage.ClientDB.los(ClientDB.java:41)
    at mypackage.ClientDB.main(ClientDB.java:73)


Servercode:


```
package mypackage;

import java.io.*;
import java.net.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import javax.swing.JOptionPane;



public class ServerDB {
    
    Connection conn;//Schnittstelle um Verbindung zur DB herzustellen
    Statement stmt;
    ResultSet rSet;
    BufferedReader reader;
    

    public void los()
    {
        try
        {
            ServerSocket servsock = new ServerSocket(4243); // Verbindungsschnittstelle auf Port 4243 erstellen
            while(true)
            {
                System.out.println("Hallo hier ist der Server!");
                Socket sock = servsock.accept(); // Warten auf "Anruf" von einem Client. accept() blockiert bis ein Client "anruft"
                
                // Empfange einen String (= SQL Befehl) vom Client:
                
                InputStreamReader isReader = new InputStreamReader (sock.getInputStream());
                reader = new BufferedReader(isReader);
                //String nachricht = reader.readLine(); // Lesen des SQL Befehls
                String nachricht = null;
                System.out.println("Bin hier");
                OutputStream os = sock.getOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(os);
                //oos.writeObject(tabledat);
                //System.out.println("Daten zurückgeschickt an Client");
                oos.flush();
                
                nachricht = reader.readLine(); // Lesen des SQL Befehls
            
                System.out.println("Empfangene Nachricht: " + nachricht);
//                try {
//                    Thread.sleep(500);
//                } catch (InterruptedException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                }
                //JOptionPane.showMessageDialog(null, "Nachricht: " + nachricht);
                System.out.println("Empfangene Nachricht nochmal: " + nachricht);
                // Ab hier wieder wie gehabt Verbindung zur Datenbank:
                
               DriverManager.setLogWriter(new PrintWriter(System.out));
               Class.forName("org.sqlite.JDBC");
               System.out.println("Treiber geladen");
               String url = "jdbc:sqlite::resource:"+ "MyDB.db";
               conn = DriverManager.getConnection(url,"",""); // Verbindungsobjekt erstellen
                  System.out.println("Verbindung steht" );
                  stmt = conn.createStatement();
                  rSet = stmt.executeQuery(nachricht); // Schicke den SQL-Befehl an die Datenbank und nimm das Ergebnis entgegen
                  ResultSetMetaData md = rSet.getMetaData(); // Ermittele Meta-Daten des ResultSets
                  int columns = md.getColumnCount();
                  System.out.println("Anzahl der Spalten: " + columns + " \n");
                  
                  ArrayList <String> tabledat = new ArrayList<String>();
                  
                  while(rSet.next()) { // Solange noch Ergebnisdatensätze da sind...
                
                for(int i=1; i<=columns; ++i) {
                     // Durchlaufe alle Spalten der aktuellen Zeile des ResultSets
                    tabledat.add(rSet.getString(i)); // Aktuellen Eintrag des ResultSets in ArrayList speichern
                    
                }
            }
                  
                  
                  
                  // Ergebnis der Datenbankabfrage wir wieder als binärer Datenstrom zum
                  // Client zurückgeschickt
                  
//                  OutputStream os = sock.getOutputStream();
//                  ObjectOutputStream oos = new ObjectOutputStream(os);
                  
              oos.writeObject(tabledat);
              System.out.println("Daten zurückgeschickt an Client");
//               oos.flush();
              
               //oos.close();
               //servsock.close();
            }
            
        }
        
        catch (IOException ex)
        {ex.printStackTrace();}
        catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {           
            CloseDB(stmt,conn); // Datenbankverbindung schließen
        }   
    
    
  
}
    
    public void CloseDB(Statement stmt, Connection conn )
    {
        try {
            stmt.close();
            conn.close();
        } catch(Exception e) {
            //
        }
    }
    public static void main(String[] args) {
        // Starte den Server:
        
        ServerDB serv = new ServerDB();
        serv.los();
    }
}
```


Server Ausgabe und Fehlermeldung:

Hallo hier ist der Server!
Bin hier
java.net.SocketException: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat
    at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:325)
    at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:981)
    at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
    at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
    at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
    at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
    at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
    at mypackage.ServerDB.los(ServerDB.java:48)
    at mypackage.ServerDB.main(ServerDB.java:132)

Ich hoffe, das hilft Dir weiter.


----------



## kneitzel (7. Aug 2021)

Jw456 hat gesagt.:


> ArrayList clientAusgabeStröme;
> //dann kommt das
> public void los() {
> clientAusgabeStröme = new ArrayList();
> ...


Die braucht man nicht. Wäre dies zwingend notwendig, dann wäre Java bei Einführung der Generics nicht abwärts kompatibel gewesen.

Daher ist es vollkommen legitim, das auch so zu nutzen.


----------



## Jw456 (7. Aug 2021)

kneitzel hat gesagt.:


> Die braucht man nicht. Wäre dies zwingend notwendig, dann wäre Java bei Einführung der Generics nicht abwärts kompatibel gewesen.
> 
> Daher ist es vollkommen legitim, das auch so zu nutzen.


ich bekomme den fehler  beim run


error: illegal character: '\u00b6'
   ArrayList  clientAusgabeStröme


----------



## Turing0001 (7. Aug 2021)

Jw456 hat gesagt.:


> ich bekomme den fehler  beim run
> 
> 
> error: illegal character: '\u00b6'
> ArrayList  clientAusgabeStröme


Ich habe diesen Fehler nicht, aber wenn er sich an dem Umlaut stört, dann z.B. in oe ändern. Obwohl das merkwürdig ist


----------



## Jw456 (7. Aug 2021)

Jw456 hat gesagt.:


> ich bekomme den fehler  beim run
> 
> 
> error: illegal character: '\u00b6'
> ArrayList  clientAusgabeStröme


schon komisch  gradle biringt mir den fehler Maven nicht    
OK


----------



## Turing0001 (7. Aug 2021)

Hallo Kneitzel,

kann ich Dir hier über das Forum eine PN zukommen lassen? Dann würde ich Dir meine WAN-IP geben (da ich Dir vertraue), Server läuft und Du könntest den Client mal direkt testen. Ansonsten per sms wenn ich Dir die Handynummer gebe (auf den sozialen Medien bin ich nirgends engagiert, zu wenig Vertrauen). Jetzt erst mal Brotzeit!


----------



## kneitzel (7. Aug 2021)

Jw456 hat gesagt.:


> schon komisch  gradle biringt mir den fehler Maven nicht
> OK


Mit was für einem Charset arbeitest Du? Bei Maven hast Du in den Properties in der Regel etwas wie:
`<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>`

und in Gradle ein:
`tasks.withType(JavaCompile) { options.encoding = 'UTF-8' }`

Damit sollten Umlaute verarbeitet werden können.

@Turing0001
Ich bin im Augenblick etwas ratlos. Das sieht eigentlich soweit in Ordnung aus. Ich bin nur über eine Sache gestolpert:
Socket.getInputStream kann wohl Bytes wegwerfen, wenn diese schon im Socket zwischengespeichert sind:


> The network software may discard bytes that are buffered by the socket. Bytes that aren't discarded by the network software can be read using read.


Aber so ganz verstehen tue ich das im Augenblick nicht.

Was Du ändern kannst: Zieh das Erzeugen der jeweiligen Streams / Writer direkt nach den connect:

Also im Client:

```
s.connect(address, 3000); // Verbinde Dich mit dem Server, maximale Wartezeit: 3 Sekunden
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
            writer = new PrintWriter(s.getOutputStream());
```

Und im Server:

```
Socket sock = servsock.accept(); // Warten auf "Anruf" von einem Client. accept() blockiert bis ein Client "anruft"
                InputStreamReader isReader = new InputStreamReader (sock.getInputStream());
                OutputStream os = sock.getOutputStream();
```

Verändert das evtl. schon etwas?



Turing0001 hat gesagt.:


> kann ich Dir hier über das Forum eine PN zukommen lassen? Dann würde ich Dir meine WAN-IP geben (da ich Dir vertraue), Server läuft und Du könntest den Client mal direkt testen. Ansonsten per sms wenn ich Dir die Handynummer gebe (auf den sozialen Medien bin ich nirgends engagiert, zu wenig Vertrauen). Jetzt erst mal Brotzeit!


Über "Gespräche" kannst Du mir persönliche Nachrichten im Forum zuschicken.


----------



## Jw456 (7. Aug 2021)

habe es auch auf einem Rechner Server und Client getestet mit öffentlicher IP geht.

habe im Moment keinen zweiten Rechner .



Frage was hast du eine IPv4 oder IPv6?


----------



## Turing0001 (7. Aug 2021)

Jw456 hat gesagt.:


> habe es auch auf einem Rechner Server und Client getestet mit öffentlicher IP geht.
> 
> habe im Moment keinen zweiten Rechner .
> 
> ...


IPv4


----------



## Jw456 (8. Aug 2021)

Hallo habe dienen Server und Client Code mit Gui noch mal mit zwei Rechner getestet.
Im Lan mit Öffentlicher IP im Client. Natürlich habe ich den Port im Router geforwarded .
Geht bei mir.



An deinem Code liegt es nicht wenn es bei dir nicht geht.
Da würde ich auf den Router tippen als erstes. Vielleicht ist da eine Firewall die das blockiert.
Order dein Forwarding ist nicht richtig.



Welchen Router hast du?



Wie schon gesagt geht es ja auch bei deinen Kumpels. Nur bei dir nicht da wollte aber gestern keiner richtig drauf eingehen. Also muss es eigentlich eine Konfig Sache Router oder Rechner sein. Nicht der Java Code.



Ob das Ganze in Bezug auf Sicherheit sinnvoll ist, ist wider ein anders Thema.


----------



## Turing0001 (8. Aug 2021)

Jw456 hat gesagt.:


> Hallo habe dienen Server und Client Code mit Gui noch mal mit zwei Rechner getestet.
> Im Lan mit Öffentlicher IP im Client. Natürlich habe ich den Port im Router geforwarded .
> Geht bei mir.
> 
> ...


Hallo,

danke für die Info. Kneitzel hatte es gestern auch probiert und das Ergebnis war einwandfrei. Muss also beim Router irgendetwas sein. Ich habe die Einstellungen zur Portweiterleitung überprüft, daran liegt es nicht, da habe ich auch seit Monaten nichts verändert. Bei der Firewall bin ich mir nicht sicher, ich habe nur die Windows-Firewall aktiviert, aber auch dahatsich eigentlich in letzter Zeit nichts geändert. Wegen der Porteinstellungen hier mal ein Screenshot (obwohl das meines Wisssens nach hier im Forum wohl nicht so gerne gesehen wird wenn ich mich recht erinnere):




Dasganze istwirklich sehr mysteriös. Ich werde aber auch nochmal mit der Firewall experimentieren. Vielen Dank für Deine Mühe.


----------



## Jw456 (8. Aug 2021)

Benutze mal im Router nicht den Rechner Nahmen sondern die IP die er im Lan hat.
Firewall im Router wenn vorhanden mal ausschalten.


----------



## Turing0001 (8. Aug 2021)

Ok, danke für den Hinweis, ich werde es nach dem Mittagessen mal ausprobieren.


----------



## Turing0001 (8. Aug 2021)

Der Router lässt das leider nicht zu, ich kann nur die Namen der Rechner verwenden.


----------



## Jw456 (8. Aug 2021)

dann wird das wol so sein.


----------



## kneitzel (8. Aug 2021)

Der Router lässt ja den Verbindungsaufbau zu. Das zeigt, dass das Portforwarding funktioniert auf den Router.
Und da die Connection zustande kommt, ist da auch erst einmal keine Firewall, die den Verbindungsaufbau blockiert.

An welcher Stelle etwas schief läuft, kann ich im Augenblick so auch nicht sagen. Da wäre es interessant, mal mit wireshark die Pakete im Detail zu analysieren um zu sehen, was für Pakete wohin geschickt werden. Die einfachen Erklärungsversuche taugen aber schlicht nichts (Und es würden andere Verhalten auftreten, so an den Stellen etwas nicht klappen sollte).

Man kann den Router einmal ausschalten und wieder einschalten um da ein Fehlverhalten etwas auszuschließen. Aber halte ich für unwahrscheinlich.

Mal ein ganz einfacher Test, den Du aber mal laufen lassen könntest:


Spoiler: Code für Test



[CODE lang="java" title="ServerDB"]package mypackage;

import java.io.*;
import java.net.*;

public class ServerDB {

    public void los()
    {
        try
        {
            ServerSocket servsock = new ServerSocket(4243);
            System.out.println("Waiting on port 4243 ...");
            Socket socket = servsock.accept();
            System.out.println("connected!");
            OutputStream out = socket.getOutputStream();
            InputStream in = socket.getInputStream();

            new Thread( () -> {
                try {
                    while (true) System.out.println("Received: " + in.read());
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }).start();

            for (int i = 0; i<100; i++) {
                out.write(i);
                System.out.println("Send: " + i);
                out.flush();
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ServerDB serv = new ServerDB();
        serv.los();
    }
}[/CODE]

[CODE lang="java" title="ClientDB"]package mypackage;

import java.io.*;
import java.net.*;

public class ClientDB {

    public void los()
    {

        try
        {
            InetSocketAddress address = new InetSocketAddress("127.0.0.1",4243);

            Socket socket = new Socket();
            socket.connect(address, 3000);
            System.out.println("connected!");
            OutputStream out = socket.getOutputStream();
            InputStream in = socket.getInputStream();

            new Thread( () -> {
                try {
                    while (true) System.out.println("Received: " + in.read());
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }).start();

            for (int i = 0; i<100; i++) {
                out.write(i);
                System.out.println("Send: " + i);
                out.flush();
            }
        }

        catch(IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // Client starten:

        ClientDB client1 = new ClientDB();
        client1.los();
    }
}[/CODE]



Der Test nutzt minimale Funktionen um einfach nur paar Bytes zu versenden. (Beide senden einfach von 0-99 hin)

Die Programme beenden sich nicht - also erst Server starten, dann Client, dann sollten die Zahlen von 0-99 versendet und empfangen worden sein und du kannst mit Ctrl-C beide abbrechen.


----------



## Turing0001 (8. Aug 2021)

kneitzel hat gesagt.:


> Der Router lässt ja den Verbindungsaufbau zu. Das zeigt, dass das Portforwarding funktioniert auf den Router.
> Und da die Connection zustande kommt, ist da auch erst einmal keine Firewall, die den Verbindungsaufbau blockiert.
> 
> An welcher Stelle etwas schief läuft, kann ich im Augenblick so auch nicht sagen. Da wäre es interessant, mal mit wireshark die Pakete im Detail zu analysieren um zu sehen, was für Pakete wohin geschickt werden. Die einfachen Erklärungsversuche taugen aber schlicht nichts (Und es würden andere Verhalten auftreten, so an den Stellen etwas nicht klappen sollte).
> ...


Hallo Kneitzel,

habe es gerade in Eclipse getestet. Bei Client und Server wird in der Konsole Send 0 ... Send 99 ausgegeben, aber bei beiden keine Received-Ausgabe, stattdessen bei beiden wieder nach einiger Zeit die Fehlermeldung (hier die vom Client):

java.net.SocketException: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat
    at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:325)
    at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:981)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:976)
    at mypackage.ClientDB.lambda$0(ClientDB.java:23)
    at java.base/java.lang.Thread.run(Thread.java:832)

Ich weiß auch keinen Rat mehr, zumal bei Dir ja der Zugriff auf meine WAN-IP korrekt funktionierte


----------



## Turing0001 (8. Aug 2021)

Ich werde nun mal den Router ein paar Minuten vom Netz nehmen, malsehen ob das was bringt


----------



## kneitzel (8. Aug 2021)

Ich habe jetzt noch einmal etwas mehr recherchiert. Es findet sich in den Telekom Hilfeseiten einiges an Aussagen, dass die Portfreischaltung nur von Außen getestet werden kann. Aber wirkliche Aussagen, die man hier ernsthaft zitieren könnte, kann ich nicht bringen. Das ist aber definitiv eine Spezialität des Speedport Routers (Besonders speziell wird es, da ja der Verbindungsaufbau klappt, d.h. beim Verbindungsaufbau senden sich Server und Client erfolgreich Pakete zu. Nur nachfolgende Pakete werden dann nicht mehr weiter gesendet.

Die Anleitung zu den Speedport 900 Routern habe ich auch einmal durchgesehen - da ist diesbezüglich keinerlei Konfiguration vorgesehen / möglich.

(Bei z.B. FirtzBox klappt sowas übrigens auch ganz ohne Probleme. Ebenso bei selbst aufgesetzten (Linux-) Routern. Ich greife auf meinen Terminal-Server immer über den DNS Namen zu - und damit immer über die externe IP)

Jetzt könnte man ja sagen: Dann musst Du halt lokale Tests per lokalen IPs machen. Aber diese Aussage ist in meinen Augen recht fatal, denn das verkompliziert einiges. Man will ja später auch per DNS zugreifen um dann auch SSL und co zu haben.


----------



## Turing0001 (8. Aug 2021)

kneitzel hat gesagt.:


> Ich habe jetzt noch einmal etwas mehr recherchiert. Es findet sich in den Telekom Hilfeseiten einiges an Aussagen, dass die Portfreischaltung nur von Außen getestet werden kann. Aber wirkliche Aussagen, die man hier ernsthaft zitieren könnte, kann ich nicht bringen. Das ist aber definitiv eine Spezialität des Speedport Routers (Besonders speziell wird es, da ja der Verbindungsaufbau klappt, d.h. beim Verbindungsaufbau senden sich Server und Client erfolgreich Pakete zu. Nur nachfolgende Pakete werden dann nicht mehr weiter gesendet.
> 
> Die Anleitung zu den Speedport 900 Routern habe ich auch einmal durchgesehen - da ist diesbezüglich keinerlei Konfiguration vorgesehen / möglich.
> 
> ...


Hallo Kneitzel,

so ist es. Habe gerade den Router neu gestartet, ohne Verbesserung. Ich werde mich die nächsten Tage mal mit der Telekom in Verbindung setzen, vielleicht haben die eine Antwort. Vielen vielen Dank jedenfals für eure Mühen.


----------



## Jw456 (8. Aug 2021)

Turing0001 hat gesagt.:


> Hallo Kneitzel,
> 
> habe es gerade in Eclipse getestet. Bei Client und Server wird in der Konsole Send 0 ... Send 99 ausgegeben, aber bei beiden keine Received-Ausgabe, stattdessen bei beiden wieder nach einiger Zeit die Fehlermeldung (hier die vom Client):
> 
> ...


zur info
mit dem Localhost 127.0.0.1
habe ich auch keinen Reciev. mit der öffentlichen oder der interenen server  ip ja.

was der Test auf den Localhost bewirken solte ist mir nicht klar.

edit hatte es auf einen Rechner.


----------



## mihe7 (8. Aug 2021)

kneitzel hat gesagt.:


> Jetzt könnte man ja sagen: Dann musst Du halt lokale Tests per lokalen IPs machen. Aber diese Aussage ist in meinen Augen recht fatal, denn das verkompliziert einiges. Man will ja später auch per DNS zugreifen um dann auch SSL und co zu haben.


Man kann testweise auch über die hosts den Domainnamen auf eine lokale IP mappen, vielleicht wäre das für @Turing0001 ein gangbarer Workaround.


----------



## kneitzel (8. Aug 2021)

mihe7 hat gesagt.:


> Man kann testweise auch über die hosts den Domainnamen auf eine lokale IP mappen, vielleicht wäre das für @Turing0001 ein gangbarer Workaround.


Ja, aber das muss dann bei jedem Rechner sein … und Tests sind dann nur begrenzt möglich, z.B. in Form eines Portscans.

Mich wundert vor allem das Verhalten. Was hat die Telekom da gebaut? Denn unter dem Strich wird da doch auch nur ein Linux in der Kiste stecken mit entsprechender Konfiguration. Aber da habe ich keine Informationen zu gefunden. Interessiert mich, da bei mir eigentlich ein Wechsel von Vodafone zur Telekom ansteht und mich das dann ja auch treffen würde…


----------



## Jw456 (8. Aug 2021)

Vielleicht gibt es auch ein Firmenware Update für das Teil.


----------

