Κωνσταντινος Θεοφίλης
A.M. sdi1600287

//////// COMPILE & RUN ////////

Compile whoServer: 
    make (with makefile) or g++ whoServer.cpp whoServerMethods.cpp -lpthread
Execute whoServer:
    make server

Compile master:
    make
Execute master:
    make exec_master

Compile whoClient:
    make (with makefile) or g++ whoClient.cpp whoClientMethods.cpp -lpthread
Execute whoClient:
    make client

//////// NOTES ////////

1)  Η πληροφορία ταξιδεύει σωστά απο τον whoClient προς τους worker και υστερα η απάντηση προς τα πίσω. 
2)  Υπάρχουν ενδεχόμενα που δεν θα επιστραφεί αποτέλεσμα στον client. Λογικά αυτό συμβαίνει επειδή κάποιος 
    worker που δεν έχει την σωστή απάντηση προλαβαίνει να απαντήσει και ύστερα να κλήση το connection. Ετσι,
    η σωστή απάντηση δεν φτάνει ποτέ.
3)  Ηταν μια εργασία με άπειρο debugging, γι αυτό μπορεί να υπάρχουν αρκετα flaws. Το connectivity μεταξύ 
    προγραμμάτων λειτουργεί σωστά και η πληροφορία μεταφέρεται (το 1).
4)  Κατα την ολοκλήρωση εκτέλεσης των προγραμμάτων και συγκεκριμένα όταν ο master τερματιστεί να γίνουν kill οι 
    workers manually απο το system monitor καθώς το signal hadling δεν λειτουργεί. (!!!Δεν ξέρω γιατι όμως!!!)

...Γενική περιγραφή...

Ξεκινάμε να εκτελούμε ενα ενα τα προγραμματα μας με σειρα, whoServer, master, whoClient.
Αρχικά ο whoServer θα πάει να κάνει connection με τους worker ώστε να συλλέξει απο αυτους 
απαραίτητες πληροφορίες όπως τα port τους για μετέπειτα συνδέσεις. 
Επίσης κατα την εκτέλεση του master το port και η ip του whoServer είναι γνωστά στον worker 
(αποστέλονται απο master -> workers μέσω πρωτοκόλλων), ετσι λοιπόν ξέρει απο που να αναμένει σύνδεση.
Αφού ο whoServer ολοκληρώσει το connection με τους worker επιστρέφει και κάνει σύνδεση με τον whoClient
τα νήματα του οποίου θα στείλουν τις εντολές του queryFile (όλα μαζί). 
Τα νήματα του whoServer θα προωθησουν τις εντολές στους worker οι οποίοι με την σειρά τους 
θα υπολογήσουν τα ζητούμενα της εντολής και θα επιστρέψουν πίσω στον whoClient τα αποτελέσματα.

(Γενικά κακός χαμός !!!)

...Σχεδιασικη επιλογή...Producer - Consumer...
Ο whoServer και ο whoClient μοιράζονται έναν fixed-size buffer (το μέγεθος το καθορίζουμε εμείς) 
ο οποίος γεμίζει και αδειάζει με δεδομένα. Στην συγκεκριμένη περίπτωση ο whoServer ξεκινά ως παραγωγός 
(producer) γεμίζει εναν buffer με file descriptors. Όταν μια εντολή (ή και περισσότερες) έρθει μέσω νήματος
(του whoClient) θα γίνει consume ένα fd και θα το αναλάβει ύστερα το νήμα του whoServer για να το "στείλει" 
σε κάποιον worker (όλα αυτα αφου πρώτα γίνουν τα απαραίτητα connection).

...whoClient.. 
ο whoClient παίρνει το queryFile με τις εντολες και το διασχίζει μια μια. 
*Σχεδιασικη επιλογή*: Τα threads του client καθορίζονται αυτόματα όσες και οι εντολές.
Σε κάθε νήμα του whoClient αναθέτω μια εντολή. Μέχρι να διαβασουμε και να θέσουμε 
όλες τις εντολές σε καθε νήμα ο whoClient δεν στέλνει τίποτα και παραμένει locked.
Οταν δωθεί "σήμα" δηλαδή διαβασει eof απο το αρχειο μας φεύγουν όλα τα νήματα μαζι προς τον whoServer.
...Τέλος ο whoClient τυπώνει τα αποτελέσματα που θα λάβει όσο ο buffer διαβαζει.

..master..
Ο master δημιουργεί τους worker με τους οποίους επικοινωνεί μέσω named pipes.
Ο master στέλνει στους worker το ip και το port του whoServer ώστε να ξερουν 
απο που θα λάβουν σύνδεση (αποστέλονται απο master -> workers μέσω πρωτοκόλλων).

...whoServer...
Έχει ως βασική λειτουργία αυτό που λεει στην *Σχεδιαστικη επιλογή*. Επίσης περιλαμβάνει 
τα βασικά πρωτοκολλα με τα οποία μεταφέρονται δεδομένα απο το ενα πρόγραμμα στο άλλο. 
Πολλά πρωτόκολλα παρέμειναν ίδια με την 2η εργασία με αλλαγές εσωτερικά ωστε η πληροφορια να μεταφερετε στον worker ή στον whoClient.