tutorials.de Buch-Aktion 05/2012
Like Tree2Danke
  • 1 Beitrag von gorefest
  • 1 Beitrag von gorefest
ERLEDIGT
NEIN
ANTWORTEN
11
ZUGRIFFE
328
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Kai008 Kai008 ist offline Mitglied Brillant
    Registriert seit
    May 2008
    Ort
    Brunn/Geb. (Niederösterreich)
    Beiträge
    944
    Blog-Einträge
    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. :)

  2. #2
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    nur mal eine zwischenfrage ... ist das java-zu-java-kommunikation?

    wenn ja, warum machst du nicht rmi/jrmp?

    grüße
    gore
     

  3. #3
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    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
    Kai008 bedankt sich. 

  4. #4
    Kai008 Kai008 ist offline Mitglied Brillant
    Registriert seit
    May 2008
    Ort
    Brunn/Geb. (Niederösterreich)
    Beiträge
    944
    Blog-Einträge
    1
    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. :)

  5. #5
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    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
    Kai008 bedankt sich. 

  6. #6
    Kai008 Kai008 ist offline Mitglied Brillant
    Registriert seit
    May 2008
    Ort
    Brunn/Geb. (Niederösterreich)
    Beiträge
    944
    Blog-Einträge
    1
    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. :)

  7. #7
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    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.
     

  8. #8
    Kai008 Kai008 ist offline Mitglied Brillant
    Registriert seit
    May 2008
    Ort
    Brunn/Geb. (Niederösterreich)
    Beiträge
    944
    Blog-Einträge
    1
    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.
    Angehängte Dateien Angehängte Dateien
     
    Mein kleiner webstart Projektplaner:
    http://178.77.101.236/ppws/
    Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.

    Danke. :)

  9. #9
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    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
     

  10. #10
    Kai008 Kai008 ist offline Mitglied Brillant
    Registriert seit
    May 2008
    Ort
    Brunn/Geb. (Niederösterreich)
    Beiträge
    944
    Blog-Einträge
    1
    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.gif
     
    Mein kleiner webstart Projektplaner:
    http://178.77.101.236/ppws/
    Ideen, Verbesserungsvorschläge, Bugsmeldungen und allg. Kritik erwünscht und erbeten.

    Danke. :)

  11. #11
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    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?
     

  12. #12
    Kai008 Kai008 ist offline Mitglied Brillant
    Registriert seit
    May 2008
    Ort
    Brunn/Geb. (Niederösterreich)
    Beiträge
    944
    Blog-Einträge
    1
    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

  1. List<String>
    Von Cäptin Pommes im Forum C/C++
    Antworten: 19
    Letzter Beitrag: 26.05.10, 08:10
  2. PrintWriter zu String
    Von LordDarkness im Forum Java
    Antworten: 7
    Letzter Beitrag: 22.10.09, 14:36
  3. UTF-8 Url mit Printwriter schreiben
    Von SeeSharpNewBee im Forum Enterprise Java (JEE, J2EE, Spring & Co.)
    Antworten: 0
    Letzter Beitrag: 13.06.07, 18:44
  4. Antworten: 2
    Letzter Beitrag: 04.09.06, 12:07
  5. Antworten: 4
    Letzter Beitrag: 23.08.04, 11:35