Speciaal op aanraden van o.a. Woy in Coffee Corner bij deze dan mijn vraag/vragen over Sockets en Java.
Anyway. voor een studieopdracht moet ik een soort Dropbox/remote file browser achtig client-server model bouwen in Java welke tevens cross-platform moet werken. Het vak waar deze opdracht voor geldt is Operating Systems 3 en het is dus de bedoeling dat ik aan kan tonen dat ik snap en begrijp hoe Sockets in een Operating System werken.
Allereerst ben ik begonnen met het maken van een relatief simpele chat client. Deze kon berichten overzenden door middel van een PrintWriter en uitlezen met een BufferedReader. Verder had ik een implementatie gebouwd die op basis van de eerste parameter (gescheiden op spaties) kijkt welk commando uitgevoerd moet worden; zoals CD, DIR, etc. Dat ging allemaal erg voorspoedig, totdat ik nu bij de FileTransfer kant aankom.
Het probleem waar ik vooralsnog mee zit is dat ik niet goed weet hoe ik een file transfer kan starten en het goed kan scheiden van de chat functionaliteit.
Nu naar de code.
Sowieso heb ik door middel van Maven modules onderscheid gemaakt in drie projecten, Client, Server en Shared. De Shared module heeft maar drie klassen, namelijk:
En welke volgens mij op deze manier goed moet zijn. Daarnaast is er dan nog de Server welke de SocketConnection implementeert als ClientConnection, welke dan in een thread loopt en er als volgt uitziet:
Zoals je al ziet gebruikt deze klasse het FileBrowsingProtocol, welke op basis van de input een process() methode aanroept en dan de input van de client verwerkt. Nu heb ik in het bovenstaande voorbeeld ook het FileTransferProtocol verwerkt, maar ik weet totaal niet of dat wel klopt, althans hoe ik het heb gedaan.
Op de client kant zou de read() methode er ongeveer hetzelfde uitzien als op de Server kant, aangezien ze allebei van SocketConnection afstammen met dezelfde input en output klassen. Verder gebeurt er op de client kant momenteel nog niet veel spannends.
Nu, wat is dan mijn vraag?!
Hoe kan ik op deze manier, of doe ik het gewoon helemaal fout, gemakkelijk en fatsoenlijk die verdomde file transfer werkend krijgen...? Ik weet namelijk totaal niet of ik op deze manier goed bezig ben of dat ik het beter anders kan aanpakken...
Anyway. voor een studieopdracht moet ik een soort Dropbox/remote file browser achtig client-server model bouwen in Java welke tevens cross-platform moet werken. Het vak waar deze opdracht voor geldt is Operating Systems 3 en het is dus de bedoeling dat ik aan kan tonen dat ik snap en begrijp hoe Sockets in een Operating System werken.
Allereerst ben ik begonnen met het maken van een relatief simpele chat client. Deze kon berichten overzenden door middel van een PrintWriter en uitlezen met een BufferedReader. Verder had ik een implementatie gebouwd die op basis van de eerste parameter (gescheiden op spaties) kijkt welk commando uitgevoerd moet worden; zoals CD, DIR, etc. Dat ging allemaal erg voorspoedig, totdat ik nu bij de FileTransfer kant aankom.
Het probleem waar ik vooralsnog mee zit is dat ik niet goed weet hoe ik een file transfer kan starten en het goed kan scheiden van de chat functionaliteit.
Nu naar de code.
Sowieso heb ik door middel van Maven modules onderscheid gemaakt in drie projecten, Client, Server en Shared. De Shared module heeft maar drie klassen, namelijk:
- Constants, voor ... juist
- FileTransferProtocol, welke een read() en write() methode heeft om buffered byte[]'s te kunnen verzenden en ontvangen.
- SocketConnection, welke een basis heeft met een abstracte read(), maar geïmplementeerde write()-methoden om gemakkelijk tekst te verzenden en ontvangen.
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
| public class FileTransferProtocol { private static final int BUFFER_SIZE = 1024 * 16; private Socket connection; public FileTransferProtocol(Socket connection) { this.connection = connection; } public void sendFile(File file) throws IOException { try (ObjectOutputStream outputStream = new ObjectOutputStream(this.connection.getOutputStream())) { long fileSize = file.length(); long sentBytes = 0; byte[] buffer = new byte[FileTransferProtocol.BUFFER_SIZE]; try (FileInputStream fileStream = new FileInputStream(file)) { while (sentBytes <= fileSize) { fileStream.read(buffer); outputStream.write(buffer); sentBytes += FileTransferProtocol.BUFFER_SIZE; } } } } public void receiveFile(String fileName) throws IOException { try (ObjectInputStream inputStream = new ObjectInputStream(this.connection.getInputStream())) { try (FileOutputStream fileStream = new FileOutputStream(fileName)) { long bytesRead = 0; byte[] buffer = new byte[FileTransferProtocol.BUFFER_SIZE]; while (bytesRead >= 0) { bytesRead = inputStream.read(buffer); if (bytesRead >= 0) { fileStream.write(buffer); } if (bytesRead < FileTransferProtocol.BUFFER_SIZE) { fileStream.flush(); break; } } } } } } |
En welke volgens mij op deze manier goed moet zijn. Daarnaast is er dan nog de Server welke de SocketConnection implementeert als ClientConnection, welke dan in een thread loopt en er als volgt uitziet:
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
| private final FileBrowsingProtocol protocol; private final BufferedReader input; public void read() { String message = ""; try { while ((message = this.input.readLine()) != null) { if (message.startsWith(Constants.RECEIVE_FILE)) { this.transferProtocol.receiveFile(message.replace(Constants.RECEIVE_FILE, "")); } else if (message.startsWith(Constants.SEND_FILE)) { this.transferProtocol.sendFile(Paths.get(this.protocol.getCurrentWorkingDirectory().toString(), message.replace(Constants.SEND_FILE, "")).toFile()); } else { protocol.process(message); System.out.println(message); // debug. } } } catch (IOException e) { if (e.getMessage().equals("Connection reset")) { System.out.printf("Client disconnected <%s>.%n", this.getConnection().getRemoteSocketAddress().toString()); } else { System.err.printf("Issue when reading from client: %s%n", e.getMessage()); } } } |
Zoals je al ziet gebruikt deze klasse het FileBrowsingProtocol, welke op basis van de input een process() methode aanroept en dan de input van de client verwerkt. Nu heb ik in het bovenstaande voorbeeld ook het FileTransferProtocol verwerkt, maar ik weet totaal niet of dat wel klopt, althans hoe ik het heb gedaan.
Op de client kant zou de read() methode er ongeveer hetzelfde uitzien als op de Server kant, aangezien ze allebei van SocketConnection afstammen met dezelfde input en output klassen. Verder gebeurt er op de client kant momenteel nog niet veel spannends.
Nu, wat is dan mijn vraag?!
Hoe kan ik op deze manier, of doe ik het gewoon helemaal fout, gemakkelijk en fatsoenlijk die verdomde file transfer werkend krijgen...? Ik weet namelijk totaal niet of ik op deze manier goed bezig ben of dat ik het beter anders kan aanpakken...