# Socket Performance erhöhen?



## nambrot (21. Mai 2008)

Hi
ich habe leider keinen passenderen Titel finden können.
Was ich will ist kontinuierlich Daten zu meinem Server zu schicken. Diese soll er verwerten und damit die Maus bewegen.  Da es sich um eine Maus handelt sollte die Bewegung auch flüssig verlaufen, deshalb schicke ich die Daten von meinem Client mit ca 50 - 100 ms zwischen jedem Senden.
Wenn ich allerdings die Zeit messe zwischen den Mausbewegungen so kann ich nur einen Abstand von 200 ms messen.
Wie kann ich meinen Server also noch verbessern?
NewIO Libs? MultiThreading?
Ich habe keine Ahnung:
Hier der Code, ich hoffe ihr könnt mir helfen.

```
import java.awt.*;
import java.net.*;
import java.awt.event.*;
import java.io.*;
import java.io.IOException; 
public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args)
		throws AWTException,IOException{
		int pozX;
		int pozY;
	    long startzeit = System.currentTimeMillis();
	    long endzeit;
		Robot robot = new Robot();
		try {
		    ServerSocket serverSocket = new ServerSocket(3258);
		    while(true) {                              
		    	Socket client_socket = serverSocket.accept();
		    	System.out.println(client_socket);
		    	client_socket.setTcpNoDelay(true);
		                   
		        while(true){
		        	BufferedReader bufferedReader = 
		                new BufferedReader(
		                    new InputStreamReader(
		                        client_socket.getInputStream()));
		            pozX = MouseInfo.getPointerInfo().getLocation().x;
				    pozY = MouseInfo.getPointerInfo().getLocation().y;
				    String line = bufferedReader.readLine();
				    String[] results = line.split("<"); 
				    int newX = 1024/2 - Integer.parseInt(results[0]);
				    int newY = 768/2 - Integer.parseInt(results[1]);		    
				    robot.mouseMove(pozX+newX/4,pozY-newY/4);
				    System.out.println(line);
				    endzeit = System.currentTimeMillis();
				    System.out.println(endzeit-startzeit+" ms" );
				    startzeit = System.currentTimeMillis();
			    }
		      
		    }
		} catch (IOException e) {
		    System.out.println("Could not listen on port: 3258");
		    System.exit(-1);
		}
	}

}
```


----------



## Chefkoch333 (22. Mai 2008)

Hi,
probiere doch mal ganze doch mal ohne BufferedReader/Writer aus. Dies könnte evtl. was bringen!?


----------



## zeja (22. Mai 2008)

Wieso erstellt du z.B. in der inneren while-Schleife immer wieder nen neuen Reader?


----------



## nambrot (22. Mai 2008)

hey
das mit dem reader stimmt, da war ich wohl sonst wo.
Natürlich sollte man den nur einmal generieren.
Ich hab den dann außerhalb der while schleife gepackt.
Auch die außerste Wihle schleife ist sinnlos, aber sowas merkt man immer nur hinterher^^
Ein Problem dass ich habe ist dann aber, dass er durch die immer wahrheit der inneren Whileschleifen auch versucht zu lesen, obwohl noch kein neues Paket angekommen ist und ich dadurch zu null schleifen komme.
Und wieso soll ich den Reader rausnehmen?
dann kan nich doch nichts lesen.


----------



## Chefkoch333 (22. Mai 2008)

Klar einen reader brauchst du, ist nur die Frage ob er unbedingt buffered sein muss.


----------



## nambrot (22. Mai 2008)

oh, ich wusste gar nicht, dass man auch ohne Buffern machen kann.
Was ist denn der Vorteil daran? Kann man dann überhaupt noch die einzelnen Pakete lesen?


----------



## Chefkoch333 (23. Mai 2008)

Buffered hat den Vorteil das nicht jedes Byte einzeln gelesen wird sondern immer ein ganzer Block. Beim Aufruf der read Methode muss dann nicht jedes mal erneut auf das zu lesende Medium zugegriffen werden sondern es kann die Information aus dem Buffer gelesen werden. Dies hat dann einen Geschwindigkeitsvorteil beim Zugriff z.B. beim lesen.
Beim nicht 'gebufferten' lesen wird jedes Byte einzeln von der HD gelesen.
Nun könnte ich mir vorstellen das in deinem Fall ein ungepuffertes Lesen und Schreiben evtl. schneller sein könnte da du ja sofort auf den ankommenden Datenstrom reagieren willst, und nicht erst warten willst bis der Buffer gefüllt ist um mit der Weiterverarbeitung fortzufahren.
Aber wie gesagt, ich bin mir nicht sicher ob es wirklich was bringt. Versuche es doch einfach mal aus, ist ja keine große Änderung. Das Ergebniss würde mich auch interessieren.


----------



## nambrot (23. Mai 2008)

hey
das hört sich sehr logisch an
das PRoblem:

Reader bufferedReader = new Reader(new InputStreamReader(client_socket.getInputStream()));

verursacht den Fehler:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Cannot instantiate the type Reader

	at Test.main(Test.java:23)
außerdem gibt read() ja dann nur irgendwelche int zahlen aus. Ich weiß ja gar nicht wie ich diese verwerten soll.


----------



## zeja (24. Mai 2008)

Wenn du mal in der API schaust siehst du das Reader ein Interface ist und InputStreamReader dieses Interface schon implementiert.

Das was du da zurückbekommst sind bytes. Besser ist es aber das ganze in ein Byte-Array einzulesen. Das ByteArray kannst du z.B. in einen ByteBuffer stecken und darüber auslesen.

Problem bei nem BufferedReader mit readLine ist, dass er bis zu einem Zeilenumbruch liest. Eigentlich willst du aber keinen machen denke ich mir....


----------



## nambrot (24. Mai 2008)

Hey danke, ich hab mich schon gewunder wozu es die KLasse Reader gibt.
ICh hab also daraus nen InputStreamReader ohne Buffered Reader gemacht, kommt mir aber nicht wirklich schneller vor:
Ich denke einfach mal das Parsen dauert viel zu lange. Und während er parst kommen schon die nächsten Pakete die die while schleife verpasst. Ich muss wohl auf New IO umsteigen?

```
InputStreamReader bufferedReader = new InputStreamReader(client_socket.getInputStream());

		    	//BufferedReader newReader = new BufferedReader()
		        while(true){
		        	//BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client_socket.getInputStream()),30);
		        	
		            pozX = MouseInfo.getPointerInfo().getLocation().x;
				    pozY = MouseInfo.getPointerInfo().getLocation().y;
				    //System.out.println(bufferedReader.getEncoding());
				    char[] array1 = new char[8];
				    int line = bufferedReader.read(array1);
				    String nachricht = new String(array1, 0, line);
				    System.out.println(nachricht);
				    String[] results = nachricht.split("<"); 
				    int newX = 1024/2 - Integer.parseInt(results[0]);
				    int newY = 768/2 - Integer.parseInt(results[1]);
```


----------



## zeja (24. Mai 2008)

Also verpassen tust du auf keinen Fall was. Bist du es nicht rausliest bleiben die Daten eigentlich im Stream.

Ich frage mich nur gerade warum du das was du liest erst in einen String umwandelst?

Schreib doch einfach nur die Zahlen in den Stream und gut ist:
S1020

S wäre quasi nen Startpunkt damit du nicht falsch liest. Danach folgen einfach beide Ints.

Auslesen dann mit:

```
InputStream in = client_socket.getInputStream();
byte [] b = new byte[(Integer.SIZE/Byte.SIZE)*2 + Character.SIZE/Byte.SIZE];//hoffe das reicht an Größe
ByteBuffer buf = ByteBuffer.wrap(b);
char c = buf.getChar();
//prüfe ob dies dass Start-Zeichen ist
int x = buf.getInt();
int y = buf.getInt();
```

Oder du verwendest direkt nen DataOutputStream und DataInputStream..


```
DataInputStream in = new DataInputStream(client_socket.getInputStream());
char c = in.readChar();
//prüfe ob dies dass Start-Zeichen ist
int x = in.readInt();
int y = in.readInt();
```


----------



## nambrot (24. Mai 2008)

hey, danke für den Lösungsvorschlag. Ich hab noch ein paar Fragen:
mein Client ist nicht in Java geschrieben, deshalb kann ich den send() befehl auch nicht so einfach modifizieren, soweit ich das sehe, sendet der Client nämlich in String, deshalbdas konverten String. Ich werd aber deinen Vorschlag auf jeden Fall ausprobieren.
Brauche ich eigentlich ein Startzeichen, wenn es immer gleich abgesenet wid?
Wie soll ich byte verstehen?


----------



## nambrot (24. Mai 2008)

hey
ich habs grad mal probiert, ich weiß aber gar nicht, wohin ich die Befehle genau machen soll
ich hab das so gemacht:

```
InputStreamReader bufferedReader = new InputStreamReader(client_socket.getInputStream());
		    	
		    	byte [] b = new byte[2048];//hoffe das reicht an Größe
		    	
		    	//BufferedReader newReader = new BufferedReader()
		        while(true){
		        	//BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client_socket.getInputStream()),30);
		        	ByteBuffer buf = ByteBuffer.wrap(b);
		        	int x = buf.getInt();
		        	System.out.println(x);
```
Ich bekomm aber immer nur 0 zurück, ich send auch nur einen Int Wert.
Wo wird der buffer eigentlich dem Inputstream zugewiesen?


----------



## nambrot (25. Mai 2008)

hey, ich hab mal ne frage, wär es nicht schneller, wenn man nicht parseInt machen würde, sondern eine indivduelle select abfrage?
Also select
case string="0" then int=0
also für die Zahlen 1-1000 sowas machen?
Hört sich lang an, aber sollte doch schneller sein als parseInt oder?


----------



## zeja (25. Mai 2008)

Nein das ist auf keinen Fall schneller...

Die Lösung wie es schnell ist habe ich dir im Prinzip gegeben. Versuch doch mal ernsthaft das zu verstehen und einzubauen.


----------



## nambrot (25. Mai 2008)

habe ich doch probiert, das Problem ist, dass ich beim Client immer nur als String senden kann, und deswegen nicht beim Server als Int lesen kann.
Deshalb bekomme ich auch immer nur die 0 zurück.
Edit:
In hab mal ein wenig gegoogelt, und es gibt einen fall wo es um 50 % schneller war.


----------



## Looky (6. August 2008)

bei sowas würde ich immer eine udp verbindung. wenn du ein telegramm verlierst,  drauf, aber DAS ist wirklich schnell


----------

