# Java Internetserver



## scaary (28. Sep 2009)

Hi.
Ich habe mich jetzt mal auf vollkommenes Neuland begeben und mit der Programmierung eines kleinen Servers "begonnen" (eigentlich hab ich nur das Beispiel eines Buches durchgearbeitet, damit ich erstmal ein Verstaendnis fuer die Materie erhalte).

Hier die Seite:

Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 19.3 Auf der Serverseite

Die Idee dahinter, eine Entfernte Methode so zu nutzen, als ob sie Lokal waer, gefaellt mir sehr gut!

Jetzt hab ich nur noch eine Frage zu folgendem Code:

SERVER

```
package Testserver;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry; 
import java.rmi.server.RemoteServer; 
import java.rmi.server.UnicastRemoteObject; 

public class Server { 
	public static void main( String[] args ) throws RemoteException 
	{ 
		LocateRegistry.createRegistry( Registry.REGISTRY_PORT ); 

		AdderImpl adder = new AdderImpl(); 
		Adder stub = (Adder) UnicastRemoteObject.exportObject( adder, 0 ); 
		RemoteServer.setLog( System.out ); 

		Registry registry = LocateRegistry.getRegistry(); 
		registry.rebind( "Adder", stub ); 

		System.out.println( "Adder angemeldet" ); 
	} 
}
```

CLIENT

```
package Testserver;

import java.rmi.NotBoundException; 
import java.rmi.RemoteException; 
import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry; 
 
public class Client 
{ 
  public static void main( String[] args ) throws  RemoteException, NotBoundException 
  { 
    Registry registry = LocateRegistry.getRegistry(); 
    Adder adder = (Adder) registry.lookup( "Adder" ); 
    System.out.println( adder.add( 46, 115 ) ); 
  } 
}
```

Wo genau geb ich dann meine URL ein, wo der Client drauf zugreifen soll (also www.wasweissich.de)?

Einer von den beiden muss die doch kriegen!

Ich geh mal davon aus, dass ich die dem CLient uebergeben muss, und der server das ganze durch ein einfach portforwarding weitergeleitet bekommt, gell?

Danke!


----------



## tuxedo (28. Sep 2009)

RMi, Portforwarding etc... Sehr böse. Geht prinzipiell, aber kann große Probleme machen.

Aber mal davon abgesehen: Die URL (kein "www . xyz . de" sondern das was die die Java-Insel vorschreibt: rmi:// ...) musst du bei "lookup()" angeben. Aber das sollte auch in der Insel stehen.

RMI "Hello World" Beispiele gibts zu hauf im Netz und auch hier im Forum. Einfach mal googeln.

- Alex


----------



## scaary (28. Sep 2009)

Ahh, ok, vielen Dank.

Jetzt weiss ich zumindest wonach ich suchen muss!

Also sprich, ich muss mir keine eigene Adresse zulegen, sondern der Server meldet sich selbststaendig im Internet mit einer von mir vorgegebenen adresse an?

Steht bestimmt auch in der Insel und ich habs nur ueberlesen.

Ich lerne leider nicht so gut aus buechern, sondern such mir meistens ein Beispiel und nehm das auseinander.

Danke ^^


----------



## scaary (28. Sep 2009)

Wenn ich den dann nochmal ei ne Frage stellen darf;

Ist es richtig, dass sowohl Server als auch Client die Classe benoetigen die die Methode zum ausfuehren der (z.B.) Berechnung benoetigt?

Braeuchten also beide diese Klasse:


```
import java.rmi.Remote; 
import java.rmi.RemoteException; 
 

public interface Adder extends Remote { 
  int add( int x, int y ) throws RemoteException; 
}
```

Und zusaetzlich braucht der Server noch das Interface des adders, richtig?


----------



## tuxedo (28. Sep 2009)

Umgekehrt. Alle brauchen das Interface und der Server braucht noch dessen implementierung. Dem Client reicht das Interface.

- Alex


----------



## scaary (28. Sep 2009)

Ahh, ich verstehe.

Gibt es denn ne alternative zu RMi (da du das als "boese" bezeichnet hast)?

Ich hab prinzipiell nur nen server, der auf die Anfrage eines Clients vorgegeben reagieren muss.

Das Reagieren sieht so aus, das er ne List reinbekommt, mit daten, die benoetigt werden, und die daten gibt er dann zurueck.

Allerdings sind zwei anfragen fuer zwei vollkommen verschiedene Datensaezte moeglich!

Meinst du, das amcht sinn das hiermit zu implementieren?

Mir hat es halt gut gefallen, dass ich "direkt" auf Methoden zugreifen kann.

Ahja, und wenn ich zwei methoden registrieren will, :

```
LocateRegistry.createRegistry( Registry.REGISTRY_PORT ); 

		AdderImpl adder = new AdderImpl(); 
		Adder stub = (Adder) UnicastRemoteObject.exportObject( adder, 0 ); 
		RemoteServer.setLog( System.out ); 

		Registry registry = LocateRegistry.getRegistry(); 
		registry.rebind( "Adder", stub );
```

Reicht es da, nur folgenden ausschnitt zu benutzen:

```
AdderImpl adder2 = new AdderImpl(); 
		Adder stub = (Adder) UnicastRemoteObject.exportObject( adder2, 0 ); 
		RemoteServer.setLog( System.out ); 

		Registry registry = LocateRegistry.getRegistry(); 
		registry.rebind( "Adder2", stub );
```


----------



## tuxedo (29. Sep 2009)

1) Du solltest dringend mal ein RMI Tutorial anschauen. Für mehr als eine Remote-Methode brauchst du nicht mehrere Remote-Objekte. Da reicht i.d.R. eins. Mir scheint dir fehlt noch ein konkretes Verständnis wie RMI funktioniert. Da SIMON RMI sehr ähnlich ist, kannst du auch auf der SIMON Projektseite nachlesen wie das generell mit den entfernten Methodenaufrufen funktioniert.

2) RMI ist nur im Fall von Callbacks _böse_. Callbacks heisst: Der Client gibt dem Server ein Objekt mit, welches der Server nun benutzen kann um Methoden beim Client aufzurufen. Wenn du dein "Frage-Antwort-Spiel" allerdings nur in eine Richtung (Client->Server) betreibst und der Server nie von alleine den Client etwas fragen muss, dann ist RMI für deine zwecke wohl ausreichend. 

Aber in der Tat gibt es alternativen die einem das Leben vereinfachen. Hier sei exemplarisch SIMON und Spring RPC genannt (Ein Blick auf meine Signatur und evtl. noch google hilft). 

- Alex


----------



## scaary (30. Sep 2009)

Hiho 

Ich habe mir jetzt zusaetzlich noch ein Tutorial durchgelesen und das Prinzipe soweit verstanden.
Hab ausserdem schon meinen eigenen Kleinen Server gebastelt, der auch ohne Probleme (auf dem selben PC) funktioniert.

Aber ich muss dich trotzdem nochmal nerven.

Ich verstehe nicht, wie ich dem Server eine adresse im Internet zuweisen kann. Wie sag ich ihm, auf welche adresse er hoeren muss, bzw wie er diese anmeldet?

Ich habs zwar gelesen, aber nicht verstanden... 

danke!


----------



## tuxedo (1. Okt 2009)

scaary hat gesagt.:


> Ich verstehe nicht, wie ich dem Server eine adresse im Internet zuweisen kann. Wie sag ich ihm, auf welche adresse er hoeren muss, bzw wie er diese anmeldet?



Gar nicht. Der Server muss diese Adresse "besitzen".

Beispiel:

Du startest den Server auf einem Rechner der an einem DSL-Router hängt. Dann kannst du als Adresse nur die IP des PCs angeben. Eben weil er nur auf diese lokal vorhandene Adresse binden kann und eine Netzwerkkarte besitzt die diese Adresse hat.

Du kannst nicht dem PC sagen: Binde dich an "meineDomain.de" wenn "meineDomain.de" nicht zu der IP aufgelöst werden kann die der Rechner tatsächlich besitzt.

Ergo: Du kannst nur die Adressen/IPs beim binden des Servers angeben die der Rechner auf tatsächlich an seinen Netzwerkkarten hat.

Vielleicht kommen wir weiter wenn du mal detailiert erklärst was du vor hast?!


----------



## scaary (2. Okt 2009)

Ahh.

Ok, dann ist das ganze gar kein problem 

Ich dachte, sun haette irgendeine eigene Webserverdomain bei der man sich anmelden muss.
Habs einfach nur falsch verstanden 

Was ich vorhab:

Ein Server bei mir, ein Cleint bei (was weiss ich).
Client fragt bei meinem Server das einige Dateien an, die werden an den Client geschickt. Fertig.

Mehr muss das ding ned koennen.

ergo reicht mir meine ganz normale IP adresse inkl portforwarding im router auf den serverrechner, gell?

Danke vielmals!


----------



## scaary (4. Okt 2009)

Heute morgen ist mir allerdings ein vermeindlicher gedankenfehler in einem teilstueck meines Codes beim Server aufgefallen:


```
public File[] getFiles(Data[] DataList) {
		LinkedList<File> resultList = new LinkedList<File>();
		// Getting all the files of the requested datas
		for (int i = 0; i < DataList.length; ++i) {
			String[] folderPath= dataList[i].getsavedFilePath();
			File folder = new File(folderPath[0]);
			// Saving the folder in the returnList
			resultList.add(folder);
			File[] folderContent = folder.listFiles();
			for (int j = 0; j < folderContent.length; ++j) {				
				//saving all file sin the folder in the returnList
				resultList.add(folderContent[j]);
			}
		}
		// Transfoming the linkedList to an array.
		File[] result = new File[resultList.size()];
		for (int i = 0; i < resultList.size(); ++i) {
			result[i] = resultList.get(i);
		}
		return result;
	}
```

Hier speicher ich ja nur die Namen der einzelnen Dateien, nicht aber deren inhalt ¬>¬.

Gibt es eine elegante Loesung, wie ich den Inhalt gleich mit ueber das Internet verschicken kann?

Danke!


----------



## tuxedo (4. Okt 2009)

Datei häppchenweise als byte[] Methodenargument zum Server/Client übertragen. 

Für RMI gibt's - wie ich kürzlich erst lernen musste - eine Library die Streaming über RMI ermöglich: RMIIO - Utilities for streaming data over RMI

- Alex


----------



## scaary (4. Okt 2009)

Ahh, vielen lieben Dank.

Aber mal rein zur Theorie:

Das ganze sind ja quasi nur entfernte Methoden, gell?

Wuerde daher auch folgende Funktion auf dem Server funktionieren, wenn sie vom Client aufgerufen wird:


```
/**
	 * Return the content of a file in form of a String.
	 * @param file
	 * @return
	 * @throws IOException 
	 */
	public String requestFileContent(File file) throws IOException {
		return FileWorker.getFileContent(file);
	}
```


```
/**
	 * Get text content from a file.
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String getFileContent(File file) throws IOException {
		String result = "";
		String tmp = "";
		reader = new BufferedReader(new FileReader(file));
		do {
			tmp = reader.readLine();
			if (tmp != null) {
				result = result + tmp;
			}
		} while (tmp != null);
		reader.close();
		return result;
	}
```

Danke schonmal 

Ahja, und mit meiner adresse das War OK, gell? (sprich Oeffentliche IP anwaehlen und im Router Portforwarding, richtig?).

Vielen Dank nochmals fuer deine ganze Hilfe!


----------



## tuxedo (5. Okt 2009)

> Das ganze sind ja quasi nur entfernte Methoden, gell?
> 
> Wuerde daher auch folgende Funktion auf dem Server funktionieren, wenn sie vom Client aufgerufen wird:



Du musst schon der Anleitung auf der verlinkten RMIIO Projektwebseite folgen. Einfach "wie bisher" eine File lesen und schreiben geht nicht. 



> Ahja, und mit meiner adresse das War OK, gell? (sprich Oeffentliche IP anwaehlen und im Router Portforwarding, richtig?).



Ja.

- Alex


----------



## scaary (5. Okt 2009)

mhh, schade, waer zu einfach gewesen 

Na gut, dann eben so.

Danke dir!


----------



## scaary (6. Okt 2009)

Eine Frage haette ich noch:

Ich starte meinen Server:

```
/**
	 * Starts the server
	 * @throws RemoteException
	 */
	public void startServer() throws RemoteException {
		LocateRegistry.createRegistry( Registry.REGISTRY_PORT ); 

		CreateRequestedListImpl adder = new CreateRequestedListImpl(); 
		CreateRequestList stub = (CreateRequestList) UnicastRemoteObject.exportObject(adder, 0 ); 
		RemoteServer.setLog( System.out ); 

		Registry registry = LocateRegistry.getRegistry(); 
		registry.rebind( "Adder", stub ); 

		System.out.println( "CreateRequestList angemeldet" ); 
	}
```

Gibt es auch eine Moeglichkeit, den Server anzuhalten?

Danke!


----------



## tuxedo (6. Okt 2009)

Einfache Frage, einfache Antwort: Ja.

Weiteres verrät dir die JavaDOC zu "Registry" und diverse Tutorials zu RMI, sowie die JavaInsel.

- Alex


----------



## scaary (6. Okt 2009)

Okidoki, thx, dann werd ich mich mal umschauen 

Danke!


----------



## tuxedo (6. Okt 2009)

Mach dir bitte gleich noch ne Haftnotiz an den Monitor: "Erst APIDOC durchschauen, dann JavaInsel durchwühlen, dann Forumsuche bemühen und dann erst Fragen wenn es denn noch notwendig ist."


----------



## scaary (8. Okt 2009)

*ggg*

Ob du es glaubst, ode rnicht, die Schritte hab ich durchgefuehrt 

Es lag wirklich nicht an meiner Faulheit (Ehrenwort), ich hab alle durchgeschaut (bis auf die DOCApi, um ehrlich zu sein, da hab ich nicht dran gedacht).


----------



## tuxedo (9. Okt 2009)

Alle Objekte die du als Methodenargumente übergibst oder als Return-Wert von einem Methodenaufruf erhälst müssen serialisierbar sein und demnach das Marker-Interface "Serializeable" implementieren. 

Wenn die Exception immer noch kommt dann hilft erstmal nur der Stacktrace und ein nochmaliges Kontrollieren der Klassen-Signatur.

- Alex


----------

