2Danke
ERLEDIGT
NEIN
NEIN
ANTWORTEN
11
11
ZUGRIFFE
328
328
EMPFEHLEN
-
23.03.10 20:00 #1
Ich verwende zum Kommunizieren über Sockets meistens die Object-I/O-Streams. Jetzt versuche ich wieder davon wegzukommen, weil ich gemerkt habe, dass die echt langsam sind. Außerdem fliegen oft (scheinbar grundlos) Exceptions. Selbst ein 2-Byte-langer String kommt erst mit (grob geschätzt) einer viertel Sekunde Verzögerung an, was man natürlich deutlich merkt. Deshalb habe ich die Klasse umgeschrieben, um sie per PrintWriter/BufferedReader zu schreiben/lesen und rekonstruieren. Nichts besonderes, aber kann ich trotzdem eure Meinung darüber haben? Und event. Verbesserungsvorschläge, was mir weiter helfen könnte, oder die Geschwindigkeit event. weiter steigert?
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
package core; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; public class Command implements CommanandConstants { private static final int BUFFER_LENGHT = 2048; private static final char[] BUFFER = new char[BUFFER_LENGHT]; private static Map<Socket, PrintWriter> writerMap; private static Map<Socket, BufferedReader> readerMap; private String command; private String location; private List<String> parameterList; static { writerMap = new HashMap<Socket, PrintWriter>(); readerMap = new HashMap<Socket, BufferedReader>(); } public Command(String command, String location) { super(); this.command = command; this.location = location; } private Command(String readedData) { super(); String[] split = Pattern.compile(";").split(readedData, 0); command = split[0]; location = split[1]; parameterList = new ArrayList<String>(); for(byte b = 2; b < split.length; b++) parameterList.add(split[b]); } public void sendAboutSocket(Socket socket) { PrintWriter printWriter = writerMap.get(socket); if(printWriter == null) { try { printWriter = new PrintWriter(socket.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } writerMap.put(socket, printWriter); } printWriter.write(toString()); printWriter.flush(); } public boolean hasCommand(String s) { return(command.equals(s)); } public boolean hasLocation(String s) { return(location.equals(s)); } public String toString() { String asString = command + ";" + location + ";"; if(parameterList != null) for(byte b = 0; b < parameterList.size(); b++) asString+= parameterList.get(b) + ";"; return(asString); } public String getParameter(int i) { String parameter = null; if(parameterList == null) parameter = parameterList.get(i); return(parameter); } public static Command readFromSocket(Socket socket) { BufferedReader bufferedReader = readerMap.get(socket); if(bufferedReader == null) { try { bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (IOException e) { e.printStackTrace(); } readerMap.put(socket, bufferedReader); } Command command = null; try { int charCount = bufferedReader.read(BUFFER, 0, BUFFER.length); String commandAsString = String.valueOf(BUFFER, 0, charCount); command = new Command(commandAsString); } catch (SocketException e) {} catch (IOException e) { e.printStackTrace(); } return(command); } public synchronized void addParameter(String parameter) { if(parameterList == null) parameterList = new ArrayList<String>(); parameterList.add(parameter); } }
Mein kleiner webstart Projektplaner:
http://178.77.101.236/ppws/
Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.
Danke. :)
-
nur mal eine zwischenfrage ... ist das java-zu-java-kommunikation?
wenn ja, warum machst du nicht rmi/jrmp?
grüße
gore
-
Performancetechnisch fällt mir folgendes auf :
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
private Command(String readedData) { super(); String[] split = Pattern.compile(";").split(readedData, 0); command = split[0]; location = split[1]; parameterList = new ArrayList<String>(); for(byte b = 2; b < split.length; b++) parameterList.add(split[b]); } sowie public String toString() { String asString = command + ";" + location + ";"; if(parameterList != null) for(byte b = 0; b < parameterList.size(); b++) asString+= parameterList.get(b) + ";"; return(asString); }
1. mach nicht jedesmal einen patterncompile -> kostet zeit
1a) mach ein new arraylist(split.length), sonst wird immer wieder neu alloziiert
2. nimm einen stringbuilder statt "+" konkatenation bei strings, dito
-
24.03.10 11:57 #4
Danke, aber ich wollte hauptsächlich die Verbindunggeschwindigkeit verbessern, Prozessormäßig hatte ich nur selten Probleme.
Ich nehme an, der StringBuilder ist so richtig verwendet, oder?
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
public String toString() { StringBuilder builder = new StringBuilder(); builder.append(command); builder.append(";"); builder.append(location); builder.append(";"); if(parameterList != null) for(byte b = 0; b < parameterList.size(); b++) { builder.append(parameterList.get(b)); builder.append(";"); } return(builder.toString()); }
Ist Java-2-Java, aber bei einen Remote Methoden-Aufruf per RMI müssen die Klassen der Parameter wieder serialisiert werden, was das selbe Geschwindigkeitsproblem mit sich bringen würde, oder? So habe ich einen Server, der in einem Thread ließt, die Änderungen prüft/durchführt, eventuell eine Antwort sendet und wieder am Schleifenanfang zurückkehrt.Mein kleiner webstart Projektplaner:
http://178.77.101.236/ppws/
Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.
Danke. :)
-
mmm
machst Du Java NIO ?
Wenn ja, solltest Du mal die Sleeptime Deines Acceptorthreads prüfen, sprich der Thjread deines Servers, der beim Eingang einer Verbindung reagiert. Alles was wir hier je mit RMI gemacht haben, war im übrigen sauschnell.
Grüße
gore
-
24.03.10 12:31 #6
Nein, NIO habe ich nur einmal mit FileChannel für ein Backup-Programm benutzt. Um die Verbindung anzunehmen verwende ich ServerSocket.accept(), und dieser und der BufferedReader blockieren den Thread, bis was reinkommt. Deshalb schläft der Server (von mir aus) nie.
Wenn RMI wirklich so schnell ist, werde ich es mir mal anschauen. Vielen Dank für deine Hilfe.Mein kleiner webstart Projektplaner:
http://178.77.101.236/ppws/
Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.
Danke. :)
-
stimmt, das socket.accept() habe ich übersehen.
Ich könnte mir vorstellen, dass Dein StreamWriter lahm ist. Da du ja Strings hast, kannst Du die doch direkt mittels byte[] transporieren. Sollte auf jeden Fall en. Du kannst afaik auch einen ObjectStream nehen - schau mal unter
java.io.ObjectInputStream;
java.io.ObjectOutputStream;
java.io.OutputStream;
Dann kannst Du das Zeug auch direkt in Objectform streamen, was RMI letztendlich auch macht.
-
24.03.10 13:33 #8
Ja, aber dann müsste ich dem String zu bytes und wieder zurückwandeln.
Die ObjectStreams waren der Grund, warum ich die Klasse so versenden will.
Ich habe das Projekt mal hochgeladen, falls du irgendwann zwischendurch mal kurz Zeit findest.
Beim Applet ist eigendlich nur core.loginscreen.game.surfaceGame.SurfaceKeyPanel wichtig, das macht in der keyPressed/Released aus dem momentanen Status und der gedrückten Taste den neuen Status und sendet ihm serialisiert am Server.
Dort wird es von core.client.Client empfangen, er führt die core.client.ParseGame.parse(Command, Client) aus, und verteilt in der sendClientStat(Command, Client) das Objekt an alle Clients auf der Karte.
core.loginscreen.game.surfaceGame.WaitForIncomingCommandsThread empfängt dieses am Applet und setzt dem jeweiligen Spieler auf dem Status, damit er sich bewegt
Wenn man den localhost oder eine IP, die auf ihm zeigt verwendet, läuft alles ziemlich gut. Wenn man die Internet-IP verwendet (in core.Applet in einer Konstanten) merkt man schon beim ersten Tastendruck eine deutliche Verzögerung.Mein kleiner webstart Projektplaner:
http://178.77.101.236/ppws/
Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.
Danke. :)
-
Hast Du mal versucht, die einzelnen Schritte mit millisekunden zu messen?
Du kannst das indem Du Dir über new Date().getTimeInMillis() eine aktuelle Uhrzeit holst. Dann kannst Du messen, wo innerhalb Deiner Versendefunktion der Engpass ist.
Die Verbindung zu localhost ist selbstverständlich deutlisch schneller, da sie keinen Umweg über die Netzwerkkarte nimmt.
Grüße
gore
-
24.03.10 14:37 #10
Ich weiß, dass die "äußere IP" langsamer ist, das Internet ist vergleichsweiße (zumindest in unserem Raum) ja auch ein echt langsames Netzwerk
Argh, auf die Zeitmessung wäre ich echt nicht so schnell gekommen. x_x"
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Keypanel Start: 1269436619906 Keypanel sende Command: 1269436619906 Keypanel sende Command beendet: 1269436619906 Keypanel Start: 1269436620406 Keypanel sende Command: 1269436620406 Keypanel sende Command beendet: 1269436620406 Keypanel Start: 1269436620937 Keypanel Start: 1269436620984 Keypanel Start: 1269436621015 Keypanel Start: 1269436621046 Keypanel Start: 1269436621093 Keypanel Start: 1269436621124 Keypanel Start: 1269436621156 Keypanel Start: 1269436621203 Keypanel Start: 1269436622062 Keypanel sende Command: 1269436622062 Keypanel sende Command beendet: 1269436622062 Keypanel Start: 1269436622937 Keypanel sende Command: 1269436622937 Keypanel sende Command beendet: 1269436622937 Keypanel Start: 1269436623906 Keypanel sende Command: 1269436623906 Keypanel sende Command beendet: 1269436623906
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Applet status empfangen: 1269436620234 Status gesetzt: 1269436620234 Applet status empfangen: 1269436620437 Status gesetzt: 1269436620437 Applet status empfangen: 1269436620640 Status gesetzt: 1269436620640 Applet status empfangen: 1269436621640 Status gesetzt: 1269436621640 Applet status empfangen: 1269436622453 Status gesetzt: 1269436622453 Applet status empfangen: 1269436622656 Status gesetzt: 1269436622656 Applet status empfangen: 1269436623249 Status gesetzt: 1269436623249 Applet status empfangen: 1269436623656 Status gesetzt: 1269436623656 Applet status empfangen: 1269436624359 Status gesetzt: 1269436624359 Applet status empfangen: 1269436624859 Status gesetzt: 1269436624859
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Server: Beginne verteilen 1269436620031 Verteilen beendet: 1269436620031 Server: Beginne verteilen 1269436620234 Verteilen beendet: 1269436620234 Server: Beginne verteilen 1269436620437 Verteilen beendet: 1269436620437 Server: Beginne verteilen 1269436621437 Verteilen beendet: 1269436621437 Server: Beginne verteilen 1269436622249 Verteilen beendet: 1269436622249 Server: Beginne verteilen 1269436622453 Verteilen beendet: 1269436622453 Server: Beginne verteilen 1269436623046 Verteilen beendet: 1269436623046 Server: Beginne verteilen 1269436623453 Verteilen beendet: 1269436623453 Server: Beginne verteilen 1269436624062 Verteilen beendet: 1269436624062 Server: Beginne verteilen 1269436624562 Verteilen beendet: 1269436624562
Code :1 2 3 4
Errechne neuen Status: 0 ms. Senden/Empfangen des Status: 125 ms. (Ziemlich verschätzt, ist nur eine achtel Sekunde Verzögerung.) An alle User senden: 0 ms. (Das eigendliche senden rennt wohl in einen anderen Thread weiter.) Zeit zwischen senden des Servers und empfangen: 203 ms.
Es kostet eigendlich nichts außer der O-I/O-S Zeit.
Und das merkt man schon recht deutlich: http://www.imagebanana.com/view/le497wud/Video.gifMein kleiner webstart Projektplaner:
http://178.77.101.236/ppws/
Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.
Danke. :)
-
ich glaube, dass das vorrangig daran liegt, dass du afaik tcp verwendest und immer wieder einen neuen socket aufmachst.
versuch doch mal UDP pakets zu schicken und lass dabei sender und empfänger in eigenen threads laufen. btw, hast du irgendwas synchronized im applet?
-
26.03.10 11:34 #12
Ich kenne mich mit DatagramSockets eigendlich nicht aus. Ich weiß, dass UDP grundsätzlich schneller ist, aber ist es nicht so, das dabei Datenpakete nicht umbedingt ankommen? Das wäre natürlich auch nicht so gut. Eine Verbindung wird nur beim Start des Applets aufgebaut, und danach wird diese weiter verwendet.
Mein kleiner webstart Projektplaner:
http://178.77.101.236/ppws/
Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.
Danke. :)
Ähnliche Themen
-
List<String>
Von Cäptin Pommes im Forum C/C++Antworten: 19Letzter Beitrag: 26.05.10, 08:10 -
PrintWriter zu String
Von LordDarkness im Forum JavaAntworten: 7Letzter Beitrag: 22.10.09, 14:36 -
UTF-8 Url mit Printwriter schreiben
Von SeeSharpNewBee im Forum Enterprise Java (JEE, J2EE, Spring & Co.)Antworten: 0Letzter Beitrag: 13.06.07, 18:44 -
PHP String für Javascript String Escapen. (String über mehrere Zeilen)
Von Lukasz im Forum PHPAntworten: 2Letzter Beitrag: 04.09.06, 12:07 -
Auf list in einer anderen Klasse zugreifen
Von TomSto im Forum JavaAntworten: 4Letzter Beitrag: 23.08.04, 11:35





Zitieren
Login





