-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME
105 lines (69 loc) · 9.65 KB
/
README
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
Νικόλαος Μαυραπίδης - 1115201700082 - Εργασία 2 - Προγραμματισμός Συστήματος
Έγινε πλήρης υλποίηση του προγράμματος, μια γενική επεξήγηση της εργασίας πως λειτουργεί:
~~~~~~~~SERVER
1) Ανοίγει ο σέρβερ και διαβάζει από το τερματικό τα arguments που δώσαμε.
2) Στη συνέχεια κάνει initialize τα κατάλληλα mutexes για την επίτευξη συγχρονισμού μεταξύ των trheads και κάποιων δομών και μεταβλητών που βοηθάνε στην επίτευξη του σκοπού.
3) Δημιουργει ο σέρβερ ένα listening socket όπου από εκεί δέχεται τα νέα connections από τους client.
4) Κάνει initialize τα worker threads που αναλαμβάνουν την αποστολή αρχείων στους clients. Τα νήματα αυτά παίρνουν ως όρισμα ένα index που δηλώνουν την θέση στον πίνακα busy. Ο πίνακας busy έχει μέγεθος thread_pool_size και κρατάει στην θέση index αν κάποιο socket είναι απασχολημένο από νήμα.
5) Μπαίνει σε ένα infinite loop όπου το μόνο που κάνει είναι να δέχεται νέα connections και να δημιουργεί ένα νέο communication thread που είναι υπεύθυνο για να διαβάσει τα αρχεία και να τα βάλει στην custom made ουρά.
~~~~~~~~COMMUNICATION THREAD
Όταν ο σέρβερ δεχτεί νέο connection τότε δημιουργείται ένα καινούργιο νήμα επικοινωνίας. Αυτό λειτουργεί ως εξής:
1) Στέλνει το block_size στον client και παίρνει το σχετικό μονοπάτι από τον client
2) Φτιάχνει μέσω μιας custom κλάσης (fpath) μια δομή των αρχείων όπου κρατούνται κάποια απαραίτητα στοιχεία όπως το μονοπάτι, αν είναι φάκελος, το όνομα κλπ. ΔΕΝ ΚΡΑΤΟΎΝΤΑΙ ΤΑ ΔΕΔΟΜΈΝΑ ΤΩΝ ΑΡΧΕΊΩΝ.
3) Βρίσκει τον αριθμό των αρχείων που υπάρχουν στο ζητούμενο μονοπάτι.
4) Σε ένα vector κρατούνται εγγραφές της μορφής [current_socket, number_of_files, files served]. Έτσι με αυτόν τον τρόπο κρατάμε ποια socket έχουν πλήρως εξυπηρετηθεί, οπότε μπορούμε να κλείσουμε την σύνδεση με ασφάλεια.
5) Προσθέτει q_nodes στην ουρά όπου με την χρήση των mutexes ενεργοποιούνται οι workers και αρχίζουν
να εξυπηρετούν τους clients
~~~~~~~~WORKER THREAD
To νήμα-εργάτης από την στιγμή που δημιουργείται περιμένει μέσα σε έναν ατέρμον βρόγχο να μπεί κάποιο node μέσα στο shared queue. Όταν μπει και ενεργοποιηθεί κάποιος worker (μεσω mutexes):
1) Παίρνει την κυριαρχία του queue μέσω των mutexes.
2) Παίρνει το πρώτο στοιχείο από την ουρά
3) Παίρνοντας το socket που θα πάει αυτό το αρχείο τσεκάρει αν είναι busy αυτό το socket
4) Αν είναι busy το socket, τότε κάνει pop() και push() το node στο πίσω μέρος της ουράς και ξανά στο βήμα 2)
5) Αν δεν είναι busy το socket, τότε στην θέση index(περνάει σαν όρισμα στον worker thread) του πίνακα busy[] μπαίνει η τιμή του socket (default value = -1)
6) Στέλνει κάποια στοιχεία του αρχείου του client αρχικά, όπως το όνομα και στην συνέχεια στέλνει το αρχείο κατά block_size
7) [current_socket, number_of_files, files served + 1] Στην κατάλληλη εγγραφή, τα files_served αυξάνονται κατά 1
8) ΕΑΝ number_of_files == files served τότε ο client έχει πάρει όλα τα αρχεία που χρειάζεται οπότε στην συνέχεια κλείνουμε την σύνδεση και αφαιρούμε την εγγραφή κατάλληλη εγγραφή [current_socket, number_of_files, files served] από το vector μας.
Όλη η διαδικασία παραπάνω επαναλαμβάνεται συνεχώς.
~~~~~~~~CLIENT
O client είναι ένα πολύ απλό πρόγραμμα. Συγκεκριμένα:
1) Διαβάζονται τα arguments από το τερματικό
2) Δοκιμάζει σύνδεση με τον server
3) Παίρνει το block_size από τον server
4) Στέλνει στον server το σχετικό μονοπάτι που επιθυμεί
5) Διαβάζει συνεχώς αρχεία μέχρι να τα στείλει όλα ο σέρβερ
6) κλείνει η σύνδεση
--------------------------Κλάσεις
q: Είναι μια κλασική υλοποίση ουράς
q_node: Είναι το node της κλάσης q. Κρατάω σε αυτό απαραίτητα στοιχεία όπως socket, file(fpath) κλπ.
fpath: Μια ολοκληρωμένη κλάση όπου κρατούνται στοιχεία για ένα directory και τα subdirectories του. Έχει στοιχεία όπως parent αρχείου, όνομα, βάθος σε σχέση με το αρχικό μονοπάτι, αν είναι φάκελος. Όλα τα αρχεία συνδέονται μεταξύ τους μέσω αυτής της κλάσης, σαν δέντρο.
--------------------------Auxilliary functions (aux.cpp/h)
Εδώ υπάρχουν όλες οι βοηθητικές συναρτήσεις που χρησιμοποιούνται από τον client και από τον server.
Είναι όλες ΠΛΗΡΩΣ σχολιασμένες
Θα τονίσω την λειτουργεία δύο βασικών συναρτήσεων την get_file() και την send_file()
-----get_file():
1) Αρχικά παίρνει το μονοπάτι του αρχείου που θα διαβάσει.
2) σπάει το μονοπάτι στο όνομα και στο υπόλοιπο μονοπάτι.
3) παίρνει το μέγεθος του αρχείου
4) υπολογίζει πόσες φορές θα κάνει read από το socket
5) κάνει τσεκ να δεί αν υπάρχει το αρχείο, αν υπάρχει τότε το διαγράφει. Αν ΔΕΝ υπάρχει, τότε τσεκάρει αν υπάρχει όλο το υπόλοιπο μονοπάτι και το δημιουργεί αν χρειαστεί.
6) Φτιάχνει νέο κενό αρχείο
7) Επαναλαμβανόμενα διαβάζει κατά block_size από το socket και γράφει τα bytes που λαμβάνει στο νέο αρχείο.
8) Ολοκληρώνεται η διαδικασία αυτή και κλείνει το αρχείο.
-----send_file():
1) Παίρνει το μονοπάτι του αρχείου (fpath) και το ανοίγει για διάβασμα
2) Βρίσκει το μέγεθος του αρχείου
3) Στέλνει το μέγεθος του αρχείου στον client
4) Υπολογίζει πόσες φορές θα στείλει block_size αριθμό bytes στον client
5) Στέλνει δεδομένα στον client ανά block_size κάθε φορά
6) Όταν τελειώσει η διαδικασία, κλείνει το αρχείο.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Compilation και ενδεικτικές εντολές εκτέλεσης:
Για να κάνουμε compile τα προγράμματα αρκεί να τρέξουμε στο τερματικό την εντολή make
Στην συνέχεια μπορούμε να εκτελέσουμε κανονικά το πρόγραμμά μας, πχ:
./dataServer -p 8080 -s 20 -q 10 -b 512
./remoteClient -p 8080 -i 127.0.0.1 -d from/dir
Είναι ΣΗΜΑΝΤΙΚΟ να τονίσουμε ότι στο PATH του directory δεν ξεκινάει με "./" ή "/" αλλά κατευθείαν με το όνομα όπως πχ παραπάνω "from/dir"
Όταν ο client κατεβάζει τα αρχεία στον υπολογιστή του, δημιουργείται ένα directory "results" και εκεί αποθηκεύονται όλα. Αυτό έγινε διότι όταν τρέχουμε τον σερβερ και τον client από το ίδιο directory μην γίνει απλά overwrite τα υπάρχοντα αρχεία.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ΠΡΟΕΡΑΙΤΙΚΟ
Έχω φτιάξει ένα testing program που τεσταρει όσο γίνεται ότι λειτουργεί με πολλαπλούς πελάτες ταυτόχρονα. Δημιουργεί μέσω fork 10 clients που συνδέονται στον σέρβερ.
Αν θελήσετε να το χρησιμοποιήσετε τότε κάντε g++ test.cpp και τρέξτε το ./a.out ΕΝΩ ΕΙΝΑΙ ΑΝΟΙΧΤΟΣ Ο ΣΕΡΒΕΡ ΣΤΟ ΛΟΚΑΛ ΜΗΧΑΝΗΜΑ!!!