Kadaj Geschrieben 19. November 2012 Geschrieben 19. November 2012 Hallochen, ich versuche grade eine Textdatei von einem client auf einen server zu schicken und diese dann vom server ausgeben zu lassen. Das hat auch soweit erstmal funktioniert, nur dass der Server die Umlaute nicht darstellen konnte. Ich hab mir den Abschnitt über Netzwerkprogrammierung in Java im Buch von Addison Wesley fertig durchgelesen und ausprogrammiert, leider fande ich das für so ein gewaltiges Thema recht wenig und ich habe bisher auch noch keine bessere Quelle / Buch gefunden, wo mehr darüber erklärt wird ( udp wurde zb ganz weggelassen :/ ) Jedenfalls habe ich nach einigen Beispielen gegoogelt, aber das hat mich nur zurückgeworfen, sodass ich dann beim Server nur noch eine Zeile bei der Ausgabe des Textes habe. Kann mir vielleicht jemand nochmal die Datenübertragung etwas näher bringen und vielleicht auch den Unterschied zu UDP? Erstmal hier meine beiden Klassen: TCP_Client import java.io.*; import java.net.*; public class TCP_Client { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader( new FileReader( "alice.txt" ) ); Socket clientSocket = new Socket("localhost",3000); OutputStream out = clientSocket.getOutputStream(); //DataOutputStream outToServer=new DataOutputStream(clientSocket.getOutputStream()); //BufferedReader inFromServer = new BufferedReader( new InputStreamReader( clientSocket.getInputStream())); LineNumberReader lnr = new LineNumberReader( br ); String line; while( ( line = lnr.readLine() ) != null ){ out.write(line.getBytes()); System.out.println( line ); } out.write('\r'); out.write('\n'); clientSocket.close(); br.close(); //sentence = inFromUser.readLine(); // blockiert /*byte[] buffer = new byte[1024]; while(fileIn.available() > 0){ outToServer.write(buffer,0,fileIn.read(buffer)); }*/ } } [/PHP] TCP_Server [PHP] import java.io.*; import java.net.*; public class TCP_Server { public static void main(String[] args)throws Exception { String clientSentence; //String capitalizedSentence; ServerSocket welcomeSocket = new ServerSocket(3000); while(true){ Socket connectionSocket = welcomeSocket.accept(); // wartet auf Verbindung vom Client // danach geht es weiter InputStream in = connectionSocket.getInputStream(); // Eingangs-Stream vom Socket holen //BufferedReader inFromClient = new BufferedReader( new InputStreamReader( connectionSocket.getInputStream())); // Stream für Ausgang aufbauen //DataOutputStream outToClient = new DataOutputStream( connectionSocket.getOutputStream() ); byte[] buffer = new byte[1024]; // byte zur Übertragung von Daten int c; while( connectionSocket.isConnected() ){ c = in.read(buffer); if(c==-1) break; System.out.write( buffer,0,c ); } /* while( (len = in.read(buffer) ) != -1) { System.out.write(buffer,0,len); } while( true ){ clientSentence = in.readLine(); System.out.println(clientSentence); } */ in.close(); connectionSocket.close(); } } } Wäre super, wenn mir jemand erklären könnte warum keine der auskommentierten Varianten beim Server funktioniert. Wenn ich beispielsweise System.out.println( buffer.toString() ); beim Server verwende, dann bekomme ich ne ganze Menge davon:[B@213214d1 [B@213214d1 [B@213214d1 [B@213214d1 [B@213214d1 [B@213214d1 [B@213214d1 Ist mir schon etwas schleierhaft ... Zitieren
Gast runtimeterror Geschrieben 19. November 2012 Geschrieben 19. November 2012 Über Netzwerke werden immer Bytes übertragen und keine Zeichen. Bei der Umwandlung von Zeichenketten (String) in Byte-Folgen (byte[]) und umgekehrt muss immer ein Charset angegeben werden, welches die Regeln der Umwandlung beschreibt. Die von dir verwendeten Methoden machen dies implizit immer mit dem Default-Charset der jeweiligen JVM - welches je nach Mondstand ein anderes sein kann. Verwenden Server und Client unterschiedliche Charsets, so macht sicht dies meist bei den Umlauten bemerkbar. Statt: BufferedReader br = new BufferedReader( new FileReader( "alice.txt" ) ); Besser: BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("alice.txt"), Charset.forName("UTF-8"))); Oder: private static final CHARSET = Charset.forName("UTF-8") BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("alice.txt"), CHARSET)); Oder (ab Java 7): BufferedReader br = Files.newBufferedReader(new File("alice.txt").toPath(), CHARSET) Die toString-Methode gibt dir für byte-Arrays ein Objekt-Handle aus. Java kann nicht wissen, dass die darin enthaltenen Bytes lesbaren Text darstellen sollen. Statt: System.out.println( buffer.toString() ); Meinst du vermutlich: System.out.println( new String(buffer) ); Oder besser: System.out.println( new String(buffer, 0, c, CHARSET) ); > Wäre super, wenn mir jemand erklären könnte warum keine der auskommentierten Varianten beim Server funktioniert. Hier würde ich dich bitten genauer zu beschreiben, welche der zahllosen auskommentierten Bereiche welche Probleme verursachen. Zitieren
Kadaj Geschrieben 20. November 2012 Autor Geschrieben 20. November 2012 Danke dir, die Zeile System.out.println( new String(buffer) ); [/PHP] ist ne Magie, die ich bisher auch noch nicht kannte. Das funktioiert auch auf Serverseite ;-) Allerdings hab ich den Client jetzt so, da mir gesagt wurde, dass es besser sei die Bytes direkt zu lesen und zu schicken, also ohne BufferedReder etc, weil sonst Konvertierungen vorgenommen werden, die Ergebnis verfälschen könnten? Allerdings leuchtet mir das nicht ganz ein, da der bufferedReader doch nur bytes puffert bevor er sie rausschiebt, oder? [PHP] FileInputStream fis = new FileInputStream("alice.txt"); Socket clientSocket = new Socket("localhost",3000); OutputStream out = clientSocket.getOutputStream(); byte[] buffer = new byte[1024]; while( fis.read( buffer ) != -1 ){ out.write(buffer); } Zitieren
Gast runtimeterror Geschrieben 20. November 2012 Geschrieben 20. November 2012 Falls die Forderung ist, die Textdatei unverändert zu übertragen (also Binär identisch), dann darfst du tatsächlich keinen Reader oder Writer einsetzen. Diese arbeiten ausschließlich auf Zeichen-Ebene (also auf interpretierten Bytes). Byte <-> Zeichen InputStream <-> Reader OutputStream <-> Writer BufferedInputStream <-> BufferedReader BufferedOutputStream <-> BufferedWriter Ein kurzer Blick in die Java-Docs zu diesen Klassen dürfte auch ein wenig Klarheit bringen. Wenn es nach mir ginge dürfte es keine Methode geben, die die Umwandlung zwischen byte[] und String erlaubt, ohne dass ein explizites Charset angegeben wurde. Das machen einfach zu viele falsch. Zitieren
Kadaj Geschrieben 21. November 2012 Autor Geschrieben 21. November 2012 Byte <-> Zeichen InputStream <-> Reader OutputStream <-> Writer BufferedInputStream <-> BufferedReader BufferedOutputStream <-> BufferedWriter Danke! Einleuchtend auf einem Blick, kommt gleich an mein Whiteboard ;-) Ich wusste nicht, dass die Datei dadurch beim übertragen verändert werden kann. Ist das etwa gewollt? Zitieren
Gast runtimeterror Geschrieben 21. November 2012 Geschrieben 21. November 2012 Es werde nur Bytes übertragen - dort findet keine Umwandlung statt. Die Umwandlung ist dir beim Auslesen der Datei passiert. Was du gemacht hast: Bytes (aus Datei) -> Reader -> String -> getBytes -> Bytes -> Übertragung -> Bytes -> Reader -> String Was besser ist: Bytes (aus Datei) -> Übertragung -> Bytes -> Reader -> String Immer wenn Bytes in String umgewandelt werden (oder umgekehrt) finden Veränderungen statt. Das liegt daran, dass sich durch Bytes alles übertragen lässt, durch Text jedoch nicht. Versuche immer alles was schon als Bytes vorliegt so lange zu lassen, wie nötig. Zitieren
Kadaj Geschrieben 22. November 2012 Autor Geschrieben 22. November 2012 (bearbeitet) Gut zu wissen, aber mal was anderes. Unabhängig davon ob ich nun tcp oder udp nehme; angenommen ich packe Daten, die nicht über den header mitgesendet werden können mit in mein erstes Paket bzw. in jedes mit rein. Sei es beispielsweise ein Dateiname. Natürlich kann ich auch das erste Paket nur mit dem Namen ausstatten und losschicken, aber wenn ich Daten mit im Paket habe und diese dann beim auslesen trennen möchte, wie könnte man dann vorgehen? Mein erster Gedanke wäre einfach einen int am Anfang des Paketes zu stecken für die Anzahl Zeichen des Strings, dann die Anzahl Zeichen für den Name der Datei auslesen und den Rest normal als Daten behandeln. Würde das funktionieren? Wenn ich mir ein byte in Größe eines int erstelle und erst damit receive aufrufe, was passiert bei einem weiteren Aufruf von receive? Steht der Zeiger dann wieder am Anfang oder nach dem int? Die Zusammensetzung der Pakete bzw Header ist mir noch etwas schleierhaft. Mit Funktionen wie getAddress() oder getPort() hole ich mir Daten aus dem Header, alles weitere muss ich also in den Datenteil packen? Gruß Bearbeitet 22. November 2012 von Kadaj Zitieren
Kadaj Geschrieben 23. November 2012 Autor Geschrieben 23. November 2012 Hat sich erledigt; schon ne dumme Frage, wenn man es versteht^^ Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.