TCP multiClientServer mit socket mittels ObjectOutputStream

Diskutiere TCP multiClientServer mit socket mittels ObjectOutputStream im Netzwerkprogrammierung Bereich.
A

alex_Coding

Hallo zusammen,

ich Rahmen eines Praktikums im Studium war die Aufgabe Objecte über einen Socket zu verschicken.Dies sollte mitteln eines multiClientServer geschehen. Das Verschicken der Objekte muss zwingend über einen ObjectOutputStream realisiert .Derzeitig werden nur String Objekte verschickt, zum Testen...

Unten befinden sich 3 Klassen: Server, ClientHandler, und der Client. Um leichter einen Einstieg zu finden, habe ich den Code eingefügt.

Ich starte also die Main Methode der Server Klassen und im Anschluss führe ich die Main des Client aus.

An der Stelle
System.out.println("bis hier und nicht weiter"); innerhalb des ClientHandler.class ist dann irgendwie Schluss. Dies wird noch ausgegeben.

Aber der Thread wird nicht gestartet, also glaube ich zumindestens, auf jeden Fall wird der print Befehl innerhalb des Construktors von CLientHandler nicht ausgegeben.


Ich habe die Dateien zudem in den Anhang gepackt.

Vielen Dank im voraus, ich bin überfrage




Java:
package tcp_final;

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

//Java implementation of  Server side 
//It contains two classes : Server and ClientHandler 
//Save file as Server.java 



//Server class 
public class Server  
{ 
 public static void main(String[] args) throws IOException  
 { 
     // server is listening on port 5056 
   
    ServerSocket ss = new ServerSocket(8080); 
    System.out.println("Server gestartet auf Socket: "+ ss.getLocalPort());  
     // running infinite loop for getting 
     // client request 
     while (true)  
     { 
         Socket s = null; 
         
         try 
         {     
             
             // socket object to receive incoming client requests 
             s = ss.accept(); 
               
             System.out.println("bis hier und nicht weiter");
             ObjectInputStream dis = new ObjectInputStream(s.getInputStream()); 
             ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream()); 
               
             System.out.println("Assigning new thread for this client"); 
             

             Thread t = new ClientHandler(s, dis, dos); 
             t.start(); 
               
         } 
         catch (Exception e){ 
             s.close(); 
             ss.close();
             e.printStackTrace(); 
         } 
     } 
 } 
}


Java:
package tcp_final;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

//ClientHandler class 
class ClientHandler extends Thread  
{ 

 final ObjectInputStream dis; 
 final ObjectOutputStream dos; 
 final Socket s; 


 // Constructor 
 public ClientHandler(Socket s, ObjectInputStream dis, ObjectOutputStream dos)  
 { 
     System.out.println("Run ClientHandler Constructor");
     this.s = s; 
     this.dis = dis; 
     this.dos = dos; 
 } 

 @Override
 public void run()  
 { 
     System.out.println("Thread Run Methode");
     String received; 
  
     while (true)  
     { 
         try { 
             
                
             received = (String) dis.readObject(); 
             System.out.println("Vom Server gesendet: "+ received);
             
             if(received.equals("Exit")) 
             {  
                 System.out.println("Client " + this.s + " sends exit..."); 
                 System.out.println("Closing this connection."); 
                 this.s.close(); 
                 System.out.println("Connection closed"); 
                 break; 
             } 
                 
             ///send to server
             dos.writeObject("Irgendeine Nachricht");
             
                 
         } catch (IOException e) { 
             e.printStackTrace(); 
         } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
     } 
     try
     { 
         // closing resources 
         this.dis.close(); 
         this.dos.close(); 
           
     }catch(IOException e){ 
         e.printStackTrace(); 
     } 

 } 
}


Java:
package tcp_final;
import java.io.*; 
import java.net.*; 
import java.util.Scanner; 

//Client class 
public class Client  
{ 
 public static void main(String[] args) throws IOException  
 { 
     try
     { 
         Scanner scn = new Scanner(System.in); 
           
         // getting localhost ip 
         InetAddress ip = InetAddress.getByName("localhost"); 
         Socket s = new Socket(ip, 8080); 
   
         ObjectInputStream dis = new ObjectInputStream(s.getInputStream()); 
         ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream()); 
         
         // the following loop performs the exchange of 
         // information between client and client handler 
         while (true)  
         {    
             System.out.println("Client While"); 
             
             String tosend = "Nachricht an den Server";
             dos.writeObject(tosend);
             
             if(tosend.equals("Exit")) 
             { 
                 s.close(); 
                 break; 
             } 
 
             /// Antwort from Server
             String received =  (String) dis.readObject(); 
             System.out.println(received); 
             
         } 
           
         // closing resources 
         scn.close(); 
         dis.close(); 
         dos.close(); 
     }catch(Exception e){ 
         e.printStackTrace(); 
     } 
 } 
}
 

Anhänge

Zuletzt bearbeitet von einem Moderator:
L

LimDul

Das dürfte die Ursache sein:

Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.

Das erzeugen eines ObjectInputStreams ist eine Blocking-Operation. Der Server muss mindestens sofort den Serialization Header schicken (wie auch immer man das macht, da bin ich raus)
 
L

LimDul

Nachtrag: Versuch mal die ObjectOutputStreams zuerst zu erzeugen.

Dadurch das du sowohl auf Client als auch auf Server Seite die InputStreams zuerst erzeugt, warten sowohl Client als auch Server, dass der korrekte Header geschickt wird - was nie passieren wird, da keiner der beiden den ObjectOutputStream erzeugen kann.
 
J

JustNobody

Eine Idee wäre, dass man sofort nach der Verbindung jeweils ein Objekt schickt. Das kann z.B. ein leerer String sein oder einfach eine Object Instanz.

Mit dem Schreiben des ersten Objekts wird natürlich auch der Header geschrieben und die blocking Operation geht weiter. Das bedeutet, dass er zwar immer noch blockiert, aber halt nur, bis das erste Objekt angekommen ist ...

Wichtig ist aber auch, dass man die Erstellung auf Client / Server in unterschiedlicher Reihenfolge macht. Wenn sowohl Server als auch Client zuerst den InputStream öffnen, warten beide auf ein erster Objekt. Also sollte man da ggf. so hingehen, das immer erst der OutputStream erstellt wird und ein erstes Objekt gesendet wird (um den Header abgearbeitet zu haben).
 
J

JustNobody

Noch eine kleine Korrektur bezüglich meiner Antwort:
Es scheint so, als ob der Header direkt geschrieben wird und nicht beim ersten Objekt, das gesendet wurde.

Daher ist dieses erste Objekt nicht notwendig, sondern es sollte ausreichen, die ObjectOutputStreams zuerst zu erstellen. So deute ich zumindest meinen Test, der einfach nur einen ObjectOutputStream erzeugt und sofort wieder schließt.
 
A

alex_Coding

hi,
vielen Dank für die schnellen Antworten...

Ich frage mich wie ich denn einfach einen ObjectOutputStream erzeuge, mit ObjectOutputStream oos= new ObjectOutputStream()
Hier kriege ich immer das Problem, dass ich Problem mit dem Konstruktor.

ObjectInputStream dis = new ObjectInputStream(s.getInputStream());
ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream());

Ich muss ja irgendwie auch den socket beim Erstellen des ObjectOutputStream mitgeben.
Wie hast du dir das denn gedacht bzw realisiert?

Danke nochmal
 
J

JustNobody

Einfach die beiden Zeilen sowohl im Client als auch im Server vertauschen:

ObjectInputStream dis = new ObjectInputStream(s.getInputStream());
ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream dis = new ObjectInputStream(s.getInputStream());
 
A

alex_Coding

haha krass, it's magic and it works...

Hammer Typ, Hammer Beitrag, Hammer Forum.

Spass bei Seite, vielen vielen Dank
Vielen Dank
 
L

LimDul

Das bestärkt mich übrigens in meiner Ansicht, dass Serialisierung und ObjectInput/OutputStreams evil sind. Das ein XXInputStream-Konstruktor, der nur einen anderen InputStream als Eingabe bekommt eine Blocking-Operation ist - das finde ich definitiv nicht intuitiv. Es ist zwar im JavaDoc dokumentiert, aber ich hab da nur geschaut, weil das anhand der Beschreibung und des Codes die einzige Stelle sein konnte, die blockiert. Aber da wäre ich ohne Dokumentation nie drauf gekommen.
 
J

JustNobody

Also erst einmal schön, dass jetzt alles klappt.

Und ja, ich gebe Dir voll und ganz Recht @LimDul. Aber das erinnert mich an eine Diskussion mit dem allwissenden Junior Developer oder Wissenschaftler oder was auch immer, der darin DIE Lösung sah. Alles Andere ist Müll :)

@alex_Coding Aber unabhängig von der Einschätzung, ist es hier natürlich explizit gefordert und zum Anderen ist das natürlich relativ trivial aufzubauen, so es nur um kurze Übungen geht.

Und was mir bei diesem Beispiel in den Sinn kommt: Ist die serialVersionUID von String (und anderen Framework Klassen) gleich über Versionen, Anbieter und Betriebssysteme? Also Oracle JDK vs. Zulu vs. AdoptOpenJDK, ... über dieverse Versionen (8,9, ..., 14) und OS (Windows 32/64 Bit, Linux, Mac, AIX, ...)... Muss ich das erst testen oder weiss das jemand durch Zufall?
 
F

fhoffmann

Ist die serialVersionUID von String (und anderen Framework Klassen) gleich über Versionen, Anbieter und Betriebssysteme?
Zumindestens in Code der Klasse String (von unterschiedlichen Versionen) habe ich folgenden Text gefunden
Java:
    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
Wäre ja auch ziemlich blöd, wenn man Strings nicht seialisieren könnte.
 
J

JustNobody

Danke für die Antwort.

Ich habe es auch eben einmal etwas getestet und auf dem Windows PC (Zulu Java 8, Adopt OpenJDK 11) sowie auf AIX (IBMs Java 8) kam immer genau diese Zahl...

Und ist auch tatsächlich logisch, denn man selbst legt bei sich ja auch die serialVersionUID fest und das würde ja nichts bringen, wenn die eigentlichen Klassen, auf denen man aufbaut, nicht auch feste Versionen hat. Also auch mit etwas Nachdenken war das eigentlich logisch ...
 
Thema: 

TCP multiClientServer mit socket mittels ObjectOutputStream

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben