RMI Designfrage zu autorisiertem Filetransfer

NegroManus

Mitglied
Hallo alle,

momentan versuche ich über RMI verschiedene Services anzubieten. RMI ist an sich auch kein Problem.
Diese Services sollen nur autorisierten Nutzern zur Verfügung stehen. An sich auch kein Problem. Dazu übergebe ich immer eine Session-ID, mit der der Nutzer auf Serverseite herausgesucht werden kann. Bei "access denied" werfe ich eine IllegalAccessException.
Nun soll ein Service davon sein, eine Datei runter- oder hochzuladen. Ich habe gelesen, dass dies am schnellsten über Sockets machbar ist. Also wollte ich die Autorisierung und die Anfrage wie gewohnt über RMI handhaben und dann eine Socket-Verbindung herstellen.

Auszug aus dem Remote-Interface FileService:
Java:
public interface FileService extends Remote
//returns filesize
public long requestDownloadFile(String sessionId, String filePath) throws RemoteException,
	    IllegalAccessException, IOException;

Wenn dann ein User die Funktion aufruft, wird die Session-ID überprüft und ggf. die Datei rausgesucht. Die Dateigröße wollte ich zurückgeben, damit der Client eine ProgressBar aktualisieren kann.
Wie baue ich dann aber danach die Socket-Connection auf?
Wie man an sich eine Verbindung aufbaut, ist mir bewusst. Der SocketServer wartet mit accept() auf eingehende Verbindungen. Nur woher weiß er dann, von wem er die Verbindung entgegennehmen darf? Oder kann er vielleicht von sich aus eine Verbindung zum anfragenden Client aufbauen und die Daten in den Outputstream schreiben?

Oder bin ich mit dem ganzen Ansatz komplett auf dem Holzweg?

Ich wäre echt dankbar für jede Hilfe! :)
Grüße
Negro
 
S

SlaterB

Gast
ohne vertiefte Kenntnisse rate ich dir, erstmal nur bei RMI zu bleiben, was macht es schon wenn der Download vielleicht 5.5 statt 5 sec dauert,
du hast doch bestimmt noch gar nicht getestet ob es viel länger dauert?

lade alle Daten in ein großes byte[] und verschicke dieses,
für zig MB ist das natürlich weniger geeignet, ist das auch denkbar?

ansonsten:
auch bei der separaten Socket-Verbindung kann der Client doch was mitschicken, Session-Id, Dateiname, was auch immer,

vom Server an den Client eine Verbindung zu öffnen wäre sehr speziell, selbst falls innerhalb von RMI, unnötig
 

NegroManus

Mitglied
Erst einmal vielen Dank für deine Antwort! :toll:
ohne vertiefte Kenntnisse rate ich dir, erstmal nur bei RMI zu bleiben, was macht es schon wenn der Download vielleicht 5.5 statt 5 sec dauert,
du hast doch bestimmt noch gar nicht getestet ob es viel länger dauert?

lade alle Daten in ein großes byte[] und verschicke dieses,
für zig MB ist das natürlich weniger geeignet, ist das auch denkbar?
Ja, byte[] ist ja auf eine Größe von Integer.MAX_VALUE beschränkt oder nicht? Damit wären nur 2GB möglich. Diese Grenze wird auf jeden Fall angetastet bzw überschritten. Es werden also "zig MB". ^^

ansonsten:
auch bei der separaten Socket-Verbindung kann der Client doch was mitschicken, Session-Id, Dateiname, was auch immer,

vom Server an den Client eine Verbindung zu öffnen wäre sehr speziell, selbst falls innerhalb von RMI, unnötig
Ja, ich kann ja aus einem InputStream Objekte parsen ([c]String sessionId = in.read()[/code]), das meinst du oder? Aber mir gefällt mehr die Kommunikation über RMI als einfache und klar definierte Schnittstelle. Es soll für den Client so einfach wie möglich gehalten werden.
Wenn das Vorausschicken der Parameter über einen Socket die einzige Möglichkeit ist, wäre das schade.
 
S

SlaterB

Gast
du willst Informationen über den Client, das Schicken von Informationen wäre aber schade?!
alternativ reicht dir vielleich gleiche IP usw., das kann man vom Socket ja auslesen
 

NegroManus

Mitglied
Nein, so meine ich das nicht. :D
Ich möchte die Informationen "idiotensicher" übertragen.
Parsen ist ja immer fehleranfälliger als Parameterübergabe.

Kann ich denn auch die IP einer RMI-Anfrage ermitteln?
Bzw wie? ^^
 

NegroManus

Mitglied
Danke fürs googlen. :D
Au ja, bei mir funktioniert die Lösung auch. Liefert mir meine IP-Adresse. :)

Okay. Danke für das Aufzeigen der zwei Möglichkeiten. Ich werde mal überlegen, ob..
A) Der Client die Socketverbindung direkt initialisiert und Parameter mitreinschriebt
oder
B) Der Server die Authentifizierung übernimmt und dann dem SocketServer die gültigen IP-Adressen (mapped auf Files) mitteilt. Wobei ich mir das bei quasi-parallelen Anfragen von mehreren Nutzern (oder auch vom gleichen) etwas problematisch vorstelle.

Ich denke, ich werde dann zur Möglichkeit A) greifen. Iwann muss der Client eh die Verbindung aufbauen und dann muss er halt erst einen/zwei Parameter versenden.
Ich werde aber mal beides testen.

Vielen Dank für deine schnellen und hilfreichen Antworten. :)
Ich markiere mal als "erledigt".
 
Zuletzt bearbeitet:

NegroManus

Mitglied
Na siehste. Bäms!
Schaue ich mir mal an!

Ich hatte iwo gelesen, dass man Streaming lieber über Sockets machen sollte und mich dann wohl darauf versteift :-\.

[EDIT]
Still for file transfer the implementation has a drawback: The copy method reads and writes blocks and either call is a remote call. On a LAN that's no big issue, but with ADSL-connections we have latencies of around 50ms or more. Even with infinite bandwidth, to transfer 100MB using 64 KB blocks would cost us 80s assuming a latency of 50ms. A larger block size improves the performance, but we shouldn't waste memory.
Quelle: File streaming using Java RMI | censhare

Genau das hatte ich halt auch gelesen und mir gedacht. Hier wird eine Lösung über ein gebautes "RMIPipe" beschrieben. Muss ich mal schauen... :)
[/EDIT]
 
Zuletzt bearbeitet:

homer65

Top Contributor
Mit welcher Technik auch immer. Bei Dateigrößen um 2GB solltest du immer mit möglichen Abbrüchen während des Transfers rechnen. Es wäre übel, wenn du dann wieder bei Null starten müßtest. Und das womöglich auch noch mehrfach.
Deshalb rate ich dir die Datei in kleinere Pakete zu zerlegen, so das du im Fall eines Abbruchs bei einem "kleineren" Paket wieder aufsetzen könntest.
 

NegroManus

Mitglied
Ich habe mal das hier importiert: Utilities for streaming data over RMI

Damit habe ich testweise mal ein File lokal "hochgeladen". Funktionierte tadellos (nachdem ich den Apache Logger eingebunden hatte, der benötigt wurde). Die API unterstützt auch einen ProgressMonitor, netter Nebeneffekt!
Er las/schrieb lokal mit ~47mb/s (212,2 MB in 4 Sekunden; Laptopplatte).
Heute Abend werde ich es mal im lokalen Heimnetz testen und mit Socket-Filetransfer vergleichen.
Ich fand leider noch nichts bezüglich der Implementierung, was den Overhead angeht (siehe Zitat in meinem vorherigen Beitrag). Aber ich denke, das sollte schon recht fix sein.

Fortführung bei Unterbrechung wäre natürlich genial. Dazu könnte sich der Client/Server die Anzahl empfangener Bytes merken und beim Fortfahren des Hoch-/Herunterladens diese skippen, oder?
 
Zuletzt bearbeitet:
S

SlaterB

Gast
> Dazu könnte sich der Client/Server die Anzahl empfangener Bytes merken und beim Fortfahren des Hoch-/Herunterladens diese skippen, oder?

wenn der Server skippt und erst den Rest sendet, gut,
wenn der Client skippt, der Anfang aber dennoch übertragen wird, nicht so gut ;)
 

NegroManus

Mitglied
Deine Sätze beziehen sich beide auf den Downloadprozess?
Da muss natürlich eine Konsistenz herrschen.

Um so Feinheiten wie resumable Download werde ich mich später eventuell kümmern. Erstmal muss es überhaupt laufen. :D
 
Zuletzt bearbeitet:

Empire Phoenix

Top Contributor
Wäre mit sockets einfach zu machen anyway.

-> Client baut socket zum server auf, schickt session id und nen long für bereits vorhandene bytes.
-> Server antwortet mit fixed size md5 prüfsumme(die kann ja einmal beim hochladen ermittelt werden und mitgespeichert) und danach allen bytes die noch fehlen.

-> Thread liest x bytes in ein synchronized blocking linked list <byte>, während ein anderer daraus in den socket schreibt.

-> Client appendet die zusätzlichen bytes, am ende berechnet er die md5 und vergleicht diese.

-> Fortschritsbalken? gar kein problem, man kann ja periodisch am server abfragen wie groß der derzeitige lese offset ist, und entsprechend da man die gasamte filesize weiß das dann per rmi updaten am client.
 
S

SlaterB

Gast
-> Fortschritsbalken? gar kein problem, man kann ja periodisch am server abfragen wie groß der derzeitige lese offset ist, und entsprechend da man die gasamte filesize weiß das dann per rmi updaten am client.

wenn der Client die Daten liest, egal in welchen Thread, und vorher schon die Size weiß,
dann muss dazu doch gar nichts mehr gemacht werden,
weder muss der Client nochmal beim Server anfragen, noch gar der Server zum Client dazu was vermelden,
die Information (x bytes von n gelesen) hat doch der Client wenn er in seiner Schleife mitzählt
 
T

tuxedo

Gast
Die Frage ist halt, ob ausschließlich Filetransfer, oder eben auch RPC benötigt wird....

Wenn RPC benötigt wird und RMI zum Einsatz kommt, würde ich eine separate Socketverbindung benutzen. Auf keinen Fall würde ich Files die über kilobytes hinaus gehen per RMI senden wollen...

Dass SIMON RawChannels für Daten/Filetransfer unterstützt hab ich schon erwähnt?

Gruß
Alex
 

NegroManus

Mitglied
Der Ansatz vom Empire Phoenix mit dem Hash-Vergleich würde zumindest bei den vom Slater angeführten "nicht so gut"en Ereignissen dafür sorgen, dass diese erkannt werden.

Fortschrittsbalken kann man natürlich beim Client selbstständig aktualisieren anhand der filesize.

Danke! :)
 

Ähnliche Java Themen


Oben