Τ.Ε.Ι. ΚΑΒΑΛΑΣ ΤΜΗΜΑ ΜΗΧΑΝΙΚΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΤΕ ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ ΔΙΚΤΥΑΚΟΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕ JAVA



Σχετικά έγγραφα
Ethernet Ethernet ΙΕΕΕ CSMA/CD

Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Εισαγωγή στην Επιστήμη των Υπολογιστών Δίκτυα υπολογιστών. (και το Διαδίκτυο)

Α5.1 Εισαγωγή στα Δίκτυα. Α Λυκείου

Τι είναι ένα δίκτυο υπολογιστών; Αρχιτεκτονική επιπέδων πρωτοκόλλων. Δικτυακά πρωτόκολλα

Κεφάλαιο 7 Διαδικτύωση-Internet. 7.2 Τεχνολογία TCP/IP

Πρωτόκολλα Διαδικτύου

ΚΕΦΑΛΑΙΟ 1.7. Πρωτόκολλα και Αρχιτεκτονική Δικτύου

Τεχνολογία Δικτύων Επικοινωνιών (Ενότητα Πρωτόκολλα και Αρχιτεκτονική Δικτύου)

Δίκτυα Θεωρία

ΕΠΛ 001: ΕΙΣΑΓΩΓΗ ΣΤΗΝ ΕΠΙΣΤΗΜΗ ΤΗΣ ΠΛΗΡΟΦΟΡΙΚΗΣ. Δίκτυα Υπολογιστών

Στόχοι. Υπολογιστικά συστήματα: Στρώματα. Βασικές έννοιες [7]

Επαναληπτικές Ασκήσεις Μαθήματος

7.2.2 Σχέση OSI και TCP/IP

Πρότυπο Αναφοράς Open Systems Interconnection (OSI) Επικοινωνίες Δεδομένων Μάθημα 5 ο

Network Address Translation (NAT)

Γενικές Αρχές. Τεχνολογία ικτύων Επικοινωνιών ΙΙ

Πρωτόκολλα Επικοινωνίας Πρωτόκολλο IP

Δίκτυα Η/Υ Θεωρία. Διάλεξη 2η

Πρωτόκολλα Διαδικτύου Μέρος 2ο. Επικοινωνίες Δεδομένων Μάθημα 3 ο

Πρωτόκολλα Επικοινωνίας και Τείχος Προστασίας

1.2.2 Το μοντέλο δικτύωσης TCP/IP 1 / 26

Πρωτόκολλα Διαδικτύου

Τεχνολογία TCP/IP ΙΑ ΙΚΤΥΩΣΗ- INTERNET. Τεχνολογίες Τηλεκπαίδευσης & Εφαρµογές - Ιούλιος

Προγραμματισμός Διαχείρισης Συστημάτων ΙΙ

Εισαγωγή στο TCP/IP. Π. Γαλάτης

Δίκτυα Υπολογιστών. Δίκτυα υπολογιστών και το Διαδίκτυο Εισαγωγή. Κ. Βασιλάκης

7.2 Τεχνολογία TCP/IP

Συσκευές Τηλεπικοινωνιών και Δικτύωσης. Επικοινωνίες Δεδομένων Μάθημα 9 ο

Μάθημα 5: To Μοντέλο Αναφοράς O.S.I.

ίκτυα υπολογιστών Στόχοι κεφαλαίου ίκτυα

Δίκτυα Υπολογιστών Firewalls. Χάρης Μανιφάβας

ίκτυα - Internet Μάθηµα 3ο Ενότητα Β: Το Πρότυπο ΤCP/IP Eισαγωγή - Επικοινωνία µεταξύ δύο Υπολογιστών Παρασκευή 10 NOE 2006 ιευθύνσεις

Εισαγωγή στην επιστήμη των υπολογιστών. Υλικό Υπολογιστών Κεφάλαιο 6ο ίκτυα υπολογιστών

Εισαγωγή στο διαδίκτυο

6.1 Επεκτείνοντας το δίκτυο 6.2 Επιλεγόμενες τηλεφωνικές γραμμές modems Πλεονεκτήματα Μειονεκτήματα Βασική χρήση

Εργαστήριο «Δίκτυα Υπολογιστών Ι»

Κεφάλαιο 7.3. Πρωτόκολλο TCP

Δίκτυα Υπολογιστών. Δίκτυα υπολογιστών και το Διαδίκτυο Εισαγωγή. Κ. Βασιλάκης

Πανεπιστήμιο Πειραιά Τμήμα Ψηφιακών Συστημάτων. ίκτυα Υπολογιστών Ι. To Μοντέλο OSI. Αναπλ. Καθηγ. Π. εμέστιχας

Δίκτυα (2 ο μέρος) ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική

Σύντομη παρουσίαση των εργαλείων/εντολών telnet, ping, traceroute nslookup και nmap, zenmap

Εισαγωγή στην Πληροφορική

ΔΡΟΜΟΛΟΓΗΣΗ ΠΑΚΕΤΩΝ. Η δρομολόγηση των πακέτων μπορεί να γίνει είτε κάνοντας χρήση ασυνδεσμικής υπηρεσίας είτε συνδεσμοστρεφούς υπηρεσίας.

Μάθημα 6: Αρχιτεκτονική TCP/IP

Δίκτυα Υπολογιστών ΙΙ (Ασκήσεις Πράξης)

ΕΠΛ 003: ΕΠΙΣΤΗΜΗ ΤΗΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΠΛΗΡΟΦΟΡΙΚΑ ΣΥΣΤΗΜΑΤΑ

Ιόνιο Πανεπιστήµιο Τµήµα Αρχειονοµίας Βιβλιοθηκονοµίας. Μοντέλο TCP/IP. Ενότητα E. Συστήµατα Επικοινωνίας

PROXY SERVER. Άριστη πύλη διαχωρισμού μεταξύ του εσωτερικού δικτύου και του Internet.

7.5 Πρωτόκολλο IP. Τεχνολογία ικτύων Επικοινωνιών ΙΙ

ΚΕΦΑΛΑΙΟ 1: Τα είδη των Δικτύων Εισαγωγή

Κάθε διεύθυνση IP αποτελείται από δυο τμήματα.

ΤΕΧΝΟΛΟΓΙΑ ΙΚΤΥΩΝ ΕΠΙΚΟΙΝΩΝΙΩΝ

ΕΙΣΑΓΩΓΗ ΣΤΗΝ ΠΛΗΡΟΦΟΡΙΚΗ

Κεφάλαιο 2. Υπολογιστές και Τεχνολογία Επικοινωνιών Παρελθόν - Παρόν - Μέλλον

Ιόνιο Πανεπιστήµιο Τµήµα Πληροφορικής Συστήµατα Επικοινωνίας. Μοντέλο TCP/IP. Ενότητα E. Πόσοι εµπλέκονται σε ένα Σύστηµα Επικοινωνίας

Ενότητα 1. Εισαγωγή στις βασικές έννοιες των ικτύων ΗΥ

ιαδίκτυα και το ιαδίκτυο (Internetworking and the Internet)

Διαδίκτυα και το Διαδίκτυο (Internetworking and the Internet)

ΕΠΙΚΟΙΝΩΝΙΕΣ ΔΕΔΟΜΕΝΩΝ ΚΑΙ ΤΕΧΝΟΛΟΓΙΕΣ INTERNET

Φύλλο Εργασίας 1 ου Κεφαλαίου

Αρχές Δικτύων Επικοινωνιών. Επικοινωνίες Δεδομένων Μάθημα 4 ο

Ερωτήσεις / Απαντήσεις Πιστοποίησης (Επικοινωνίες Δεδομένων)

Εξοικείωση με τις εντολές ipconfig και ping

1.8 Το μοντέλο OSI 1 / 33

Επίπεδο δικτύου IP Forwading κτλ

α. Το μέγιστο μήκος δεδομένων του ωφέλιμου φορτίου του πλαισίου Ethernet είναι 1500 οκτάδες. ΣΩΣΤΟ

Κάντε κλικ για έναρξη

Δίκτυα Υπολογιστών Ενότητα 9: Dynamic Host Configuration Protocol- DHCP

ΔΙΑΓΩΝΙΣΜΑ ΤΕΛΙΚΗΣ ΕΠΑΝΑΛΗΨΗΣ ΣΤΙΣ ΕΝΟΤΗΤΕΣ

Δίκτυα Υπολογιστών I

ΜΑΘΗΜΑ / ΤΑΞΗ : ΔΙΚΤΥΑ ΥΠΟΛΟΓΙΣΤΩΝ ΙΙ / ΕΠΑΛ(Α & Β ΟΜΑΔΑ) ΣΕΙΡΑ: ΗΜΕΡΟΜΗΝΙΑ: 11/12/2011 ΑΠΑΝΤΗΣΕΙΣ

3.3 Πρωτόκολλα ανεύρεσης και απόδοσης διευθύνσεων, Address Resolution Protocol (ARP) και Dynamic Host Configuration Protocol (DHCP)

Κεφάλαιο 6ο ΕΠΙΠΕΔΟ ΕΦΑΡΜΟΓΗΣ. Εισαγωγή

Κεφάλαιο 1 Ε Π Α Ν Α Λ Η Ψ Η. Αρχές Δικτύων Επικοινωνιών

Δίκτυα Θεωρία

Κεφάλαιο 1 Ε Π Α Ν Α Λ Η Ψ Η

ΕΠΙΚΟΙΝΩΝΙΕΣ ΔΕΔΟΜΕΝΩΝ ΚΑΙ ΤΕΧΝΟΛΟΓΙΕΣ INTERNET

Μάθημα 7: Διευθυνσιοδότηση σε Επίπεδο IP

ΤΕΧΝΟΛΟΓΙΑ ΔΙΚΤΥΩΝ ΕΠΙΚΟΙΝΩΝΙΩΝ 1 ο ΚΕΦΑΛΑΙΟ

Εισαγωγή στο πως λειτουργεί το διαδίκτυο

4.1.1 Πρωτόκολλο TCP - Δομή πακέτου

ΔΙΚΤΥΑ ΥΠΟΛΟΓΙΣΤΩΝ ΙΙ

Ηλεκτρονικοί Υπολογιστές Δ Εξάμηνο

ΕΠΛ 012. Δίκτυα Τπολογιστών & Διαδίκτυο

ΒΑΣΙΚΕΣ ΥΠΗΡΕΣΙΕΣ ΤΟΥ ΔΙΑΔΙΚΤΥΟΥ

ΤΕΧΝΟΛΟΓΙΑ ΔΙΚΤΥΩΝ ΕΠΙΚΟΙΝΩΝΙΩΝ 7ο ΚΕΦΑΛΑΙΟ

Η απάντηση αυτή λαμβάνει 5 μονάδες. Και αφού βέβαια ο εξεταζόμενος γράψει το γράμμα της σωστής απάντησης μόνο.

1.5.1 ΓΕΦΥΡΑ (BRIDGE) Εικόνα Επίπεδα λειτουργίας επαναλήπτη, γέφυρας, δρομολογητή και πύλης ως προς το μοντέλο OSI.

ΤΕΧΝΟΛΟΓΙΑ ΔΙΚΤΥΩΝ ΕΠΙΚΟΙΝΩΝΙΩΝ 5ο ΚΕΦΑΛΑΙΟ

Προγραμματισμός Ηλεκτρονικών Υπολογιστών 1

ΤΕΛΟΣ 1ΗΣ ΑΠΟ 5 ΣΕΛΙ ΕΣ

Βασίλειος Κοντογιάννης ΠΕ19

ΔΙΚΤΥΑ (18-19) Π. Φουληράς

Δίκτυα ΙΙ. Κεφάλαιο 7

Ιατρική Πληροφορική. Δρ. Π. ΑΣΒΕΣΤΑΣ ΤΜΗΜΑ ΜΗΧΑΝΙΚΩΝ ΒΙΟΪΑΤΡΙΚΗΣ ΤΕΧΝΟΛΟΓΙΑΣ Τ. Ε. Χρήσιμοι Σύνδεσμοι

6.2 Υπηρεσίες Διαδικτύου

ΤΕΧΝΟΛΟΓΙΑ ΔΙΚΤΥΩΝ ΕΠΙΚΟΙΝΩΝΙΩΝ

Κεφάλαιο > Ε Π Α Ν Α Λ Η Ψ Η Επικοινωνιακό Υποδίκτυο / TCP / UDP. Σελ

2 η Σειρά Ασκήσεων Data Link Layer

AEI Πειραιά Τ.Τ. Τμ. Μηχ/κων Αυτοματισμού ΤΕ. Δίκτυα Μετάδοσης Δεδομένων. Διάλεξη 1: Εισαγωγή στα δίκτυα υπολογιστών και βασικές αρχές

Transcript:

ΣΧΟΛΗ ΤΕΧΝΟΛΟΓΙΚΩΝ ΕΦΑΡΜΟΓΩΝ Τ.Ε.Ι. ΚΑΒΑΛΑΣ ΤΜΗΜΑ ΜΗΧΑΝΙΚΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΤΕ ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ ΔΙΚΤΥΑΚΟΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕ JAVA ΜΠΙΝΙΑΡΗ ΚΑΛΛΙΟΠΗ (ΑΜ: 2236) Επιβλέπων καθηγητής: Στέργιος Παπαδημητρίου ΚΑΒΑΛΑ ΣΕΠΤΕΜΒΡΙΟΣ 2014-1-

-2-

Ευχαριστίες Θα ήθελα να εκφράσω τις ευχαριστίες μου στον Επίκουρο Καθηγητή κ. Στέργιο Παπαδημητρίου για την δυνατότητα που μου έδωσε να πραγματοποιήσω την πτυχιακή μου εργασία. Επίσης θα ήθελα να ευχαριστήσω, όλους του καθηγητές του Τεχνικού Εκπαιδευτικού Ιδρύματος Καβάλας για τις πολύτιμες γνώσεις που μου προσέφεραν όλα αυτά τα χρόνια. Τέλος, θέλω να εκφράσω ένα τεράστιο ευχαριστώ στην οικογένεια μου, για την στήριξη και την εμπιστοσύνη που μου έδειξε όλα αυτά τα χρόνια των σπουδών μου. -3-

Περιεχόμενα Ευχαριστίες... 3 Περιεχόμενα... 4 Περίληψη... 6 1. Βασικά Χαρακτηριστικά Δικτύων... 7 1.1. Εισαγωγή... 7 1.2. Δίκτυα... 8 1.3. Επίπεδα ενός δικτύου... 11 1.3.1 Το Host-to-Network Layer... 14 1.3.2 Το Internet Layer... 15 1.3.3 Το Transport Layer... 17 1.3.4 Το Application Layer... 17 1.4. Τα πρωτόκολλα IP, TCP και UDP... 18 1.4.1 Διευθύνσεις IP και Domain Name... 19 1.4.2 Θύρες (Port)... 22 1.5. Το διαδίκτυο... 24 1.5.1 Ομάδες διευθύνσεων διαδικτύου... 24 1.5.2 Μετάφραση Διεύθυνσης Δικτύου (NAT)... 25 1.5.3 Τείχος προστασίας (Firewall)... 26 1.5.4 Διακομιστές Μεσολάβησης (Proxy Servers)... 27 1.6. Το μοντέλο Client / Server... 29 1.7. Διαδικτυακά Πρότυπα (Internet Standards)... 31 1.7.1 Τα RFC της IETF... 31 1.7.2 Οι συστάσεις του W3C... 36 2. Κανάλια επικοινωνίας συνεχούς ροής (Streams)... 38 2.1. Γενικά... 38 2.2. Ροές εξόδου (Output streams)... 39 2.3. Ροές εισόδου (Input streams)... 45 2.3.1 Σήμανση και Επαναφορά (Marking and Resetting)... 49 2.4. Φίλτρα Ροών (Filter Streams)... 50 2.4.1 Δημιουργία αλυσίδων φίλτρων... 52 2.4.2 Αποθηκευμένες ροές (Buffered streams)... 54 2.4.3 Ροή εκτύπωσης (PrintStream)... 56 2.4.4 Ροές δεδομένων (Data Streams)... 59 2.5. Οι κλάσεις Readers και Writers... 63 2.5.1 Η κλάση Writer... 64 2.5.2 Η υποκλάση OutputStreamWriter... 66 2.5.3 Η κλάση Reader... 67 2.5.4 Τα φίλτρα των κλάσεων Readers και Writers... 69 2.5.5 Η κλάση PrintWriter... 72 3. Νήματα (Threads)... 74-4-

3.1. Γενικά... 74 3.2. Λειτουργικά threads... 76 3.2.1 Thread υποκλάσεων... 77 3.2.2 Εφαρμογή της διεπαφής Runnable... 80 3.3. Επιστροφή πληροφοριών από την κλάση Thread... 82 3.3.1 Συνθήκες ανταγωνισμού (Race Conditions)... 85 3.3.2 Διαδοχική σταθμοσκόπηση (Polling)... 86 3.3.3 Αναστροφές κλήσης (Callbacks)... 88 3.3.4 Τα Future, Callable και Executor... 94 3.4. Συγχρονισμός... 96 3.4.1 Συγχρονισμένα μπλοκ (synchronized blocks)... 99 3.4.2 Συγχρονισμένες μέθοδοι... 102 3.4.3 Εναλλακτικές του συγχρονισμού... 103 3.5. Αδιέξοδο... 106 3.6. Χρονοδιάγραμμα thread... 107 3.6.1 Προτεραιότητες... 108 3.6.2 Παράκαμψη (Preemption)... 109 3.7. Δεξαμενές threads και οι κλάσεις Executor... 121 Βιβλιογραφία... 126-5-

Περίληψη Ιστορικά, ο δικτυακός προγραμματισμός υπήρξε μια δύσκολη, περίπλοκη και επιρρεπής σε λάθη διαδικασία επειδή ο εκάστοτε προγραμματιστής έπρεπε να γνωρίζει πολλές λεπτομέρειες σχετικά με το δίκτυο και μερικές φορές ακόμη και το hardware υλικό του. Ωστόσο, τα τελευταία χρόνια με την εμφάνιση της γλώσσας προγραμματισμού Java η έννοια της δικτύωσης πήρε μια άλλη διάσταση και μετατράπηκε σε εύκολη και σε γενικές γραμμές ασφαλή αποστολή και λήψη δεδομένων μέσω δικτύων υπολογιστών. Βασικός αρωγός στην απλοποίηση της όλης διαδικασίας δικτυακού προγραμματισμού αποτέλεσαν οι συγκεκριμένες δυνατότητες που παρέχει η Java για την ανάπτυξη σύνθετων δικτυακών εφαρμογών. Επομένως η γνώση της Java και των εργαλείων δικτυακού προγραμματισμού που προσφέρει, συνιστά βασική προϋπόθεση για τον προγραμματισμό των σύγχρονων δικτυακών συστημάτων, κάτι που αποτελεί και σκοπό της παρούσας πτυχιακής εργασίας. Αρχικά γίνεται μια αναφορά στα βασικά στοιχεία ενός δικτύου, εξηγώντας το πώς λειτουργεί ένα δίκτυο και το διαδίκτυο μέσω των πρωτοκόλλων TCP/IP και UDP/IP. Τα επόμενα δύο κεφάλαια ρίχνουν φως σε δύο πολύ βασικά μέρη του δικτυακού προγραμματισμού με Java: την διαχείριση των δεδομένων εισόδου / εξόδου (I/O) καθώς και το threading. Το κεφάλαιο 2, περιγράφει το πώς ο δικτυακός προγραμματισμός με Java διαχειρίζεται τα δεδομένα εισόδου / εξόδου των client εφαρμογών μέσω των streams. Το κεφάλαιο 3, ερευνά τις διεργασίες του multithreading και του συγχρονισμού των δεδομένων, εστιάζοντας στο πως οι διεργασίες αυτές μπορούν να χρησιμοποιηθούν σε περιπτώσεις ασύγχρονης μεταφοράς δεδομένων I/O και στους δικτυακούς server. -6-

1. Βασικά Χαρακτηριστικά Δικτύων 1.1. Εισαγωγή Ο δικτυακός προγραμματισμός δεν αποτελεί πλέον προνόμιο μερικών ειδικών αλλά έχει γίνει βασικό μέρος της εργαλειοθήκης κάθε προγραμματιστή. Σήμερα, τα περισσότερα προγράμματα έχουν δικτυακές εφαρμογές και εκτός από τις κλασσικές εφαρμογές όπως το email, τους περιηγητές του διαδικτύου και την απομακρυσμένη σύνδεση, οι περισσότερες βασικές αυτές εφαρμογές περιέχουν κάποιο επίπεδο δικτύωσης. Για παράδειγμα: Συντάκτες κειμένου όπως το BBEdit αποθηκεύουν και ανοίγουν αρχεία απευθείας από FTP servers IDE όπως το Eclipse και το IntelliJ IDEA επικοινωνούν απευθείας με αποθετήρια πηγαίου κώδικα όπως τα GitHub και Sourceforge Επεξεργαστές κειμένου όπως το Microsoft Word ανοίγουν αρχεία από διευθύνσεις URL Προγράμματα προστασίας από ιούς όπως το Norton AntiVirus ελέγχουν για νέους ορισμούς ιών με σύνδεση στην ιστοσελίδα του προμηθευτή κάθε φορά που ξεκινά ο υπολογιστής Προγράμματα αναπαραγωγής ήχου όπως τα Winamp και itunes ανεβάζουν στο CDDB, τη χρονική διάρκεια κάθε κομματιού που περιέχεται σε ένα CD και κατεβάζουν τον αντίστοιχο τίτλο του κομματιού Οι παίκτες που παίζουν παιχνίδια FPS όπως το Halo ανταγωνίζονται σε πραγματικό χρόνο Οι ταμειακές μηχανές των supermarket που τρέχουν το IBM SurePOS ACE επικοινωνούν με τον server του καταστήματος σε πραγματικό χρόνο με κάθε συναλλαγή. Ο server ανεβάζει τις ημερήσιες εισπράξεις στους κεντρικούς υπολογιστές της αλυσίδας κάθε βράδυ -7-

Οι εφαρμογές προγράμματος όπως το Microsoft Outlook συγχρονίζει αυτόματα τα ημερολόγια των υπαλλήλων μιας εταιρείας Η Java ήταν η πρώτη γλώσσα προγραμματισμού που σχεδιάστηκε από το μηδέν για εφαρμογές δικτύου και είχε αρχικά ως στόχο τους παρόχους δικτύων καλωδιακής τηλεόρασης και όχι το διαδίκτυο Μια από τις πρώτες πραγματικές εφαρμογές της Java ήταν ένας web browser. Καθώς το διαδίκτυο συνεχίζει να αυξάνεται, η Java ταιριάζει μοναδικά στην οικοδόμηση της επόμενης γενιάς των εφαρμογών δικτύου. Ένα από τα μεγαλύτερα μυστικά της Java είναι ότι κάνει τη συγγραφή των δικτυακών προγραμμάτων εύκολη υπόθεση. Πράγματι, είναι πολύ πιο εύκολο να γράψει κανείς δικτυακά προγράμματα σε Java από ότι σχεδόν σε οποιαδήποτε άλλη γλώσσα. Ο λόγος είναι ένας. Αν παρατηρήσει κανείς τις δικτυακές εφαρμογές που είναι γραμμένες σε Java θα δει πόσο λίγος κώδικας είναι αφιερωμένος στη δικτύωση. Ακόμη και σε δικτυακά προγράμματα υψηλής έντασης, όπως είναι οι web servers και οι clients, σχεδόν όλος ο κώδικας γράφεται για την διαχείριση των δεδομένων ή τη διεπαφή του χρήστη. Το τμήμα του κώδικα που ασχολείται με το δίκτυο είναι σχεδόν πάντα το μικρότερο και το απλούστερο. Εν συντομία, είναι εύκολο για τις εφαρμογές Java να αποστέλλουν και να λαμβάνουν δεδομένα μέσω του Internet. Το κεφάλαιο αυτό καλύπτει τις βασικές έννοιες του δικτύου που θα πρέπει να γίνουν κατανοητές πριν την συγγραφή δικτυακών προγραμμάτων σε Java. Με πέρασμα από το πιο γενικό στο πιο εξειδικευμένο, εξηγούνται γενικοί όροι των δικτυών, ειδικότερα των δικτύων IP καθώς και αυτών που βασίζονται στο TCP / IP, καθώς και το Διαδίκτυο. Στο κεφάλαιο αυτό δεν θα αναφερθούν θέματα όπως το πώς γίνεται η σύνδεση ενός δικτύου ή η ρύθμιση ενός router, αλλά το πώς θα πρέπει να γράφεται μια εφαρμογή που επικοινωνεί με το Internet. Τα θέματα που καλύπτονται σε αυτό το κεφάλαιο περιλαμβάνουν τη φύση των δικτύων, το μοντέλο επιπέδων TCP / IP, τα πρωτόκολλα IP, TCP και UDP, τα firewall και τους proxy server, το Διαδίκτυο και τη διαδικασία τυποποίησής του. 1.2. Δίκτυα Το δίκτυο είναι μια συλλογή από υπολογιστές και άλλες συσκευές που μπορούν να ανταλλάξουν δεδομένα μεταξύ τους, πάνω κάτω σε πραγματικό χρόνο. Ένα δίκτυο συχνά συνδέεται ενσύρματα και τα bits των δεδομένων μετατρέπονται σε ηλεκτρομαγνητικά κύματα που κινούνται μέσω των καλωδίων του. Στα ασύρματα δίκτυα τα δεδομένα μεταδίδονται μέσω ραδιοκυμάτων, ενώ στις πιο μεγάλες αποστάσεις χρησιμοποιούνται πλέον καλώδια -8-

οπτικών ινών μέσω των οποίων μεταδίδονται δεδομένα με τη μορφή κυμάτων φωτός. Όσον αφορά τα φυσικά μέσα για τη μετάδοση των δεδομένων αυτών, τίποτα δεν είναι απόλυτο. Θεωρητικά, τα δεδομένα μπορούν να μεταδίδονται από υπολογιστές που καίνε κάρβουνο και που στέλνουν σήματα καπνού ο ένας στον άλλο. Ο χρόνος απόκρισης (και οι περιβαλλοντικές επιπτώσεις) ενός τέτοιου δικτύου θα ήταν μάλλον κακός. Κάθε μηχάνημα σε ένα δίκτυο ονομάζεται κόμβος. Οι περισσότεροι κόμβοι είναι υπολογιστές, εκτυπωτές, δρομολογητές, γέφυρες, πύλες, απλά τερματικά. Ακόμα και μηχανήματα της Coca-Cola μπορεί επίσης να είναι κόμβοι. Χρήση της Java θα μπορούσε να γίνει για τη διασύνδεση με μια μηχανή της Coca-Cola, όμως το καλύτερο θα ήταν να χρησιμοποιηθεί για την επικοινωνία με άλλους υπολογιστές. Οι κόμβοι οι οποίοι είναι πλήρως λειτουργικοί υπολογιστές αναφέρονται επίσης και ως hosts. Στην παρούσα πτυχιακή εργασία θα χρησιμοποιηθεί ο όρος κόμβος για την αναφορά σε οποιαδήποτε συσκευή του δικτύου και ο όρος host για την αναφορά σε ένα κόμβο που είναι υπολογιστής γενικής χρήσης. Κάθε κόμβος του δικτύου έχει μια διεύθυνση, μια ακολουθία από byte που τον προσδιορίζει με μοναδικό τρόπο. Αυτή η ομάδα των byte μπορεί να νοηθεί ως αριθμός, αλλά σε γενικές γραμμές ο αριθμός των byte σε μία διεύθυνση ή η σειρά των εν λόγω byte (big endian ή little endian) δεν είναι σίγουρο ότι ταιριάζει με κανένα πρωτόγονο τύπο αριθμητικών δεδομένων της Java. Όσο περισσότερα byte υπάρχουν σε κάθε διεύθυνση, τόσο περισσότερες διευθύνσεις υπάρχουν διαθέσιμες και τόσο περισσότερες συσκευές μπορούν να συνδεθούν ταυτόχρονα στο δίκτυο. Οι διευθύνσεις αποδίδονται με διαφορετικό τρόπο σε διαφορετικά είδη δικτύων. Οι διευθύνσεις Ethernet συνδέονται με το φυσικό hardware υλικό Ethernet. Οι κατασκευαστές του hardware Ethernet χρησιμοποιούν προκαθορισμένους κωδικούς κατασκευής για να εξασφαλίσουν ότι δεν θα υπάρχουν συγκρούσεις μεταξύ των διευθύνσεων του υλικού τους και των διευθύνσεων του υλικού άλλων κατασκευαστών. Κάθε κατασκευαστής είναι υπεύθυνος για τη διασφάλιση ότι δύο κάρτες Ethernet δεν έχουν την ίδια διεύθυνση. Οι διευθύνσεις στο Διαδίκτυο συνήθως εκχωρούνται στους υπολογιστές από τον πάροχο του δικτύου. Ωστόσο, οι διευθύνσεις που ο εκάστοτε πάροχος επιτρέπεται να επιλέξει για τους υπολογιστές του, ανατίθενται από τον οργανισμό παρόχων υπηρεσιών Internet (Internet service provider - ISP). Οι ISP παίρνουν τις IP διευθύνσεις τους από ένα από τα τέσσερα περιφερειακά μητρώα του Internet (το μητρώο για τη Βόρεια Αμερική είναι το American -9-

Registry for Internet Numbers - ARIN), στο οποία οι διευθύνσεις IP έχουν ανατεθεί με τη σειρά τους από το Internet Corporation for Assigned Names and Numbers (ICANN). Σε ορισμένα είδη δικτύων, οι κόμβοι έχουν ονόματα που βοηθούν στον προσδιορισμό τους, όπως "www.elharo.com" ή " Beth Harold s Computer". Σε μια συγκεκριμένη χρονική στιγμή, ένα συγκεκριμένο όνομα αναφέρεται συνήθως σε μία και μόνο διεύθυνση. Ωστόσο, τα ονόματα δεν είναι κλειδωμένα στις διευθύνσεις. Τα ονόματα μπορεί να αλλάξουν, ενώ οι διευθύνσεις παραμείνουν οι ίδιες. Ομοίως, οι διευθύνσεις μπορούν να αλλάξουν, ενώ τα ονόματα παραμένουν τα ίδια. Μια διεύθυνση μπορεί να έχει πολλά ονόματα και ένα όνομα μπορεί να αναφέρεται σε πολλές διαφορετικές διευθύνσεις. Όλα τα σύγχρονα δίκτυα υπολογιστών είναι δίκτυα μεταγωγής πακέτων: τα δεδομένα που ταξιδεύουν στο δίκτυο χωρίζονται σε κομμάτια που ονομάζονται πακέτα και κάθε πακέτο αντιμετωπίζεται ξεχωριστά. Κάθε πακέτο περιέχει πληροφορίες σχετικά με το ποιος το έστειλε και το πού πηγαίνει. Το πιο σημαντικό πλεονέκτημα της διάσπασης των δεδομένων σε μεμονωμένα πακέτα είναι ότι τα πακέτα, παρά τις πολλές και συνεχείς ανταλλαγές, μπορούν να ταξιδέψουν μέσω ενός και μόνο καλωδίου, γεγονός που σημαίνει μειωμένο κόστος δημιουργίας ενός δικτύου. Πολλοί υπολογιστές μπορούν να μοιράζονται το ίδιο καλώδιο χωρίς να υπάρχουν παρεμβολές. Για να γίνει κατανοητό το πλεονέκτημα αυτής της διεργασίας, αρκεί να δούμε ότι σε μια τοπική τηλεφωνική κλήση μέσω μιας παραδοσιακής τηλεφωνικής γραμμής, μια γραμμή βασικά διατηρείται για την επικοινωνία δύο τηλεφώνων. Όταν όλες οι γραμμές είναι σε χρήση, όπως συμβαίνει μερικές φορές κατά τη διάρκεια μιας σοβαρής κατάστασης έκτακτης ανάγκης ή κατά τη διάρκεια των διακοπών, οποιοσδήποτε κι αν προσπαθήσει να τηλεφωνήσει δεν θα μπορέσει να πάρει ήχο κλήσης. Αν παραμείνει στη γραμμή, θα πάρει τελικά έναν ήχο κλήσης όταν κάποια άλλη γραμμή απελευθερωθεί. Σε ορισμένες χώρες με χειρότερη τηλεφωνική υπηρεσία από τις Ηνωμένες Πολιτείες, δεν είναι ασυνήθιστο το φαινόμενο της αναμονής μισής ώρας ή περισσότερο για την απελευθέρωση γραμμής. Ένα άλλο πλεονέκτημα των πακέτων είναι ότι μπορούν να χρησιμοποιηθούν αθροίσματα ελέγχου (checksums) για την ανίχνευση πιθανής καταστροφής του πακέτου κατά τη μεταφορά. Λείπει ακόμα ένα σημαντικό κομμάτι: κάποια ιδέα για το τι πληροφορίες πρέπει να ανταλλάξουν οι υπολογιστές για την μεταφορά των δεδομένων. Ένα πρωτόκολλο είναι ένα ακριβές σύνολο κανόνων που καθορίζουν το πώς επικοινωνούν οι υπολογιστές: τη μορφή των διευθύνσεων, πώς τα δεδομένα χωρίζονται σε πακέτα, και ούτω καθεξής. Υπάρχουν πολλά διαφορετικά πρωτόκολλα που καθορίζουν τις διάφορες πτυχές της επικοινωνίας ενός δικτύου. -10-

Για παράδειγμα, το πρωτόκολλο Hypertext Transfer Protocol (HTTP) καθορίζει το πώς επικοινωνούν οι web browsers και servers. Στο άλλο άκρο του φάσματος, το πρότυπο ΙΕΕΕ 802.3 ορίζει ένα πρωτόκολλο για το πώς τα bit κωδικοποιούνται ως ηλεκτρικά σήματα σε ένα συγκεκριμένο τύπο καλωδίου. Τα ελεύθερα πρότυπα πρωτοκόλλων επιτρέπει σε λογισμικά και εξοπλισμό από διαφορετικούς κατασκευαστές να επικοινωνούν μεταξύ τους. Ένας web server δεν ενδιαφέρεται για το αν o client είναι σταθμός εργασίας Unix, ένα τηλέφωνο Android, ή ένα ipad, επειδή όλοι οι client επικοινωνούν μέσω του ίδιου πρωτοκόλλου HTTP ανεξάρτητα από την πλατφόρμα. 1.3. Επίπεδα ενός δικτύου Η αποστολή δεδομένων σε ένα δίκτυο είναι μια σύνθετη λειτουργία που θα πρέπει να ρυθμιστεί προσεκτικά ανάλογα με τα φυσικά χαρακτηριστικά του δικτύου, καθώς και με τον λογικό χαρακτήρα των δεδομένων που αποστέλλονται. Το λογισμικό που χρησιμοποιείται για την αποστολή αυτή θα πρέπει να είναι σχεδιασμένο κατάλληλα ώστε να αποφεύγονται οι συγκρούσεις μεταξύ των πακέτων, να γίνεται σωστά η μετατροπή των ψηφιακών δεδομένων σε αναλογικά, να εντοπίζονται και να διορθώνονται τα όποια προβλήματα, να δρομολογούνται σωστά τα πακέτα από τον ένα host στον άλλο, κ.α. Η διαδικασία περιπλέκεται περαιτέρω όταν προστίθεται και η απαίτηση υποστήριξης πολλαπλών λειτουργικών συστημάτων και ετερογενών τρόπων σύνδεσης των μερών του δικτύου. Για να μπορέσει να μην είναι εμφανές το μεγαλύτερο μέρος αυτής της πολυπλοκότητας, οι διάφορες πτυχές της επικοινωνίας του δικτύου χωρίζονται σε πολλαπλά επίπεδα (layer). Κάθε layer αντιπροσωπεύει ένα διαφορετικό επίπεδο μεταξύ του φυσικού υλικού (δηλαδή, καλώδια και ηλεκτρική ενέργεια) και των πληροφοριών που διαβιβάζονται. Θεωρητικά, κάθε layer επικοινωνεί απευθείας μόνο με τα layer που βρίσκονται ακριβώς πάνω και κάτω από αυτό. Ο διαχωρισμός του δικτύου σε layer επιτρέπει την τροποποίηση ή ακόμη και αντικατάσταση του λογισμικού σε ένα layer, χωρίς να επηρεάζονται τα υπόλοιπα, εφ 'όσον οι διεπαφές μεταξύ των layer παραμένουν οι ίδιες. Η εικόνα 1 απεικονίζει μια στοίβα (stack) από πιθανά πρωτόκολλα που μπορεί να υπάρχουν σε ένα δίκτυο. Ενώ τα πρωτόκολλα του μεσαίου layer χρησιμοποιούνται στις περισσότερες εφαρμογές του διαδικτύου σήμερα, αυτά που βρίσκονται στο πάνω και στο layer διαφέρουν ανάλογα με τον host. Όσον αφορά την σύνδεσή τους με το διαδίκτυο, μερικοί host χρησιμοποιούν Ethernet, κάποιοι άλλοι WiFi, ορισμένοι χρησιμοποιούν PPP, ορισμένοι χρησιμοποιούν κάτι άλλο. Παρομοίως, το τι πρωτόκολλο θα υπάρχει στην κορυφή του stack -11-

θα εξαρτηθεί πλήρως από το ποια προγράμματα τρέχουν στον host. Αυτό όμως που έχει σημασία είναι ότι, το πρωτόκολλο που υπάρχει στην κορυφή είναι ανεξάρτητο από αυτό που υπάρχει στην βάση του stack και το αντίστροφο. Το μοντέλο των layer διαχωρίζει τα πρωτόκολλα εφαρμογών από τα φυσικά υλικά του δικτύου και την τοπολογία των συνδέσεων του δικτύου. Εικόνα 1: Πρωτόκολλα σε διάφορα layer ενός δικτύου Υπάρχουν πολλά διαφορετικά μοντέλα layer, καθένα οργανωμένο με τέτοιο τρόπο ώστε να ταιριάζει στις ανάγκες ενός συγκεκριμένου είδος δικτύου. Στην παρούσα πτυχιακή εργασία χρησιμοποιείται το πρότυπο μοντέλο TCP / IP τεσσάρων layer κατάλληλο για το διαδίκτυο (Εικ.2). Σε αυτό το μοντέλο, όλες οι εφαρμογές τρέχουν στο επίπεδο εφαρμογών (application layer) και επικοινωνούν μόνο με το επίπεδο μεταφοράς (transport layer). Το transport layer επικοινωνεί μόνο με το application layer και τη διαστρωμάτωση διαδικτύου (Internet layer). Με τη σειρά του το Internet layer επικοινωνεί μόνο με το επίπεδο διασύνδεσης μεταξύ υπολογιστή υπηρεσίας και δικτύου (host-to-network layer) και το transport layer, ποτέ άμεσα με το application layer. Το host-to-network layer μεταφέρει τα δεδομένα μέσω καλωδίων, οπτικών ινών, ή άλλου μέσου στο host-to-network layer του απομακρυσμένου συστήματος, το οποίο στη συνέχεια μεταφέρει τα δεδομένα μέσω των αντίστοιχων επιπέδων μέχρι την εφαρμογή του απομακρυσμένου συστήματος. -12-

Εικόνα 2: Layer ενός δικτύου Για παράδειγμα, όταν ένας web browser στέλνει μια αίτηση σε ένα web server για να ανακτήσει μια σελίδα, ο browser στην πραγματικότητα μιλάει με το transport layer του τοπικού client υπολογιστή. Το port του transport layer σπάει σε TCP segment, προσθέτει μερικούς αριθμούς ακολουθίας και αθροίσματα ελέγχου στα δεδομένα και στη συνέχεια μεταβιβάζει την αίτηση στο τοπικό internet layer. Το internet layer κατακερματίζει τα segment σε IP datagram στο απαραίτητο μέγεθος για το τοπικό δίκτυο και τα περνά στο hostto-network layer για τη μετάδοση προς το δίκτυο. Το host-to-network layer κωδικοποιεί τα ψηφιακά δεδομένα σε αναλογικά σήματα κατάλληλα ανάλογα με το φυσικό μέσο διασύνδεσης του δικτύου και στέλνει την αίτηση μέσω του καλωδίου σύνδεσης προς το hostto-network layer του απομακρυσμένου συστήματος στο οποίο απευθύνεται. Το host-to-network layer του απομακρυσμένου συστήματος αποκωδικοποιεί τα αναλογικά σήματα σε ψηφιακά δεδομένα και στη συνέχεια περνά τα προκύπτοντα IP datagram στο internet layer του server. Το internet layer κάνει μερικούς απλούς ελέγχους για να δει ότι τα IP datagram δεν έχουν υποστεί αλλοιώσεις, τα ανασυγκροτεί αν έχουν κατακερματιστεί και τα περνάει προς το transport layer του server. Το transport layer του server ελέγχει για να δει ότι όλα τα δεδομένα έχουν φτάσει και ζητά αναμετάδοση των κομματιών που είτε λείπουν είτε είναι κατεστραμμένα. Αυτό το αίτημα στην πραγματικότητα πηγαίνει πίσω στο σύστημα του client, μέσω των intenet layer και host-to-network layer του server. Στο σύστημα του client τελικά φτάνει στο transport layer, το οποίο επανεκπέμπει τα δεδομένα που λείπουν πίσω, προς τον server μέσω των ίδιων layer. Η όλη διαδικασία δεν γίνεται αντιληπτή από το application layer. Όταν το transport layer του server λάβει αρκετά συνεχόμενα και διαδοχικά datagram, τα ανασυγκροτεί και δημιουργεί μία συνεχή ροή δεδομένων (stream) που διαβάζεται από τον web server που τρέχει στο application layer του server. Ο server απαντά στο αίτημα και αποστέλλει την απόκριση του πίσω μέσω όλων των layer του συστήματός του, η οποία φτάνει στον web client μέσω του διαδικτύου. -13-

Στην πραγματικότητα βέβαια, η όλη διαδικασία είναι πολύ πιο περίτεχνη. Το host-to-network layer είναι μακράν το πιο πολύπλοκο και πολλές διαδικασίες είναι εσκεμμένα κρυμμένες. Για παράδειγμα, είναι δυνατόν, τα δεδομένα που αποστέλλονται μέσω του Internet, να περάσουν μέσα από διάφορους δρομολογητές και τα layer τους, πριν φθάσουν στον τελικό προορισμό τους. Μπορεί να χρειαστεί να μετατραπούν από ραδιοκύματα που μεταφέρονται μέσω του αέρα σε ηλεκτρικά σήματα που μεταφέρονται μέσω καλωδίων ή σε παλμούς φωτός που μεταφέρονται μέσω οπτικών ινών και το αντίστροφο, ίσως περισσότερο από μία φορά. Ωστόσο, το 90% του κώδικα της Java ασχολείται με το application layer και την επικοινωνία του με το transport layer. Το υπόλοιπο 10%, ασχολείται με την επικοινωνία του transport layer με το application layer ή το internet layer. Η πολυπλοκότητα του host-to-network layer παραμένει κρυμμένη. Αυτός είναι άλλωστε και ο σκοπός του μοντέλου επιπέδων. Το application layer φαίνεται σαν να επικοινωνεί απευθείας με το application layer του άλλου συστήματος. Το δίκτυο δημιουργεί ένα λογικό μονοπάτι επικοινωνίας ανάμεσα στα δύο application layer. Για να γίνει ευκολότερα κατανοητό ένα τέτοιο λογικό μονοπάτι, ας δούμε τι συμβαίνει σε μια συνεδρία IRC chat. Οι περισσότεροι συμμετέχοντες σε μια συνομιλία IRC θα έλεγαν ότι επικοινωνούν με ένα άλλο πρόσωπο. Αν τους ζητηθεί να το αναλύσουν περαιτέρω, θα μπορούσαν να πούνε ότι μιλάνε με τον υπολογιστή τους (στην πραγματικότητα με το application layer), το οποίο μιλάει με τον υπολογιστή του άλλου ατόμου, που μιλάει με το άλλο πρόσωπο. Οτιδήποτε πιο κάτω από ένα layer είναι αποτελεσματικά αόρατο και έτσι ακριβώς πρέπει να είναι. Ας εξετάσουμε κάθε layer με περισσότερες λεπτομέρειες.. 1.3.1 Το Host-to-Network Layer Ένας προγραμματιστής Java είναι αρκετά ψηλά στην τροφική αλυσίδα του δικτύου και πολλά συμβαίνουν κάτω από το ραντάρ του. Στο καθιερωμένο μοντέλο αναφοράς των IP-based Internets (το μόνο είδος δικτύου που η Java καταλαβαίνει πραγματικά), τα κρυμμένα τμήματα του δικτύου ανήκουν στο host-to-network layer, επίσης γνωστό και ως επίπεδο ζεύξης (link layer), επίπεδο ζεύξης δεδομένων (data link layer), επίπεδο διεπαφής δικτύου (network interface layer). Το host-to-network layer καθορίζει το πώς μια συγκεκριμένη διεπαφή δικτύου, όπως μια κάρτα Ethernet ή μια κεραία WiFi, στέλνει IP datagram μέσω της φυσικής σύνδεσής του με το τοπικό δίκτυο και τον κόσμο. Το κομμάτι του host-to-network layer που αποτελείται από το hardware υλικό που συνδέει τους διάφορους υπολογιστές (δηλαδή τα καλώδια, οι οπτικές ίνες, τα ραδιοκύματα, ή τα σήματα καπνού) ονομάζεται μερικές φορές ως φυσικό επίπεδο (physical layer) του δικτύου. -14-

Οι προγραμματιστές Java, δεν χρειάζεται να ανησυχούν για το layer αυτό, εκτός αν κάτι πάει στραβά, όπως το βύσμα να βγει από το πίσω μέρος του υπολογιστή, ή κάποιος να κόψει την T-1 γραμμή σύνδεσης με τον υπόλοιπο κόσμο. Με άλλα λόγια, η Java δεν βλέπει ποτέ το φυσικό επίπεδο. Ο κύριος λόγος που ένας προγραμματιστής Java μπορεί να ασχοληθεί με το host-to-network layer και το φυσικό επίπεδο, αν ασχοληθεί ποτέ, είναι η απόδοση τους. Για παράδειγμα, ένα πρωτόκολλο και οι εφαρμογές του θα πρέπει να σχεδιαστούν διαφορετικά για ένα δίκτυο που είναι στημένο με γρήγορες, αξιόπιστες συνδέσεις οπτικών ινών και διαφορετικά αν είναι στημένο με υψηλής ανοχής δορυφορικές συνδέσεις και βρίσκεται σε μια εξέδρα άντλησης πετρελαίου στη Βόρεια Θάλασσα. Επίσης, διαφορετικές θα πρέπει να είναι οι επιλογές εάν οι χρήστες του δικτύου βρίσκονται σε ένα πρόγραμμα δεδομένων 3G όπου χρεώνονται με βάση τα byte για σχετικά χαμηλού εύρους ζώνη. Ή ακόμα αν θα πρέπει να δημιουργηθεί μια γενική εφαρμογή καταναλωτών που θα μπορούσε να χρησιμοποιηθεί από οποιονδήποτε από αυτούς τους χρήστες, ο σχεδιασμός θα πρέπει να γίνει με το κριτήριο της χρυσής τομής ή ίσως ακόμη και με βάση τον εντοπισμό και την δυναμική προσαρμογή στις ατομικές ικανότητες του εκάστοτε χρήστη. Ωστόσο, όποιες κι αν είναι οι φυσικές συνδέσεις, τα API που χρησιμοποιούνται για την επικοινωνία μέσω αυτών των δικτύων είναι τα ίδια. Αυτό που κάνει κάτι τέτοιο δυνατό είναι το internet layer. 1.3.2 Το Internet Layer Το επόμενο επίπεδο του δικτύου, και το πρώτο που θα πρέπει να ασχοληθεί ένας προγραμματιστής Java, είναι το internet layer. Στο μοντέλο OSI, το internet layer έχει το πιο γενικό όνομα επίπεδο δικτύου (network layer). Ένα πρωτόκολλο αυτού του layer καθορίζει τον τρόπο με τον οποίο τα bit και byte των δεδομένων οργανώνονται σε μεγαλύτερες ομάδες που ονομάζονται πακέτα, καθώς και το σύστημα διευθυνσιοδότησης με το οποίο διαφορετικά μηχανήματα βρίσκουν το ένα το άλλο. Το Internet Protocol (IP) είναι το πιο ευρέως χρησιμοποιούμενο πρωτόκολλο επιπέδου δικτύου στον κόσμο και το μόνο πρωτόκολλο επιπέδου δικτύου που καταλαβαίνει η Java. Στην πραγματικότητα, πρόκειται για δύο πρωτόκολλα: το IPv4, που χρησιμοποιεί διευθύνσεις 32-bit, και το IPv6, το οποίο χρησιμοποιεί διευθύνσεις 128-bit και περιέχει κάποια επιπρόσθετα τεχνικά χαρακτηριστικά που βοηθούν στη δρομολόγηση. Αυτή τη στιγμή, το IPv4 εξακολουθεί να αντιπροσωπεύει περισσότερο από το 90% της κίνησης στο Διαδίκτυο. Παρόλο που πρόκειται για δύο πολύ διαφορετικά πρωτόκολλα δικτύου που δεν -15-

συνεργάζονται στο ίδιο δίκτυο χωρίς ειδικές πύλες (gateway) ή / και πρωτόκολλα ενθυλάκωσης, η Java καταφέρνει να αποκρύψει σχεδόν όλες τις διαφορές από τους προγραμματιστές. Τόσο στο IPv4 όσο και στο IPv6, τα δεδομένα αποστέλλονται μέσω του internet layer σε πακέτα που ονομάζονται datagram. Κάθε datagram του IPv4 περιέχει μια κεφαλίδα (heading) των 20 με 60 byte και σώμα (payload) που περιέχει μέχρι 65.515 byte δεδομένων. Στην πράξη, τα περισσότερα IPv4 datagram είναι πολύ μικρότερα, που κυμαίνονται από μερικές δεκάδες byte έως λίγο παραπάνω από 8 kilobyte. Ένα IPv6 datagram περιέχει μια μεγαλύτερη κεφαλίδα και μέχρι 4 gigabyte δεδομένων. Στην εικόνα 3 απεικονίζονται οι θέσεις των διαφορετικών στοιχείων που περιλαμβάνει ένα IPv4 datagram. Όλα τα bit και byte είναι big endian, με τα πιο σημαντικά (MSB) να βρίσκονται προς τα αριστερά και τα λιγότερο σημαντικά (LSB) προς τα δεξιά. Εικόνα 3: Δομή ενός IPv4 datagram Εκτός από τη δρομολόγηση και τη διευθυνσιοδότηση, ο δεύτερος σκοπός του internet layer είναι να επιτρέψει σε διαφορετικούς τύπους host-to-network layer να επικοινωνήσουν μεταξύ τους. Οι δρομολογητές διαδικτύου μπορούν να μεταφράσουν τους διάλογους μεταξύ WiFi και Ethernet, Ethernet και DSL, DSL και πρωτόκολλα οπτικών ινών backhaul, και ούτω καθεξής. Χωρίς το internet layer ή κάτι σαν αυτό, κάθε υπολογιστής θα μπορούσε να επικοινωνήσει μόνο με υπολογιστές που θα μοιράζονταν τον ίδιο τύπο δικτύου. Το internet layer είναι υπεύθυνο για τη σύνδεση ετερογενών μεταξύ τους δικτύων, χρησιμοποιώντας ομοιογενή πρωτόκολλα. -16-

1.3.3 Το Transport Layer Τα ακατέργαστα (raw) datagram έχουν κάποια μειονεκτήματα. Πιο συγκεκριμένα, δεν υπάρχει καμία εγγύηση ότι θα παραδοθούν. Ακόμα κι αν παραδοθούν, μπορεί να έχουν καταστραφεί κατά τη μεταφορά. Το άθροισμα ελέγχου της κεφαλίδας (header checksum) μπορεί να ανιχνεύσει μόνο την καταστροφή στην κεφαλίδα και όχι στο τμήμα των δεδομένων ενός datagram. Τέλος, ακόμη και αν αυτά τα datagram φτάσουν ακέραια, δεν είναι απαραίτητο ότι θα φτάσουν με τη σειρά με την οποία στάλθηκαν. Μεμονωμένα datagram μπορεί να ακολουθήσουν διαφορετικές διαδρομές από την πηγή στον προορισμό. Ότι το datagram Α στάλθηκε πριν από το datagram Β, δεν σημαίνει αυτομάτως ότι θα φτάσει και πριν από το datagram Β. Το transport layer είναι υπεύθυνο για τη διασφάλιση ότι τα πακέτα λαμβάνονται με τη σειρά που είχαν αποσταλεί και ότι δεν υπάρχουν δεδομένα που έχουν χαθεί ή έχουν καταστραφεί. Αν ένα πακέτο έχει χαθεί, το transport layer μπορεί να ζητήσει από τον αποστολέα να αναμεταδώσει το πακέτο. Τα IP δίκτυα εφαρμόζουν αυτό τον έλεγχο με την προσθήκη μιας επιπλέον κεφαλίδας σε κάθε datagram που περιέχει περισσότερες πληροφορίες. Υπάρχουν δύο βασικά πρωτόκολλα σε αυτό το επίπεδο. Το πρώτο, το πρωτόκολλο TCP (Transmission Control), είναι πρωτόκολλο υψηλού overhead που επιτρέπει την αναμετάδοση των χαμένων ή κατεστραμμένων δεδομένων και παράδοση των byte με τη σειρά που στάλθηκαν. Το δεύτερο πρωτόκολλο, το User Datagram Protocol (UDP), επιτρέπει στον δέκτη να ανιχνεύει κατεστραμμένα πακέτα, αλλά δεν εγγυάται ότι τα πακέτα θα παραδοθούν με τη σωστή σειρά (ή αν παραδοθούν καθόλου). Ωστόσο, το UDP είναι συχνά πολύ γρηγορότερο από το TCP. Το TCP αναφέρεται και ως αξιόπιστο πρωτόκολλο, ενώ το UDP είναι ένα αναξιόπιστο πρωτόκολλο. Αργότερα, θα δούμε ότι τα αναξιόπιστα πρωτόκολλα είναι πολύ πιο χρήσιμα από ότι ακούγεται. 1.3.4 Το Application Layer Το layer που παρέχει δεδομένα στον χρήστη ονομάζεται application layer. Τα τρία χαμηλότερα layer συνεργάζονται για να καθορίσουν τον τρόπο μεταφοράς των δεδομένων από έναν υπολογιστή σε άλλο. Το application layer αποφασιζει τι να κανει με τα δεδομένα αφού έχουν διαβιβασθεί. Για παράδειγμα, ένα πρωτόκολλο εφαρμογής (application protocol), όπως είναι το HTTP (για το World Wide Web), σιγουρεύεται ότι ο περιηγητής του χρήστη εμφανίζει ένα γραφικό ως εικόνα και όχι ως ένα μακρύ stream από αριθμούς. Το application layer είναι το layer όπου τα περισσότερα από τα τμήματα του δικτύου των προγραμμάτων -17-

περνούν το χρόνο τους. Υπάρχει μια ολόκληρη σειρά πρωτοκόλλων επιπέδου εφαρμογής: εκτός από το HTTP για το Web, υπάρχουν τα SMTP, POP και IMAP για το ηλεκτρονικό ταχυδρομείο, τα FTP, FSP και TFTP για μεταφορά αρχείων, το NFS για πρόσβαση αρχείων, τα Gnutella και BitTorrent για κοινή χρήση αρχείων, το Session Initiation Protocol (SIP) και το Skype για επικοινωνία φωνής και πολλά άλλα. Επιπλέον, τα προγράμματα μπορούν να καθορίσουν το δικό τους πρωτόκολλο επιπέδου εφαρμογής, αν απαιτείται. 1.4. Τα πρωτόκολλα IP, TCP και UDP Το πρωτόκολλο διαδικτύου (Internet Protocol IP) αναπτύχθηκε με στρατιωτική χορηγία κατά τη διάρκεια του Ψυχρού Πολέμου και κατέληξε με πολλά χαρακτηριστικά γνωρίσματα που ενδιέφεραν το στρατό. Πρώτα απ όλα, θα έπρεπε να είναι εύρωστο. Το σύνολο του δικτύου δεν μπορούσε να σταματήσει να λειτουργεί εάν, για παράδειγμα, οι Σοβιετικοί έριχναν πυρηνικά σε ένα δρομολογητή στο Cleveland. Όλα τα μηνύματα θα έπρεπε να φτάσουν στο προορισμό τους, εκτός φυσικά από αυτά που προορίζονταν για το Cleveland. Ως εκ τούτου, το IP σχεδιάστηκε για να επιτρέπει πολλαπλές διαδρομές μεταξύ δύο οποιωνδήποτε σημείων και τη δρομολόγηση πακέτων δεδομένων γύρω από κατεστραμμένους δρομολογητές. Δεύτερον, ο στρατός είχε πολλά διαφορετικά είδη υπολογιστών τα οποία θα έπρεπε να είναι σε θέση να επικοινωνούν μεταξύ τους. Ως εκ τούτου, το IP θα έπρεπε να είναι ανοικτό και ανεξάρτητο από οποιαδήποτε πλατφόρμα. Δεν θα ήταν αρκετά καλό να υπάρχει ένα πρωτόκολλο μόνο για τους υπολογιστές της IBM και ένα άλλο για τους αντίστοιχους της PDP-11. Οι υπολογιστές της IBM θα έπρεπε να επικοινωνούν με τους PDP-11 και οποιουσδήποτε άλλους διαφορετικούς υπολογιστές που μπορεί να βρίσκονται γύρω. Λόγω της ύπαρξης πολλών διαδρομών ανάμεσα σε δύο σημεία και επειδή ο πιο γρήγορος δρόμος μεταξύ τους μπορεί να αλλάξει με την πάροδο του χρόνου ως συνάρτηση της κίνησης του δικτύου αλλά και άλλων παραγόντων (όπως για παράδειγμα η περίπτωση του Cleveland), τα πακέτα που απαρτίζουν ένα ιδιαίτερο stream δεδομένων δεν μπορούν να κάνουν όλα την ίδια διαδρομή. Επιπλέον, δεν μπορούν να φτάσουν με τη σειρά που είχαν αποσταλεί και βέβαια υπάρχει και η περίπτωση να μην φτάσουν καθόλου. Για να βελτιωθεί το βασικό σύστημα, πάνω από το IP δημιουργήθηκε ένα layer, το TCP, με σκοπό να δώσει σε κάθε άκρο της σύνδεσης τη δυνατότητα να γνωρίζει τη λήψη των πακέτων IP και του αιτήματος της αναμετάδοσης των χαμένων ή κατεστραμμένων πακέτων. Επιπλέον, το TCP επιτρέπει την ανασυγκρότηση των πακέτων που έχουν ληφθεί με την ίδια σειρά που είχαν αποσταλεί. -18-

Πάντως το TCP περιέχει αρκετό overhead και ως εκ τούτου, εάν η σειρά των δεδομένων δεν είναι ιδιαίτερα σημαντική και αν η απώλεια των ατομικών πακέτων δεν αλλοιώνει εντελώς το stream των δεδομένων, τότε υπάρχουν φορές που τα πακέτα αποστέλλονται χωρίς τις εγγυήσεις που παρέχει το πρωτόκολλο TCP, χρησιμοποιώντας το πρωτόκολλο UDP. Το UDP είναι ένα αναξιόπιστο πρωτόκολλο που δεν εγγυάται ότι τα πακέτα θα φτάσουν στον προορισμό τους ή ότι θα φτάσουν στην ίδια σειρά με την οποία στάλθηκαν. Αν και αυτό θα ήταν ένα πρόβλημα για χρήσεις όπως η μεταφορά αρχείων, είναι απολύτως αποδεκτό για εφαρμογές όπου η απώλεια κάποιων δεδομένων θα περάσει απαρατήρητη από τον τελικό χρήστη. Για παράδειγμα, η απώλεια κάποιων bit από ένα βίντεο ή ηχητικό σήμα δεν θα προκαλέσει μεγάλη υποβάθμιση της αναπαραγωγής του βίντεο ή του ηχητικού σήματος και δεν θα προκαλέσει μεγαλύτερο πρόβλημα από αυτό που θα μπορούσε να δημιουργηθεί εάν θα έπρεπε να υπάρχει αναμονή από ένα πρωτόκολλο όπως το TCP να ζητήσει αναμετάδοση των δεδομένων που λείπουν. Επιπλέον, υπάρχει δυνατότητα ενσωμάτωσης κώδικα διόρθωσης σφαλμάτων στα UDP stream δεδομένων στο application layer που μπορούν να ασχοληθούν με τα δεδομένα που λείπουν. Πάνω από το IP μπορεί να τρέξει μια σειρά από άλλα πρωτόκολλα. Το πιο συχνά χρησιμοποιούμενο είναι το πρωτόκολλο ελέγχου μηνυμάτων διαδικτύου (Internet Control Message Protocol ICMP), το οποίο χρησιμοποιεί raw IP datagram για την αναμετάδοση μηνυμάτων λάθους μεταξύ των host. Η πιο γνωστή χρήση του πρωτοκόλλου αυτού είναι το πρόγραμμα ping. Η Java δεν υποστηρίζει το ICMP αλλά ούτε και επιτρέπει την αποστολή raw IP datagram (σε αντίθεση με τα TCP segment ή τα UDP datagram). Τα μόνα πρωτόκολλα που υποστηρίζει η Java είναι τα TCP και UDP, καθώς και τα πρωτόκολλα επιπέδου εφαρμογής που δημιουργούνται με βάση αυτά. Όλα τα υπόλοιπα πρωτόκολλα των transport layer, internet layer και χαμηλότερων layer, όπως το ICMP, IGMP, ARP, RARP, RSVP, κ.α. μπορούν να υλοποιηθούν σε προγράμματα Java μόνο με σύνδεση σε εγγενή κώδικα. 1.4.1 Διευθύνσεις IP και Domain Name Ένας προγραμματιστής Java, δεν χρειάζεται να ανησυχεί για τις εσωτερικές λειτουργίες του IP, αλλά χρειάζεται να γνωρίζει για τη διευθυνσιοδότηση. Κάθε υπολογιστής σε ένα δίκτυο IPv4 αναγνωρίζεται από μια σειρά τεσσάρων byte που γράφονται συνήθως σε dotted quad format, όπως 199.1.32.90, όπου κάθε ένας από τους τέσσερις αριθμούς είναι ένα μη προσημασμένο byte με τιμή που κυμαίνεται από 0 έως 255. Κάθε υπολογιστής συνδεδεμένος στο δίκτυο IPv4 έχει μια μοναδική διεύθυνση τεσσάρων byte. Κατά τη μετάδοση των -19-

δεδομένων στο δίκτυο, η κεφαλίδα του πακέτου περιλαμβάνει τη διεύθυνση του μηχανήματος για το οποίο προορίζεται το πακέτο (διεύθυνση προορισμού) και τη διεύθυνση του μηχανήματος που στέλνει το πακέτο (διεύθυνση πηγής). Οι δρομολογητές κατά μήκος της διαδρομής ελέγχουν τη διεύθυνση προορισμού για να επιλέξουν την καλύτερη διαδρομή μέσω της οποίας θα γίνει η αποστολή του πακέτου. Η διεύθυνση πηγής συμπεριλαμβάνεται ούτως ώστε ο παραλήπτης να είναι σε θέση να γνωρίζει σε ποιον θα πρέπει να απαντήσει. Υπάρχουν λίγο περισσότερες από τέσσερα δισεκατομμύρια πιθανές διευθύνσεις IP, ούτε καν μία για κάθε άτομο στον πλανήτη, πολύ λιγότερες για κάθε υπολογιστή. Οι διευθύνσεις αυτές δεν έχουν κατανεμηθεί πολύ αποτελεσματικά, κάτι που δυσχεραίνει ακόμα περισσότερο την κατάσταση. Τον Απρίλιο του 2011, η Ασία και η Αυστραλία ξέμειναν από διευθύνσεις. Στις ηπείρους αυτές δεν υπήρχαν περισσότερες διαθέσιμες διευθύνσεις IPv4 για να χορηγηθούν και έτσι αναγκαστικά από τότε έχουν μπει στη διαδικασία ανακύκλωσης και ανακατανομής των υπαρχουσών διευθύνσεών τους. Τον Σεπτέμβριο του 2012, ήταν η σειρά της Ευρώπης να ξεμείνει από διευθύνσεις. Η Βόρεια Αμερική, η Λατινική Αμερική και η Αφρική εξακολουθούν να έχουν λίγα μπλοκ διευθύνσεων IP ακόμα για να διαθέσουν, αλλά δεν πρόκειται να αντέξουν πολύ περισσότερο. Αυτή τη στιγμή, μια αργή μετάβαση βρίσκεται σε εξέλιξη για αλλαγή του IPv4 σε IPv6, το οποίο θα χρησιμοποιεί διευθύνσεις 16-byte. Κάτι τέτοιο παρέχει αρκετές διευθύνσεις IP για την διευθυνσιοδότηση κάθε προσώπου, κάθε υπολογιστή και μάλιστα κάθε συσκευής στον πλανήτη. Οι διευθύνσεις IPv6 είναι συνήθως γραμμένες σε οκτώ μπλοκ των τεσσάρων δεκαεξαδικών ψηφίων που χωρίζονται από άνω και κάτω τελείες, όπως FEDC: BA98: 7654:3210: FEDC: BA98: 7654:3210. Τα μηδενικά στην αρχή της διεύθυνσης δεν χρειάζεται να γράφονται. Η ύπαρξη το πολύ μιας διπλής άνω και κάτω τελείας σε οποιαδήποτε διεύθυνση, δείχνει πολλαπλά μπλοκ μηδενικών. Για παράδειγμα, η διεύθυνση FEDC:0000:0000:0000:00 DC: 0000:7076:0010 θα μπορούσε να γραφτεί πιο συμπαγώς ως FEDC :: DC:0:7076:10. Σε μεικτά δίκτυα IPv6 και IPv4, τα τελευταία τέσσερα byte της διεύθυνσης IPv6 μερικές φορές γράφονται ως μια dotted quad διεύθυνση IPv4. Για παράδειγμα, η διεύθυνση FEDC:BA98:7654:3210:FEDC:BA98:7654:3210 μπορεί να γραφτεί ως FEDC:BA98:7654:3210:FEDC:BA98:118.84.50.16. Παρά το γεγονός ότι για τους υπολογιστές οι αριθμοί δεν αποτελούν πρόβλημα, οι άνθρωποι δεν είναι πολύ καλοί στο να τους θυμούνται. Ως εκ τούτου, το Domain Name System (DNS) αναπτύχθηκε για να μεταφράζει τα hostname που οι άνθρωποι μπορούν να θυμηθούν, όπως "www.oreilly.com", σε αριθμητικές διευθύνσεις του Internet, όπως 208.201.239.101. Όταν τα -20-

προγράμματα της Java αποκτούν πρόσβαση στο δίκτυο, χρειάζεται να επεξεργάζονται τόσο τις αριθμητικές διευθύνσεις όσο και τα αντίστοιχα hostname τους. Ορισμένοι υπολογιστές, ειδικά servers, έχουν σταθερή διεύθυνση. Άλλοι, ειδικά client σε τοπικά δίκτυα και ασύρματες συνδέσεις, λαμβάνουν μια διαφορετική διεύθυνση κάθε φορά που κάνουν εκκίνηση, που συχνά παρέχεται από ένα διακομιστή DHCP. Οι IP διευθύνσεις μπορεί να αλλάξουν με την πάροδο του χρόνου, επομένως δεν θα πρέπει να γράφεται κώδικας παίρνοντας σαν δεδομένο ότι ένα σύστημα θα έχει την ίδια διεύθυνση IP. Για παράδειγμα, δεν θα πρέπει να αποθηκεύεται η τοπική διεύθυνση IP κατά την αποθήκευση της κατάστασης μιας εφαρμογής. Αντ' αυτού, καλύτερα θα είναι να γίνεται ο έλεγχος της υπάρχουσας διεύθυνσης IP κάθε φορά που το εκάστοτε πρόγραμμα ξεκινά. Είναι επίσης δυνατό, αν και λιγότερο πιθανό, μια διεύθυνση IP να αλλάξει κατά τη διάρκεια εκτέλεσης ενός προγράμματος. Κάτι τέτοιο μπορεί να συμβεί, για παράδειγμα, σε περίπτωση που η μίσθωση του DHCP λήγει. Για να αποφευχθεί κάτι τέτοιο είναι καλύτερο να γίνεται έλεγχος της τρέχουσας διεύθυνση IP κάθε φορά που απαιτείται, παρά να αποθηκεύεται προσωρινά στη μνήμη cache. Βέβαια, η διαφορά ανάμεσα στη διευθυνσιοδότηση με δυναμικό και αυτόματο τρόπο δεν είναι σημαντική για τα προγράμματα της Java. Αρκετά μπλοκ διευθύνσεων και πρότυπα είναι ιδιαίτερα. Όλες οι διευθύνσεις IPv4 που αρχίζουν με 10., από 172.16. μέχρι 172.31. και 192.168. είναι ακαθόριστες. Μπορούν να χρησιμοποιηθούν σε εσωτερικά δίκτυα, αλλά κανένας host που χρησιμοποιεί διευθύνσεις που βρίσκονται στις περιοχές αυτές δεν πρόκειται να έχει πρόσβαση στο διαδίκτυο. Αυτές οι μη δρομολογούμενες διευθύνσεις είναι χρήσιμες για την κατασκευή ιδιωτικών δικτύων που δεν απαιτείται να έχουν πρόσβαση στο διαδίκτυο. Οι IPv4 διευθύνσεις που ξεκινούν από 127 (συνηθέστερα η 127.0.0.1) προορίζονται για τοπικές διευθύνσεις loopback, δηλαδή, αυτές οι διευθύνσεις πάντα δείχνουν προς τον τοπικό υπολογιστή ανεξαρτήτως ποιος υπολογιστής λειτουργεί. Το hostname της διεύθυνσης αυτής συχνά είναι το localhost. Στο IPv6, η διεύθυνση loopback είναι η 0:0:0:0:0:0:0:1 (γνωστή ως :: 1). Η διεύθυνση 0.0.0.0 αναφέρεται πάντα στον host προέλευσης, αλλά μπορεί να χρησιμοποιηθεί μόνο ως διεύθυνση πηγής και όχι ως διεύθυνση προορισμού. Ομοίως, οποιαδήποτε διεύθυνση IPv4 αρχίζει με 0. (8 μηδενικά bit) υποτίθεται ότι αναφέρεται σε host του ίδιου τοπικού δικτύου. Η διεύθυνση IPv4 που χρησιμοποιεί τον ίδιο αριθμό για κάθε ένα από τα τέσσερα byte (δηλαδή, 255.255.255.255), είναι μια διεύθυνση εκπομπής (broadcast address). Τα πακέτα που στέλνονται σε αυτή τη διεύθυνση, λαμβάνονται από όλους τους κόμβους του τοπικού δικτύου, αν και δεν δρομολογούνται πέραν του τοπικού δικτύου. Για παράδειγμα, όταν ένας -21-

προσωρινός client ενός δικτύου κάνει εκκίνηση, όπως ένα laptop, θα στείλει ένα συγκεκριμένο μήνυμα στη 255.255.255.255 για να βρεί το τοπικό DHCP διακομιστή. Όλοι οι κόμβοι του δικτύου λαμβάνουν το πακέτο, αλλά μόνο ο διακομιστής DHCP αποκρίνεται. Η απόκριση αυτή περιλαμβάνει όλες τις πληροφορίες σχετικά με τη διαμόρφωση του τοπικού δικτύου, συμπεριλαμβανομένης της διεύθυνσης IP που θα πρέπει να χρησιμοποιεί το laptop για το υπόλοιπο της παραμονής του στο δίκτυο και της διεύθυνσης του διακομιστή DNS που μπορεί να χρησιμοποιήσει για την ανεύρεση των hostname. 1.4.2 Θύρες (Port) Αν οι υπολογιστές εκτελούσαν μόνο μια λειτουργία τη φορά, τότε το μόνο πράγμα που θα χρειαζόταν θα ήταν η διεύθυνσή του. Ωστόσο, οι σύγχρονοι υπολογιστές κάνουν πολλά διαφορετικά πράγματα ταυτόχρονα. Τα email πρέπει να διαχωρίζονται από τις FTP αιτήσεις, που θα πρέπει να διαχωρίζονται από την κίνηση του δικτύου. Ο διαχωρισμός των διεργασιών αυτών επιτυγχάνεται με την βοήθεια των θυρών (port). Κάθε υπολογιστής με μια διεύθυνση IP έχει αρκετές χιλιάδες λογικά port (65.535 για το transport layer, για να είμαστε ακριβείς). Τα port είναι αφηρημένες οντότητες στη μνήμη του υπολογιστή και δεν αντιπροσωπεύουν τίποτα το φυσικό, όπως ένα USB port. Κάθε port προσδιορίζεται από έναν αριθμό μεταξύ του 1 και του 65535 και μπορεί να προορίζεται για μια συγκεκριμένη υπηρεσία. Για παράδειγμα, το HTTP, το υποκείμενο πρωτόκολλο του Web, συνήθως χρησιμοποιεί το port 80. Στην τεχνική ορολογία λέγεται ότι ένας web server ακούει στη θύρα 80 για εισερχόμενες συνδέσεις. Τα δεδομένα που αποστέλλονται σε ένα web server ενός συγκεκριμένου μηχανήματος που έχει μια συγκεκριμένη διεύθυνση IP, στην ουσία αποστέλλονται στο συγκεκριμένο port (συνήθως το port 80) του μηχανήματος. Ο αποδέκτης ελέγχει κάθε πακέτο που βλέπει στο port και στέλνει τα δεδομένα σε κάθε πρόγραμμα που ακούει στο port αυτό. Με τον τρόπο αυτό διευθετούνται διαφορετικοί τύποι της κίνησης του δικτύου. Οι θέσεις των port με αριθμούς μεταξύ 1 και 1023 προορίζονται για γνωστές υπηρεσίες όπως η υπηρεσία finger, το FTP, το HTTP και το IMAP. Σε συστήματα Unix, συμπεριλαμβανομένων των Linux και Mac OS X, δεδομένα από τα port αυτά λαμβάνουν μόνο τα προγράμματα που τρέχουν ως root, αλλά όλα τα προγράμματα μπορούν να στείλουν δεδομένα σε αυτά. Στα Windows, οποιοδήποτε πρόγραμμα μπορεί να χρησιμοποιήσει αυτές τις θύρες, χωρίς ειδικά προνόμια. Ο Πίνακας 1 παρουσιάζει τις γνωστές θύρες για τα πρωτόκολλα που περιγράφονται στην πτυχιακή αυτή. Αυτές οι εργασίες δεν είναι απολύτως -22-

εγγυημένες. Ειδικότερα, οι διακομιστές web συχνά λειτουργούν σε port εκτός του 80, είτε επειδή στο ίδιο μηχάνημα πρέπει να λειτουργούν πολλοί διακομιστές ή επειδή το άτομο που εγκατέστησε το διακομιστή δεν έχει τα προνόμια root που χρειάζονται για να τρέξει για τη θύρα 80. Σε συστήματα Unix, μια αρκετά πλήρη λίστα των εκχωρημένων port αποθηκεύεται στο αρχείο / etc / services. Πίνακας 1: Λειτουργίες των πιο γνωστών θυρών Πρωτόκολλο Αριθμός port Πρωτόκολλο Περιγραφή echo 7 TCP/UDP Πρωτόκολλο ελέγχου που χρησιμοποιείται για τη διαπίστωση συνδεσιμότητας μεταξύ δύο host discard 9 TCP/UDP Λιγότερο εύχρηστο πρωτόκολλο ελέγχου με το οποίο ο server αγνοεί όλα τα δεδομένα λήψης daytime 13 TCP/UDP ASCII απεικόνιση του πραγματικού χρόνου στον server FTP data 20 TCP Πρώτο από τα δύο port που χρησιμοποιεί το FTP. Χρησιμοποιείται για μεταφορά αρχείων FTP 21 TCP Δεύτερο από τα δύο port που χρησιμοποιεί το FTP. Χρησιμοποιείται για μεταφορά εντολών (put get) SSH 22 TCP Χρησιμοποιείται για κωδικοποιημένα απομακρυσμένα login Telnet 23 TCP Χρησιμοποιείται για διαδραστικά απομακρυσμένα command line session smtp 25 TCP Χρησιμοποιείται για αποστολή mail time 37 TCP/UDP Ένας χρονικός server επιστρέφει τον αριθμό των δευτερολέπτων που έχουν περάσει από τα μεσάνυχτα της 1/1/1900 σε μορφή μη σηματοδοτούμενου bigendian ακεραίου μήκους 4-bytes whois 43 TCP Απλή υπηρεσία καταλόγου για admin διαδικτύου finger 79 TCP Υπηρεσία που δίνει πληροφορίες για τους χρήστες του τοπικού συστήματος HTTP 80 TCP Το γνωστό πρωτόκολλο του διαδικτύου POP3 110 TCP Χρησιμοποιείται για τη μεταφορά πλήθους e-mail ενός host προς διάφορους client NNTP 119 TCP Μεταφορά ειδήσεων usenet IMAP 143 TCP Πρόσβαση σε ταχυδρομικούς λογαριασμούς ενός server dict 2628 TCP Ένα UTF-8 κωδικοποιημένο λεξικό για ερμηνεία λέξεων -23-

1.5. Το διαδίκτυο Το διαδίκτυο είναι το μεγαλύτερο δίκτυο που στηρίζεται στο πρωτόκολλο IP (IP-based network) του κόσμου. Είναι μια άμορφη ομάδα υπολογιστών σε πολλές διαφορετικές χώρες και στις επτά ηπείρους (συμπεριλαμβανομένης της Ανταρκτικής) που επικοινωνούν μεταξύ τους με χρήση IP πρωτοκόλλων. Κάθε υπολογιστής στο διαδίκτυο έχει τουλάχιστον μία διεύθυνση IP μέσω της οποίας μπορεί να προσδιοριστεί. Πολλοί από αυτούς έχουν επίσης τουλάχιστον ένα όνομα που αντιστοιχεί σε αυτήν τη διεύθυνση IP. Το διαδίκτυο δεν ανήκει σε κανέναν, αν και υπάρχουν μέρη του που ανήκουν κάπου. Δεν κυβερνείται από καμία χώρα κάτι όμως που δεν αποκλείει αρκετές από το να το προσπαθούν. Είναι απλά μια πολύ μεγάλη συλλογή από υπολογιστές που έχουν συμφωνήσει να επικοινωνούν μεταξύ τους με ένα τυποποιημένο τρόπο. Το διαδίκτυο δεν είναι το μοναδικό IP-based δίκτυο, αλλά είναι το μεγαλύτερο. Υπάρχουν και δίκτυα IP που λειτουργούν σαν το διαδίκτυο, όπως για παράδειγμα, ένα υψηλής ασφάλειας εσωτερικού δικτύου που όμως δεν είναι συνδεδεμένο με το παγκόσμιο διαδίκτυο. Ο όρος intranet περιγράφει με απλό τρόπο πρακτικές εταιριών που θέτουν πολλά δεδομένα σε εσωτερικούς web server οι οποίοι δεν είναι ορατοί στους χρήστες έξω από το τοπικό δίκτυο. Το σίγουρο είναι ότι ένας χρήστης χρησιμοποιεί το παγκόσμιο διαδίκτυο και όχι κάποιο άλλο δίκτυο που λειτουργεί ως διαδίκτυο, εκτός και αν εργάζεται σε ένα περιβάλλον υψηλής ασφάλειας που είναι φυσικά αποσυνδεμένο από το ευρύτερο δίκτυο. Για την εξασφάλιση της επικοινωνίας μεταξύ των host διαφορετικών δικτύων του διαδικτύου, θα πρέπει να ακολουθούνται μερικοί κανόνες που δεν εφαρμόζονται σε καθαρά εσωτερικά διαδίκτυα. Οι πιο σημαντικοί κανόνες ασχολούνται με την εκχώρηση διευθύνσεων σε διαφορετικούς οργανισμούς, εταιρείες και ιδιώτες. Αν ο καθένας έπαιρνε τις διευθύνσεις διαδικτύου που ήθελε τυχαία, θα προέκυπταν συγκρούσεις σχεδόν αμέσως καθώς θα εμφανίζονταν διαφορετικοί υπολογιστές με την ίδια διεύθυνση. 1.5.1 Ομάδες διευθύνσεων διαδικτύου Για την αποφυγή του προβλήματος των συγκρούσεων, στους φορείς παροχής υπηρεσιών διαδικτύου (Internet service providers - ISP) έχουν δοθεί ομάδες διευθύνσεων IPv4 από τον περιφερειακό διανομέα διευθύνσεων (Regional Internet Registry - RIR). Όταν μια εταιρεία ή ένας οργανισμός θέλει να δημιουργήσει ένα IP-based δίκτυο που θα συνδέεται με το Internet, ο ISP τους, τους χορηγεί μια ομάδα διευθύνσεων. Κάθε ομάδα έχει ένα σταθερό πρόθεμα. Για παράδειγμα, εάν το πρόθεμα είναι 216.254.85, το τοπικό δίκτυο μπορεί να χρησιμοποιήσει τις -24-

διευθύνσεις από 216.254.85.0 έως 216.254.85.255. Επειδή αυτή η ομάδα έχει σταθερά τα πρώτα 24 bit, ονομάζεται /24. Μια ομάδα /23 έχει σταθερά τα πρώτα 23 bit, αφήνοντας 9 bit για 29 ή 512 συνολικά τοπικές διευθύνσεις IP. Ένα /30 υποδίκτυο (subnet) (το μικρότερο δυνατό) έχει σταθερά τα πρώτα 30 bit για τις διευθύνσεις IP εντός του subnet, αφήνοντας 2 bit για 22 ή 4 συνολικά τοπικές διευθύνσεις IP. Ωστόσο δύο διευθύνσεις της ομάδας είναι δεσμευμένες. Η χαμηλότερη διεύθυνση της ομάδας χρησιμοποιείται για τον προσδιορισμό του ίδιου του δικτύου και η μεγαλύτερη είναι η διεύθυνση broadcast του δικτύου, με αποτέλεσμα να υπάρχουν δύο λιγότερες διαθέσιμες διευθύνσεις από ότι μπορεί αρχικά να περιμένουμε. 1.5.2 Μετάφραση Διεύθυνσης Δικτύου (NAT) Λόγω της αυξανόμενης σπανιότητας και της ζήτησης για raw IP διευθύνσεις, τα περισσότερα δίκτυα χρησιμοποιούν σήμερα Μετάφραση Διεύθυνσης Δικτύου (Network Address Translation - NAT). Στα δίκτυα NAT οι περισσότεροι κόμβοι έχουν μόνο τοπικές, μη δρομολογούμενες διευθύνσεις που επιλέγονται από τις ομάδες διευθύνσεων 10.x.x.x, 172.16.x.x μέχρι 172.31.x.x, ή 192.168.x.x. Οι δρομολογητές που συνδέουν τα τοπικά δίκτυα με τον ISP μεταφράζουν αυτές τις τοπικές διευθύνσεις σε ένα πολύ μικρότερο σύνολο δρομολογούμενων διευθύνσεων. Για παράδειγμα, μια δωδεκάδα και πλέον IP κόμβοι στο διαμέρισμά μου μοιράζονται όλοι μία μόνο εξωτερικά ορατή διεύθυνση IP. Ο υπολογιστής στον οποίο γράφω αυτή την εργασία έχει τη IP διεύθυνση 192.168.1.5, αλλά σε ένα άλλο δίκτυο η διεύθυνση αυτή μπορεί να αναφέρεται σε ένα εντελώς διαφορετικό host, αν υπάρχει κιόλας. Ούτε κάποιος θα μπορούσε να έχει πρόσβαση στον υπολογιστή μου αν έστελνε δεδομένα στη διεύθυνση 192.168.1.5. Αντ' αυτού, η αποστολή των δεδομένων θα έπρεπε να γίνει προς την 216.254.85.72 (και ακόμα και τότε, τα δεδομένα θα περνούσαν μόνο αν είχα ρυθμίσει τον NAT router μου να περνάει τις εισερχόμενες συνδέσεις προς την 192.168.1.5). Ο δρομολογητής παρακολουθεί τις εξερχόμενες και εισερχόμενες συνδέσεις μου και προσαρμόζει αυτόματα τις διευθύνσεις στα πακέτα IP. Για ένα εξερχόμενο πακέτο, αλλάζει τη διεύθυνση πηγής στην εξωτερική διεύθυνση του δρομολογητή (216.254.85.72 στο δίκτυό μου). Για ένα εισερχόμενο πακέτο, αλλάζει τη διεύθυνση προορισμού σε μία από τις τοπικές διευθύνσεις, όπως την 192.168.1.12. Το πώς ακριβώς παρακολουθεί το ποια από τις συνδέσεις προέρχονται και έχουν ως προορισμό έναν από τους εσωτερικούς υπολογιστές, είναι κάτι που δεν είναι ιδιαίτερα σημαντικό για έναν προγραμματιστή Java. Εφ 'όσον τα -25-

μηχανήματα έχουν ρυθμιστεί σωστά, η διαδικασία αυτή είναι ως επί το πλείστον διαφανή. Το μόνο που θα πρέπει να θυμάται κάποιος είναι ότι οι εξωτερικές και οι εσωτερικές διευθύνσεις μπορεί να μην είναι οι ίδιες. Σε τελική ανάλυση, η είσοδος του IPv6 θα κάνει την όλη διαδικασία ξεπερασμένη. Η χρήση του NAT θα είναι άσκοπη, αν και τα firewall θα εξακολουθούν να είναι χρήσιμα. Τα subnet θα εξακολουθούν να υπάρχουν για τη δρομολόγηση, αλλά θα είναι πολύ μεγαλύτερα. 1.5.3 Τείχος προστασίας (Firewall) Στο διαδίκτυο υπάρχουν μερικοί άνθρωποι που είναι άτακτοι. Για να κρατηθούν έξω, είναι συχνά χρήσιμη η δημιουργία ενός σημείου πρόσβασης σε ένα τοπικό δίκτυο στο οποίο θα γίνεται ο έλεγχος όλης της κίνησης προς τα μέσα ή προς τα έξω. Το υλικό και το λογισμικό που βρίσκονται μεταξύ του Internet και του τοπικού δικτύου και εξετάζουν όλα τα στοιχεία που εισέρχονται ή εξέρχονται ώστε να βεβαιώσουν ότι είναι επιτρεπτά, ονομάζεται τείχος προστασίας (firewall). Το τείχος προστασίας είναι συχνά μέρος του router που συνδέει το τοπικό δίκτυο στο ευρύτερο Διαδίκτυο και μπορεί να εκτελεί και άλλα καθήκοντα, όπως είναι η μετάφραση διευθύνσεων δικτύου. Άλλες φορές, το τείχος προστασίας μπορεί να είναι ένα ξεχωριστό μηχάνημα. Σύγχρονα λειτουργικά συστήματα, όπως το Mac OS X και το Red Hat Linux συχνά έχουν ενσωματωμένα προσωπικά firewall που ελέγχουν μόνο την κίνηση που αποστέλλεται σε ένα μηχάνημα. Με τον ένα ή τον άλλο τρόπο, το τείχος προστασίας είναι υπεύθυνο για τον έλεγχο κάθε πακέτου που περνά προς τα μέσα ή προς τα έξω από το interface του δικτύου της και το αποδέχεται ή το απορρίπτει σύμφωνα με ένα σύνολο κανόνων. Το φιλτράρισμα αυτό γίνεται συνήθως με βάση τις διευθύνσεις του δικτύου και των θυρών. Για παράδειγμα, όλη η κίνηση που έρχεται από το δίκτυο κλάσης C 193.28.25.x μπορεί να απορριφθεί λόγω πρότερης κακής εμπειρίας χάκερ από το δίκτυο αυτό. Μπορούν να επιτρέπονται οι εξερχόμενες συνδέσεις SSH, αλλά όχι και οι εισερχόμενες συνδέσεις SSH. Εισερχόμενες συνδέσεις στη θύρα 80 (web) μπορεί να επιτρέπονται, αλλά μόνο στον εταιρικό web server. Πιο έξυπνα firewall ελέγχουν το περιεχόμενο των πακέτων για να αποφασίσουν εάν θα το αποδεχθούν ή θα το απορρίψουν. Η ακριβής ρύθμιση ενός τείχους προστασίας, σχετικά με το ποια πακέτα δεδομένων θα περάσει και ποια όχι, εξαρτάται από τις ανάγκες ασφάλειας του site. Η Java δεν ασχολείται πολύ με τα τείχη προστασίας, εκτός από τις περιπτώσεις που της δημιουργούν συχνά εμπόδια. -26-

1.5.4 Διακομιστές Μεσολάβησης (Proxy Servers) Οι διακομιστές μεσολάβησης σχετίζονται με τα τείχη προστασίας. Εάν ένα τείχος προστασίας εμποδίζει ένα host ενός δικτύου να συνδεθεί απευθείας με τον έξω κόσμο, ο διακομιστής μεσολάβησης μπορεί να ενεργήσει ως μεσολαβητής. Έτσι, ένα μηχάνημα, που εμποδίζεται να συνδεθεί με το εξωτερικό δίκτυο από ένα τείχος προστασίας, θα κάνει αίτηση για πρόσβαση σε μια ιστοσελίδα από τον τοπικό διακομιστή μεσολάβησης, αντί να το ζητήσει απευθείας από τον απομακρυσμένο web server. Ο διακομιστής μεσολάβησης τότε θα ζητήσει τη σελίδα από τον web server και θα διαβιβάσει την απάντηση πίσω προς τον αρχικό αιτούντα. Οι proxy server μπορούν επίσης να χρησιμοποιηθούν για υπηρεσίες FTP αλλά και για άλλες συνδέσεις. Ένα από τα πλεονεκτήματα ασφάλειας της χρήσης ενός διακομιστή μεσολάβησης είναι ότι μόνο οι εξωτερικοί host μαθαίνουν για την ύπαρξή του. Δεν μπορούν να μάθουν ούτε τα ονόματα αλλά ούτε και τις IP διευθύνσεις των εσωτερικών μηχανημάτων, καθιστώντας έτσι πιο δύσκολο το χακάρισμα των εσωτερικών συστημάτων. Ενώ τα firewall γενικά λειτουργούν στο επίπεδο των transport ή internet layer, οι proxy servers λειτουργούν κανονικά στο application layer. Ο proxy server μπορεί να καταλάβει με λεπτομέρεια κάποια από τα πρωτόκολλα επιπέδου εφαρμογής, όπως τα HTTP και FTP. Αξιοσημείωτη είναι η εξαίρεση του SOCKS proxy server που λειτουργεί στο transport layer και μπορεί να διαμεσολαβήσει για όλες τις TCP και UDP συνδέσεις, ανεξάρτητα από το πρωτόκολλο επιπέδου εφαρμογής. Τα πακέτα που περνούν μέσω του διακομιστή μεσολάβησης μπορεί να εξεταστούν εξασφαλίζοντας έτσι ότι το περιεχόμενό τους αντιστοιχεί στον τύπο τους. Για παράδειγμα, τα πακέτα FTP που φαίνεται να περιέχουν δεδομένα Telnet μπορεί να είναι απορριφθούν. Η εικόνα 4 απεικονίζει πως οι proxy servers ταιριάζουν στο μοντέλο επιπέδων. Εφ 'όσον όλη η πρόσβαση στο διαδίκτυο προωθείται μέσω του διακομιστή μεσολάβησης, η πρόσβαση μπορεί να ελέγχεται αυστηρά. Για παράδειγμα, μια εταιρεία μπορεί να επιλέξει να εμποδίσει την πρόσβαση στη σελίδα www.playboy.com αλλά να επιτρέπει την πρόσβαση στην www.microsoft.com. Ορισμένες εταιρείες επιτρέπουν τις εισερχόμενες FTP, αλλά απορρίπτουν τις εξερχόμενες FTP και έτσι εμπιστευτικά δεδομένα δεν μπορούν να βγουν εύκολα από την εταιρεία. Άλλες εταιρείες χρησιμοποιούν proxy servers για την παρακολούθηση της χρήσης του διαδικτύου από τους εργαζόμενους τους ώστε να μπορούν να δουν ποιος κάνει χρήση του διαδικτύου για να πάρει τεχνική υποστήριξη και ποιος το χρησιμοποιεί για να δει την playmate του μήνα. -27-

Εικόνα 4: Συνδέσεις layer μέσω proxy server Ένας proxy server μπορεί επίσης να χρησιμοποιηθεί για την εφαρμογή τοπικής προσωρινής αποθήκευσης δεδομένων (caching). Όταν ζητείται ένα αρχείο από έναν web server, ο proxy server ελέγχει πρώτα να δει αν το αρχείο είναι στη προσωρινή μνήμη cache. Εάν το αρχείο βρίσκεται εκεί, ο proxy στέλνει το αρχείο από τη μνήμη cache και όχι από το Internet. Εάν το αρχείο δεν βρίσκεται στην μνήμη cache, ο proxy server ανακτά το αρχείο, τo διαβιβάζει στον αιτούντα και το αποθηκεύει στη μνήμη cache για την επόμενη φορά που θα του ζητηθεί. Το σύστημα αυτό μπορεί να μειώσει σημαντικά το φορτίο μιας σύνδεσης στο Internet και σε μεγάλο βαθμό βελτιώνει το χρόνο απόκρισης. Η America Online έχει ένα από τα μεγαλύτερα κέντρα διακομιστών μεσολάβησης (farms of proxy servers) στον κόσμο για να επιταχύνει τη μεταφορά των δεδομένων στους χρήστες της. Αν κοιτάξετε το αρχείο καταγραφής (logfile) ενός web server, είναι πιθανό να βρείτε κάποια hit από τους πελάτες του domain aol.com, αλλά όχι τόσα όσα θα περίμενε κανείς δεδομένου του αριθμού των συνδρομητών της AOL που ξεπερνά τα τρία εκατομμύρια. Αυτό συμβαίνει γιατί οι διακομιστές μεσολάβησης της AOL παρέχουν πολλές σελίδες από την προσωρινή μνήμη τους, αντί να τις ζητούν εκ νέου ο ένας από τον άλλο. Πολλοί άλλοι, μεγάλοι ISP κάνουν ακριβώς το ίδιο. Το μεγαλύτερο πρόβλημα των διακομιστών μεσολάβησης είναι η αδυναμία τους να αντιμετωπίσουν όλα τα πρωτόκολλα. Γενικώς, επιτρέπεται η μεταφορά δεδομένων καθιερωμένων πρωτοκόλλων όπως τα HTTP, FTP και SMTP, όμως όχι νεοτέρων πρωτοκόλλων όπως το BitTorrent. Υπάρχουν βέβαια και μερικοί διαχειριστές δικτύου που θεωρούν αυτή την αδυναμία ως χαρακτηριστικό γνώρισμα. Παρόλα αυτά, στον ταχέως μεταβαλλόμενο κόσμο του Internet, η αδυναμία αυτή αποτελεί ένα σημαντικό μειονέκτημα. Είναι μια ιδιαίτερα μειονεκτική θέση για τους προγραμματιστές Java, διότι περιορίζει την -28-

αποτελεσματικότητα των προσαρμοσμένων πρωτοκόλλων. Στην Java, είναι εύκολη και συχνά χρήσιμη, η δημιουργία ενός νέου πρωτοκόλλου που θα βελτιστοποιεί την εκάστοτε εφαρμογή. Ωστόσο, κανένας διακομιστής μεσολάβησης δεν πρόκειται να καταλάβει ποτέ αυτού του είδους τα πρωτόκολλα. Κατά συνέπεια, ορισμένοι προγραμματιστές διοχετεύουν τα πρωτόκολλά τους (protocol tunneling) μέσω HTTP, κυρίως με SOAP. Ωστόσο, αυτό έχει σημαντικές αρνητικές επιπτώσεις στην ασφάλεια. Το τείχος προστασίας είναι συνήθως εκεί για σοβαρό λόγο και όχι μόνο για να ενοχλεί τους προγραμματιστές Java. Τα applet που τρέχουν σε web browsers συνήθως χρησιμοποιούν τις ρυθμίσεις διακομιστή μεσολάβησης του web, παρά το γεγονός ότι μπορεί να παρακαμφθούν από τον Πίνακα Ελέγχου Java (Java Control Panel). Οι αυτόνομες εφαρμογές Java μπορούν να δείξουν τη χρήση διακομιστή μεσολάβησης, θέτοντας τις ιδιότητες socksproxyhost και socksproxyport (αν χρησιμοποιείται SOCKS proxy server), ή θέτοντας τις ιδιότητες συστήματος http.proxyset, http.proxyhost, http.proxyport, https.proxyset, https.proxyhost, https.proxyport, ftpproxyset, ftpproxyhost, ftpproxyport, gopherproxyset, gopherproxyhost και gopherproxyport (αν χρησιμοποιούνται proxy συγκεκριμένου πρωτοκόλλου). Οι ιδιότητες του συστήματος μπορούν να οριστούν και από τη γραμμή εντολών, χρησιμοποιώντας τη -D flag, κάπως έτσι: java-dsocksproxyhost = socks.cloud9.net -DsocksProxyPort = 1080 MyClass 1.6. Το μοντέλο Client / Server Τα περισσότερα σύγχρονα δικτυακά προγράμματα βασίζονται στο μοντέλο client / server. Μια client / server εφαρμογή αποθηκεύει συνήθως μεγάλες ποσότητες δεδομένων σε ένα ακριβό, υψηλής ισχύος server ή cloud servers, ενώ το μεγαλύτερο μέρος της λογικής του προγράμματος και της διεπαφής του χρήστη διαχειρίζεται από το λογισμικό του client που λειτουργεί σε σχετικά φθηνούς προσωπικούς υπολογιστές. Στις περισσότερες περιπτώσεις, ένας server στέλνει δεδομένα, ενώ ο client λαμβάνει, αλλά είναι σπάνιο για ένα πρόγραμμα να στέλνει ή να λαμβάνει αποκλειστικά. Μια πιο αξιόπιστη διάκριση είναι ότι ο client ξεκινά μια συνομιλία, ενώ ο sever περιμένει τους client να ξεκινήσουν συνομιλίες μαζί του. Στην εικόνα 5 απεικονίζονται και οι δύο περιπτώσεις. Σε ορισμένες περιπτώσεις, το ίδιο πρόγραμμα μπορεί να είναι τόσο client όσο και server. -29-

Εικόνα 5: Σύνδεση server/client Ο περισσότερος κόσμος είναι ήδη εξοικειωμένος με πολλά παραδείγματα συστημάτων client / server. Το 2013, το πιο δημοφιλές σύστημα client / server στο διαδίκτυο είναι ο Παγκόσμιος Ιστός. Web servers, όπως ο Apache, ανταποκρίνονται σε αιτήματα από web clients, όπως το Firefox. Τα δεδομένα είναι αποθηκευμένα στο web server και αποστέλλονται προς τους client που θα τα ζητήσουν. Σχεδόν όλα τα δεδομένα μεταφέρονται από το server προς τον client και όχι από τον client στον server, εκτός από το αρχικό αίτημα για κάποια σελίδα. Το FTP είναι μια παλαιότερη υπηρεσία που ταιριάζει στο μοντέλο client / server. Το FTP χρησιμοποιεί διαφορετικά πρωτόκολλα εφαρμογής και διαφορετικό λογισμικό, αλλά εξακολουθεί να χωρίζεται σε FTP servers που στέλνουν αρχεία και FTP clients που λαμβάνουν αρχεία. Οι άνθρωποι χρησιμοποιούν συχνά το FTP για να ανεβάσουν αρχεία από τον client στον server, γι 'αυτό είναι δύσκολο να πούμε ότι η μεταφορά δεδομένων γίνεται κατά κύριο λόγο προς μία κατεύθυνση, αλλά εξακολουθεί να είναι αλήθεια ότι ένας FTP client εκκινεί τη σύνδεση και ο FTP server ανταποκρίνεται. Δεν ταιριάζουν όλες οι εφαρμογές εύκολα στο μοντέλο client / server. Για παράδειγμα, σε δικτυακά παιχνίδια, φαίνεται ότι και οι δύο παίκτες θα στείλουν και θα λάβουν δεδομένα σχεδόν ισομερώς (τουλάχιστον σε ένα δίκαιο παιχνίδι). Αυτά τα είδη των συνδέσεων ονομάζονται peer-to-peer. Το τηλεφωνικό σύστημα είναι κλασικό παράδειγμα δικτύου peerto-peer. Κάθε τηλεφωνική κλήση μπορεί να γίνεται είτε προς ένα άλλο τηλέφωνο και κάθε τηλέφωνο μπορεί να κληθεί από άλλο τηλέφωνο. Δεν απαιτείται η αγορά ενός τηλεφώνου για την αποστολή κλήσεων και ένα άλλο για τη λήψη. -30-

Στην Java δεν υπάρχει ρητή επικοινωνία peer-to-peer όσον αφορά τη βασική δικτύωση των API της. Ωστόσο, οι εφαρμογές της μπορούν να προσφέρουν εύκολα peer-to-peer επικοινωνία με διάφορους τρόπους, συνήθως ενεργώντας τόσο ως server όσο και ως client. Εναλλακτικά, τα peer μπορούν να επικοινωνούν μεταξύ τους μέσω ενός ενδιάμεσου προγράμματος διακομιστή που προωθεί δεδομένα από ένα peer σε άλλα. Αυτό λύνει το πρόβλημα του τρόπου με τον οποίο το ένα peer βρίσκει το άλλο. 1.7. Διαδικτυακά Πρότυπα (Internet Standards) Η πτυχιακή αυτή εργασία ασχολείται με διάφορα πρωτόκολλα διαδικτύου του application layer, κυρίως όμως με το HTTP. Ωστόσο, ο σκοπός της δεν είναι τα πρωτόκολλα αυτά. Περισσότερες αναλυτικές πληροφορίες για το κάθε πρωτόκολλο υπάρχουν στα έγγραφα των προτύπων των πρωτοκόλλων. Αν και υπάρχουν πολλοί οργανισμοί προτύπων, οι δύο που παράγουν τα περισσότερα πρότυπα σχετικά με τον δικτυακό προγραμματισμό του application layer και τα πρωτόκολλά του είναι η Τακτική Δύναμη Μηχανικών Διαδικτύου (Engineering Task Force Internet - IETF) και η Κοινοπραξία Παγκόσμιου Ιστού (World Wide Web Consortium - W3C). Η IETF είναι ένας σχετικά ανεπίσημος οργανισμός ανοικτών προτύπων, χωρίς τυπικά μέλη ή τυπικές απαιτήσεις από τα μέλη του. Αναπτύσσει και προωθεί πρότυπα που βασίζονται σε τραχίες συναινέσεις και εκτελέσιμο κώδικα και τείνουν να ακολουθούν κάθε άλλο παρά ηγετικές εφαρμογές. Τα πρότυπα της IETF περιλαμβάνουν τα TCP / IP, MIME, και SMTP. Η W3C, αντιθέτως, είναι μια κοινοπραξία που δημιουργήθηκε από κατασκευαστές και που ελέγχεται από εταιρείες-μέλη που πληρώνουν τέλη και που αποκλείει ρητά τη συμμετοχή ιδιωτών. Κύριος σκοπός του W3C είναι ο καθορισμός των προτύπων πριν την εφαρμογή. Τα πρότυπα του W3C περιλαμβάνουν τα HTTP, HTML και XML. 1.7.1 Τα RFC της IETF Τα πρότυπα και τα σχεδόν πρότυπα της IETF δημοσιεύονται ως Requests for Comments (RFCs). Παρά το όνομά τους, ένα δημοσιευμένο RFC αποτελεί ολοκληρωμένο έργο. Μπορεί να γίνει ξεπερασμένο ή να αντικατασταθεί από ένα νέο RFC, αλλά δεν πρόκειται ποτέ να αλλάξει. Τα IETF έγγραφα εργασίας που υπόκεινται σε αναθεώρηση και είναι ανοικτά για ανάπτυξη ονομάζονται Internet drafts. Τα RFC κυμαίνονται από ενημερωτικά έντυπα γενικού ενδιαφέροντος μέχρι λεπτομερείς προδιαγραφές τυπικών πρωτοκόλλων Internet, όπως το FTP. Τα RFC είναι διαθέσιμα σε -31-

πολλά μέρη του διαδικτύου, συμπεριλαμβανομένων των http://www.faqs.org/rfc/ και http://www.ietf.org/rfc.html. Το μεγαλύτερο μέρος των RFC, ιδιαίτερα τα RFC που είναι πρότυπα, είναι γραμμένα με τεχνική ορολογία σχεδόν ακατανόητη. Παρ 'όλα αυτά, είναι συχνά η μόνη ολοκληρωμένη και αξιόπιστη πηγή πληροφοριών σχετικά με ένα συγκεκριμένο πρωτόκολλο. Οι περισσότερες προτάσεις για ένα RFC αρχίζουν όταν ένα άτομο ή μια ομάδα έχει μια ιδέα και δημιουργεί ένα πρωτότυπο. Το πρωτότυπο είναι εξαιρετικά σημαντικό. Για να δημιουργηθεί ένα IETF πρότυπο, θα πρέπει πρωτίστως να υπάρχει ολοκληρωμένη και λειτουργική πρόταση. Η απαίτηση αυτή εξασφαλίζει ότι τα IETF πρότυπα είναι τουλάχιστον εφικτά, σε αντίθεση με τα πρότυπα που εκδίδονται από ορισμένους άλλους οργανισμούς. Ο Πίνακας 2 παραθέτει τα RFC που παρέχουν επίσημη τεκμηρίωση για τα πρωτόκολλα που αναφέρονται στην πτυχιακή αυτή εργασία. Πίνακας 2: Επιλεγμένα διαδικτυακά RFC RFC Τίτλος Περιγραφή RFC 5000 RFC 1122 RFC 1123 RFC 791, RFC 919, RFC 922, RFC 950 RFC 768 RFC 792 RFC 793 Internet Official Protocol Standards Host Requirements Internet Protocol User Datagram Protocol Internet Control Message Protocol (ICMP) Transmission Control Protocol Περιγράφει τη διαδικασία προτυποποίησης και την παρούσα κατάσταση των διαφόρων πρωτοκόλλων του διαδικτύου. Ενημερώνεται περιοδικά με κάθε καινούριο RFC Καταγράφει τα πρωτόκολλα που πρέπει να υποστηρίζονται από όλους τους host του διαδικτύου στα διάφορα layer (data link layer, IP layer, transport layer, and application layer) Το πρωτόκολλο IP του internet layer Ένα αναξιόπιστο, χωρίς σύνδεση πρωτόκολλο του transport layer Ένα πρωτόκολλο του internet layer που χρησιμοποιεί raw IP datagram και δεν υποστηρίζεται από την Java.Οι πιο γνωστές του εφαρμογές είναι το ping και το traceout Ένα αξιόπιστο πρωτόκολλο με συνδέσεις και ροές δεδομένων του transport layer RFC 2821 Simple Mail Transfer Πρωτόκολλο του application layer με το οποίο ένας host στέλνει e- -32-

RFC 822 RFC 854, RFC 855 RFC 862 RFC 863 RFC 864 RFC 865 RFC 867 RFC 868 Protocol Format of Electronic Mail Messages Telnet Protocol Echo Protocol Discard Protocol Character Generator Protocol Quote of the Day Daytime Protocol Time Protocol mail σε άλλο host, χωρίς να ενδιαφέρεται για τη διεπαφή του εκάστοτε χρήστη αλλά μόνο για το μηχανισμό προώθησης του e- mail από έναν υπολογιστή σε έναν άλλον Βασική σύνταξη για μηνύματα e-mail ASCII κειμένου. Το MIME έχει σχεδιαστεί για να επεκτείνει αυτή τη σύνταξη στην υποστήριξη δυαδικών δεδομένων, εξασφαλίζοντας ταυτόχρονα ότι τα μηνύματα που μεταφέρονται ανταποκρίνονται πάντα σε αυτό το πρότυπο Μια υπηρεσία απομακρυσμένης σύνδεσης του application layer για περιβάλλοντα γραμμής εντολών που βασίζεται σε ένα αφηρημένο εικονικό τερματικό δικτύου (network virtual terminal NVT) και το TCP Ένα πρωτόκολλο του application layer που αντηχεί (echo) όλα τα δεδομένα που λαμβάνει τόσο από το TCP όσο και από το UDP. Χρήσιμο ως εργαλείο εντοπισμού σφαλμάτων Ένα πρωτόκολλο του application layer που λαμβάνει πακέτα δεδομένων τόσο από το TCP όσο και από το UDP χωρίς να επιστρέφει καμία απάντηση στον client. Χρήσιμο ως εργαλείο εντοπισμού σφαλμάτων Ένα πρωτόκολλο του application layer που στέλνει μια αόριστη ακολουθία χαρακτήρων ASCII σε κάθε client που συνδέεται μέσω TCP ή UDP. Επίσης χρήσιμο ως εργαλείο εντοπισμού σφαλμάτων. Ένα πρωτόκολλο του application layer που επιστρέφει ένα σύντομο αυθαίρετο μήνυμα (quotation) σε κάθε χρήστη που συνδέεται μέσω TCP ή UDP και στη συνέχεια κλείνει τη σύνδεση. Ένα πρωτόκολλο του application layer που στέλνει μια συμβολοσειρά ASCII αναγνώσιμη από τον άνθρωπο δείχνοντας την τρέχουσα ημερομηνία και ώρα του server σε κάθε client που συνδέεται μέσω TCP ή UDP. Αυτό έρχεται σε αντίθεση με τα διάφορα πρωτόκολλα NTP και πρωτόκολλα ώρας διακομιστή (Time Server protocols), που δεν επιστρέφουν δεδομένα που μπορούν εύκολα να διαβαστούν από τους ανθρώπους. Ένα πρωτόκολλο του application layer που στέλνει το χρόνο σε δευτερόλεπτα από τα μεσάνυχτα της 1ης Ιανουαρίου 1900, σε έναν client που συνδέεται μέσω TCP ή UDP. Ο χρόνος στέλνεται ως 32- bit ακέραιος χωρίς πρόσημο που διαβάζεται μόνο από το μηχάνημα. Το πρότυπο είναι ελλιπής, διότι δεν καθορίζει τον τρόπο ο ακέραιος -33-

RFC 959 RFC 977 RFC1034, RFC 1035 RFC 1112 RFC 1288 RFC 1305 RFC 1939 RFC 1945 RFC 2045, RFC 2046, RFC 2047 File Transfer Protocol Network News Transfer Protocol Domain Name System Host Extensions for IP Multicasting Finger Protocol Network Time Protocol (Version 3) Post Office Protocol, Version 3 Hypertext Transfer Protocol (HTTP 1.0) Multipurpose Internet Mail Extensions κωδικοποιείται σε 32 bits, αλλά στην πράξη χρησιμοποιείται ένας ακέραιος big-endian Ένα πρωτόκολλο με προαιρετική γνησιότητα και δύο socket του application layer για μεταφορά αρχείων που χρησιμοποιεί το πρωτόκολλο TCP Πρωτόκολλο του application layer, με το οποίο Usenet news μεταφέρονται από μηχάνημα σε μηχάνημα μέσω TCP. Χρησιμοποιείται από news clients που επικοινωνούν με news servers και news servers που επικοινωνούν μεταξύ τους Συλλογή λογισμικού διανομής με την οποία τα hostname που μπορούν να θυμηθούν τα ανθρώπινα όντα, όπως το www.oreilly.com, μεταφράζονται σε αριθμούς που οι υπολογιστές μπορούν να κατανοήσουν, όπως ο 198.112.208.11. Αυτό το RFC καθορίζει οι domain name servers διαφορετικών host επικοινωνούν μεταξύ τους χρησιμοποιώντας UDP Οι μέθοδοι του internet layer με τους οποίους σύμφωνα συστήματα μπορούν να κατευθύνουν ένα ενιαίο πακέτο δεδομένων σε πολλούς host ταυτόχρονα. Η διεργασία αυτή ονομάζεται multicasting και υποστηρίζεται από την Java Ένα πρωτόκολλο του application layer για την αίτηση πληροφοριών σχετικά με ένα χρήστη σε μια απομακρυσμένη ιστοσελίδα. Μπορεί να είναι κίνδυνος για την ασφάλεια Ένα πιο ακριβές πρωτόκολλο του application layer για το συγχρονισμό των clock μεταξύ των συστημάτων που προσπαθούν να αντιμετωπίσουν την καθυστέρηση του δικτύου Ένα πρωτόκολλο του application layer που χρησιμοποιείται από σποραδικά συνδεδεμένους email clients όπως το Eudora για την ανάκτηση της αλληλογραφίας τους από ένα server μέσω TCP Έκδοση 1.0 του πρωτοκόλλου του application layer που χρησιμοποιείται από προγράμματα περιήγησης στο Web που επικοινωνούν στους web servers μέσω TCP. Αναπτύχθηκε από το W3C και όχι το IETF Ένα μέσο κωδικοποίησης δυαδικών δεδομένων και μη ASCII κειμένου για μετάδοση μέσω Internet e-mail και άλλα ASCII προσανατολισμένα πρωτόκολλα -34-

RFC 2141 RFC 2616 RFC 2373 RFC 3501 RFC 3986 RFC 3987 Uniform Resource Names (URN) Syntax Hypertext Transfer Protocol (HTTP 1.1) IP Version 6 Addressing Architecture Internet Message Access Protocol Version 4rev1 Uniform Resource Identifiers (URI): Generic Syntax Internationalized Resource Identifiers (IRIs) Παρόμοια με τις διευθύνσεις URL, αλλά προορίζεται να αναφέρεται σε πραγματικούς πόρους μόνιμης τοποθεσίας παρά στην παροδική τοποθεσία των πόρων αυτών Η έκδοση 1.1 του πρωτοκόλλου του application layer που χρησιμοποιείται από προγράμματα περιήγησης στο Web που επικοινωνούν με web servers μέσω TCP Το format και η ερμηνεία των IPv6 διευθύνσεων Ένα πρωτόκολλο για την απομακρυσμένη πρόσβαση σε ένα γραμματοκιβώτιο αποθηκευμένο σε ένα διακομιστή, που περιλαμβάνει τη λήψη μηνυμάτων, τη διαγραφή τους και την μεταφορά τους σε διαφορετικούς φακέλους Παρόμοια με τις διευθύνσεις URL, αλλά περιλαμβάνουν μικρότερο μέρος. Για παράδειγμα, οι αριθμοί ISBN μπορεί να είναι URIs ακόμη και αν το βιβλίο δεν μπορεί να ανακτηθεί μέσω του διαδικτύου URIs που μπορούν να περιέχουν μη-ascii χαρακτήρες Η IETF εργάζεται παραδοσιακά στο παρασκήνιο για να κωδικοποιήσει και να τυποποιήσει υφιστάμενες πρακτικές. Παρόλο που οι δραστηριότητες της είναι εντελώς ανοικτές για το κοινό, διατηρεί ένα προφίλ πολύ χαμηλού επιπέδου. Δεν υπάρχουν πολλοί άνθρωποι που να ενθουσιάζονται με την ενασχόληση με ένα πρωτόκολλο όπως είναι το Internet Gateway Message (IGMP). Οι συμμετέχοντες στη διαδικασία είναι ως επί το πλείστον μηχανικοί και επιστήμονες ηλεκτρονικών υπολογιστών, συμπεριλαμβανομένων αρκετών από τον ακαδημαϊκό χώρο, καθώς και από τον εταιρικό κόσμο. Κατά συνέπεια, παρά τις έντονες συχνά διαφωνίες για ιδανικές εφαρμογές, οι περισσότερες σοβαρές προσπάθειες της IETF απέδωσαν εύλογα πρότυπα. Δυστυχώς, κάτι ανάλογο δεν μπορεί να ειπωθεί και για τις προσπάθειες της IETF να παράγει web (σε αντίθεση με τα διαδικτυακά) πρότυπα. Συγκεκριμένα, η πρώτη προσπάθεια της IETF να τυποποιήσει το HTML ήταν μια κολοσσιαία αποτυχία. Η άρνηση της Netscape και άλλων βασικών προμηθευτών να συμμετέχουν ή ακόμη και να αναγνωρίσουν τη διαδικασία δημιούργησε μεγάλο πρόβλημα. Το HTML ήταν αρκετά απλό και υψηλού προφίλ πρωτόκολλο, χαρακτηριστικά που ήταν αρκετά ώστε να το καταστήσουν ανοιχτό σε -35-

κακόβουλες επιθέσεις, γεγονός που δεν βοήθησε βέβαια καθόλου την κατάσταση. Έτσι, τον Οκτώβριο του 1994, το World Wide Web Consortium συγκροτήθηκε ως ένα σώμα ελεγχόμενο από τους προμηθευτές με σκοπό την αποφυγή των παγίδων που μάστιζαν τις προσπάθειες της IETF να τυποποιήσει τα HTML και HTTP. 1.7.2 Οι συστάσεις του W3C Παρόλο που η διαδικασία τυποποίησης του W3C είναι παρόμοια με τη διαδικασία του IETF (μια σειρά από σχέδια εργασίας προέβησαν σε λίστες με αποτέλεσμα τη διαμόρφωση των τελικών προδιαγραφών), το W3C είναι ένας ριζικά διαφορετικός οργανισμός. Ενώ η IETF είναι ανοικτή στη συμμετοχή από τον οποιοδήποτε, μέλη του W3C μπορούν να γίνουν μόνο εταιρείες και άλλες οργανώσεις. Οι ιδιώτες αποκλείονται ρητά, αν και μπορούν να προσκληθούν ως εμπειρογνώμονες σε συγκεκριμένες ομάδες εργασίας. Ωστόσο, ο αριθμός αυτών των ατόμων είναι αρκετά μικρός σε σχέση με τον αριθμό των ενδιαφερομένων εμπειρογνωμόνων στην ευρύτερη κοινότητα. Η συμμετοχή στο W3C κοστίζει $ 50.000 το χρόνο ($ 5.000 το χρόνο για μη κερδοσκοπικούς οργανισμούς) με ελάχιστη δέσμευση 3 ετών. Η συμμετοχή στο IETF κοστίζει $ 0 το χρόνο χωρίς καμία δέσμευση πέρα από την προθυμία συμμετοχής. Και αν και πολλοί συμμετέχουν στην ανάπτυξη των W3C προτύπων, κάθε πρότυπο θα πρέπει τελικά να εγκριθεί από ένα άτομο, τον διευθυντή του W3C, Tim Berners- Lee. Τα IETF πρότυπα εγκρίνονται με συναίνεση των ανθρώπων που εργάστηκαν για το πρότυπο. Σαφώς, η IETF είναι πολύ πιο δημοκρατική (μερικοί θα έλεγαν αναρχική) και πολύ πιο ανοιχτή οργάνωση από το W3C. Παρά την έντονη πόλωση του W3C προς τα εταιρικά μέλη που πληρώνουν τους λογαριασμούς της, έχει μέχρι στιγμής καταφέρει να κάνει καλύτερη δουλειά από την IETF στην πλοήγηση των δύσκολων πολιτικά νερών της τυποποίησης του web. Έχει παράξει πολλά πρότυπα HTML, καθώς και μια ποικιλία άλλων, όπως τα HTTP, PICS, XML, CSS, MathML, και πολλά άλλα. Το W3C έχει σημαντικά λιγότερη επιτυχία στο να πείσει προμηθευτές όπως η Mozilla και η Microsoft για την πλήρη και με συνέπεια εφαρμογή των προτύπων της. Το W3C έχει πέντε βασικά επίπεδα προτύπων: 1. Σημείωση (Note) Μια σημείωση είναι σε γενικές γραμμές είτε μια αυτόκλητη υποβολή εκ μέρους ενός μέλους του W3C (κάτι ανάλογο με το Internet draft του IETF) είτε τυχαίοι συλλογισμοί από προσωπικό του W3C ή άλλα σχετικά μέλη που δεν αποτελούν όμως μια πλήρη πραγματική -36-

πρόταση (κάτι ανάλογο με το RFC του IETF). Οι σημειώσεις δεν οδηγούν αναγκαστικά στη δημιουργία μιας ομάδας εργασίας ή μία σύσταση του W3C. 2. Σχέδια εργασίας (Working drafts) Ένα σχέδιο εργασίας είναι μια αντανάκλαση της τρέχουσας σκέψης κάποιων (όχι απαραίτητα όλων) από τα μέλη μιας ομάδας εργασίας. Θα πρέπει τελικά να οδηγήσει σε μια πρόταση σύστασης, αλλά μέχρι να γίνει κάτι τέτοιο, πολλά μπορεί να έχουν αλλάξει σημαντικά. 3. Υποψήφια σύσταση (Candidate recommendation) Μια υποψήφια σύσταση υποδηλώνει ότι η ομάδα εργασίας έχει καταφέρει να συναινέσει σε όλα τα σημαντικά ζητήματα και είναι έτοιμη για σχόλια τρίτων και εφαρμογή. Εάν κατά τη διάρκεια της εφαρμογής δεν παρουσιαστούν τυχόν εμπόδια, τότε το spec μπορεί να προαχθεί σε υποψήφια σύσταση. 4. Προτεινόμενη σύσταση (Proposed recommendation) Μια προτεινόμενη σύσταση είναι ως επί το πλείστον ολοκληρωμένη και είναι απίθανο να υποστεί αλλαγές, πλην ίσως από μικρές αλλαγές στο συντακτικό. Ο κύριος σκοπός της προτεινόμενης σύστασης είναι να βρεθούν σφάλματα στο έγγραφο προδιαγραφών και όχι στην υποκείμενη τεχνολογία που τεκμηριώνεται. 5. Σύσταση (Recommendation) Η σύσταση αποτελεί το υψηλότερο επίπεδο του προτύπου W3C. Ωστόσο, το W3C είναι πολύ προσεκτικό στο να μην την ονομάσει πρότυπο επειδή υπάρχει ο φόβος του να έρθει σε σύγκρουση με το αντιμονοπωλιακό καταστατικό. Το W3C περιγράφει μια σύσταση ως έργο που αντιπροσωπεύει συναίνεση μέσα στο W3C και έχει τη σφραγίδα έγκρισης του διευθυντή. Το W3C θεωρεί ότι οι ιδέες ή η τεχνολογία που καθορίζονται στη σύσταση είναι κατάλληλες για ευρεία ανάπτυξη και προωθεί την αποστολή του W3C. -37-

2. Κανάλια επικοινωνίας συνεχούς ροής (Streams) 2.1. Γενικά Ένα μεγάλο μέρος των λειτουργιών των δικτυακών προγραμμάτων είναι ουσιαστικά η μεταφορά δεδομένων από ένα σύστημα σε ένα άλλο. Η λήψη δεδομένων από ένα server δεν είναι τίποτα άλλο παρά η ανάγνωση ενός αρχείου. Το ίδιο συμβαίνει και κατά την αποστολή δεδομένων σε ένα client, που δεν διαφέρει και πολύ από την εγγραφή σε ένα αρχείο. Επομένως κύριο μέλημα των δικτυακών προγραμμάτων είναι η είσοδος και η έξοδος (Ι/Ο) των δεδομένων ενός συστήματος. Στην Java το (I/O) είναι οργανωμένο διαφορετικά από ότι στις περισσότερες γλώσσες προγραμματισμού όπως οι Fortran, Pascal, C, και C++ και είναι δομημένο πάνω σε κανάλια επικοινωνίας συνεχούς ροής (streams) δεδομένων. To I/O στην Java είναι δομημένο πάνω σε streams, τα streams εισόδου ανάγνωσης δεδομένων και τα streams εξόδου εγγραφής δεδομένων. Διαφορετικές κλάσεις streams, όπως οι java.io.fileinputstream και sun.net.telnetoutputstream, διαβάζουν και γράφουν συγκεκριμένες πηγές δεδομένων. Ωστόσο, όλα τα streams εξόδου έχουν τις ίδιες βασικές μεθόδους εγγραφής των δεδομένων και όλα τα streams εισόδου χρησιμοποιούν τις ίδιες βασικές μεθόδους ανάγνωσης των δεδομένων. Μετά τη δημιουργία ενός stream λίγο ενδιαφέρουν οι λεπτομέρειες του τι ακριβώς διαβάζεται ή του τι εγγράφεται. Τα φίλτρα των streams (filter streams) μπορούν να συνδυαστούν αλυσιδωτά είτε σε ένα stream εισόδου ή ένα stream εξόδου. Τα φίλτρα μπορούν να τροποποιήσουν τα δεδομένα ανάγνωσης ή εγγραφής, για παράδειγμα, με την κρυπτογράφηση ή συμπίεση τους ή μπορούν απλά να παρέχουν πρόσθετες μεθόδους για τη μετατροπή ανάγνωσης ή εγγραφής τους σε άλλες μορφές. Για παράδειγμα, η κλάση java.io.dataoutputstream παρέχει μια μέθοδο που μετατρέπει ένα int σε τέσσερα byte και γράφει αυτά τα byte στο υποκείμενο stream εξόδου του. Οι readers και οι writers μπορούν να συνδυαστούν αλυσιδωτά είτε σε ένα stream εισόδου ή ένα stream εξόδου για να επιτρέψουν στα προγράμματα να διαβάσουν και να γράψουν -38-

κείμενο (δηλαδή, χαρακτήρες) και όχι bytes. Αν χρησιμοποιηθούν σωστά, οι readers και οι writers μπορούν να χειριστούν μια μεγάλη ποικιλία από κωδικοποιήσεις χαρακτήρων, συμπεριλαμβανομένων τα σύνολα χαρακτήρων πολλαπλών byte όπως τα SJIS και UTF-8. Τα streams είναι σύγχρονα, αυτό σημαίνει ότι όταν ένα πρόγραμμα (στην πραγματικότητα ένα thread) ζητά από ένα stream να διαβάσει ή να γράψει ένα κομμάτι δεδομένων, περιμένει πρώτα να γίνει η ανάγνωση ή η εγγραφή των δεδομένων, πριν κάνει οτιδήποτε άλλο. Σκοπός του κεφαλαίου αυτού είναι η σύνοψη της ιδιαίτερης προσέγγισης της Java στο I/O καθώς και η ανάλυση των streams που χρησιμοποιούνται. 2.2. Ροές εξόδου (Output streams) Η βασική κλάση εξόδου της Java είναι η java.io.outputstream : public abstract class OutputStream Η κλάση αυτή καθορίζει τις θεμελιώδεις μεθόδους που απαιτούνται για την εγγραφή δεδομένων. Οι μέθοδοι αυτές είναι οι εξής: public abstract void write(int b) throws IOException public void write(byte[] data) throws IOException public void write(byte[] data, int offset, int length) throws IOException public void flush() throws IOException public void close() throws IOException Οι υποκλάσεις της OutputStream χρησιμοποιούν αυτές τις μεθόδους για την εγγραφή δεδομένων σε συγκεκριμένα μέσα εγγραφής. Για παράδειγμα, η FileOutputStream χρησιμοποιεί αυτές τις μεθόδους για να γράψει δεδομένα σε ένα αρχείο, η TelnetOutputStream χρησιμοποιεί αυτές τις μεθόδους για να γράψει τα δεδομένα σε μια σύνδεση δικτύου και η ByteArrayOutputStream χρησιμοποιεί αυτές τις μεθόδους για να γράψει δεδομένα σε ένα επεκτάσιμο πίνακα byte. Ως επί το πλείστον χρησιμοποιούνται μόνο αυτές οι πέντε μέθοδοι εγγραφής, ανεξάρτητα από το μέσο εγγραφής. Μερικές φορές μάλιστα είναι δυνατόν να μην είναι γνωστό ούτε το είδος του stream στο οποίο γίνεται η εγγραφή. Για παράδειγμα, στη βιβλιογραφία της βιβλιοθήκης κλάσεων της Java δεν θα βρεθεί η κλάση TelnetOutputStream, επειδή είναι σκόπιμα κρυμμένη μέσα στα πακέτα του sun. Είναι επιστροφή διαφόρων μεθόδων, διαφόρων κλάσεων της java.net, όπως η getoutputstream() της java.net.socket. Ωστόσο, αυτές οι μέθοδοι έχουν δηλωθεί ώστε να επιστρέφουν μόνο την OutputStream, και όχι την περισσότερο συγκεκριμένη υποκλάση TelnetOutputStream. -39-

Αυτή είναι η δύναμη του πολυμορφισμού. Εάν είναι γνωστή η χρησιμοποίηση της υπερκλάσης τότε είναι γνωστή και η χρησιμοποίηση όλων των υποκλάσεων. Η θεμελιώδης μέθοδος της OutputStream είναι η εντολή write(int b). Η μέθοδος αυτή λαμβάνει ως argument έναν ακέραιο (integer) από το 0 έως το 255 και γράφει το αντίστοιχο byte στο output stream. Αυτή η μέθοδος θεωρείται αφηρημένη διότι οι υποκλάσεις θα πρέπει να την τροποποιήσουν προκειμένου να χειριστούν το συγκεκριμένο μέσο εγγραφής τους. Για παράδειγμα, η ByteArrayOutputStream μπορεί να εφαρμόσει αυτή τη μέθοδο με καθαρό κώδικα Java που αντιγράφει ένα byte στον πίνακά της. Ωστόσο, η FileOutputStream θα πρέπει να χρησιμοποιήσει κώδικα ανάλογο της πλατφόρμας του host για να καταλαβαίνει πώς να γράψει δεδομένα σε αρχεία του host. Αν και η μέθοδος αυτή παίρνει ένα int ως argument, στην πραγματικότητα γράφει ένα μη προσημασμένο byte. Η χρήση του ακέραιου είναι αναγκαία επειδή η Java δεν υποστηρίζει τον τύπο των μη προσημασμένων byte. Η μόνη πραγματική διαφορά ανάμεσα σε ένα μη προσημασμένο byte και ένα προσημασμένο byte είναι η ερμηνεία, καθώς και τα δύο αποτελούνται από 8 bit τα οποία μεταφέρονται μέσω της write(int b) σε μια σύνδεση δικτύου. Εάν χρησιμοποιηθεί ένας int έξω από το εύρος 0-255, τότε γράφεται το λιγότερο σημαντικό byte του αριθμού, ενώ τα υπόλοιπα 3 αγνοούνται. Σε σπάνιες περιπτώσεις, ωστόσο, μπορεί να προκύψει κάποια εξαίρεση η οποία μπορεί να εμφανιστεί με την μορφή της IllegalArgumentException. Για παράδειγμα, το πρωτόκολλο γεννήτριας χαρακτήρων ορίζει ένα διακομιστή που στέλνει ASCII κείμενο. Η πιο δημοφιλής παραλλαγή του πρωτοκόλλου αυτού στέλνει γραμμές 72 χαρακτήρων που περιέχουν ASCII χαρακτήρες που μπορούν να τυπωθούν. (Οι ASCII χαρακτήρες που μπορούν να τυπωθούν είναι εκείνοι μεταξύ του 33 και του 126 εξαιρουμένων των διαφόρων κενών και των χαρακτήρων ελέγχου.) Η πρώτη γραμμή περιέχει ταξινομημένους τους χαρακτήρες 33 μέχρι 104. Η δεύτερη γραμμή περιέχει τους χαρακτήρες 34 έως 105. Η τρίτη γραμμή περιέχει τους χαρακτήρες 35 έως 106. Αυτό συνεχίζεται μέχρι την γραμμή 29, η οποία περιέχει τους χαρακτήρες 55 έως 126. Από το σημείο αυτό, οι χαρακτήρες αναδιπλώνονται με τέτοιο τρόπο ώστε η γραμμή 30 να περιέχει τους χαρακτήρες 56 έως 126 ακολουθούμενους και πάλι από το χαρακτήρα 33. Οι γραμμές τερματίζονται με ένα χαρακτήρα επαναφοράς (ASCII 13) και αλλαγής γραμμής (ASCII 10). Η έξοδος μοιάζει κάπως έτσι:!"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefgh -40-

"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij $%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijk %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkl &'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm '()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmn Επειδή η ASCII είναι ένα σύνολο χαρακτήρων 7-bit, κάθε χαρακτήρας αποστέλλεται ως ένα byte. Κατά συνέπεια, το πρωτόκολλο αυτό είναι εύκολο να εφαρμόσει τη χρήση των βασικών μεθόδων εγγραφής write(), όπως φαίνεται στο επόμενο κομμάτι κώδικα: public static void generatecharacters(outputstream out) throws IOException { int firstprintablecharacter = 33; int numberofprintablecharacters = 94; int numberofcharactersperline = 72; int start = firstprintablecharacter; while (true) { /* infinite loop */ for (int i = start; i < start+numberofcharactersperline; i++) { out.write(( (i-firstprintablecharacter) % numberofprintablecharacters) + firstprintablecharacter); out.write('\r'); // carriage return out.write('\n'); // linefeed start = ((start+1) - firstprintablecharacter) % numberofprintablecharacters + firstprintablecharacter; Μια OutputStream περνιέται στη μέθοδο generatecharacters() στο argument εξόδου. Τα byte γράφονται στην έξοδο, ένα τη φορά. Τα byte αυτά δίνονται ως ακέραιοι σε μια περιστρεφόμενη αλληλουχία από το 33 έως το 126. Το μεγαλύτερο μέρος του αριθμητικού εδώ είναι να κάνει το βρόχο (loop) να περιστρέφεται μέσα στο εύρος αυτό. Μετά την εγγραφή κάθε κομματιού των 72 χαρακτήρων, στο stream εξόδου γράφονται ένας χαρακτήρας επαναφοράς και ένας χαρακτήρας αλλαγής γραμμής. Στη συνέχεια υπολογίζεται ο επόμενος χαρακτήρας εκκίνησης και το loop επαναλαμβάνεται. Ολόκληρη η μέθοδος έχει δηλωθεί ώστε να δημιουργήσει μια IOException. Αυτή η εξαίρεση είναι πολύ σημαντική διότι ο server που λειτουργεί ως γεννήτρια χαρακτήρων θα τερματίσει τη λειτουργία του μόνο όταν ο client κλείσει τη σύνδεση. Το γεγονός αυτό θα γίνει αντιληπτό από τον κώδικα Java ως μια εξαίρεση IOException. Η εγγραφή ενός μόνο byte τη φορά είναι συχνά αναποτελεσματική. Για παράδειγμα, κάθε TCP segment περιέχει τουλάχιστον 40 bytes overhead για δρομολόγηση και διόρθωση λάθους. Εάν κάθε byte αποστέλλεται μόνο του, το δίκτυο θα γεμίσει με 41 φορές -41-

περισσότερα δεδομένα από ότι θα νόμιζε κανείς. Αν στην συσσώρευση αυτή των δεδομένων προστεθεί και το overhead του πρωτοκόλλου του host-to-network layer, η κατάσταση θα γίνει ακόμη χειρότερη. Κατά συνέπεια, οι περισσότερες υλοποιήσεις του TCP / IP κάνουν buffer δεδομένων ως ένα βαθμό. Δηλαδή, συσσωρεύουν τα byte στη μνήμη και τα στέλνουν στον τελικό προορισμό τους, μόνο όταν έχει συσσωρευτεί ορισμένος αριθμός ή όταν έχει περάσει ένα ορισμένο χρονικό διάστημα. Ωστόσο, εάν περισσότερα από ένα byte είναι έτοιμα να αποσταλούν, δεν είναι κακή ιδέα να αποσταλούν όλα ταυτόχρονα. Η χρήση των write(byte[] data) ή write(byte[] data, int offset, int length) κάνει την όλη διαδικασία συνήθως πολύ πιο γρήγορη σε σχέση με το να γραφούν όλες οι συνιστώσες των πινάκων δεδομένων, μία κάθε φορά. Για παράδειγμα, στη συνέχεια παρουσιάζεται μια εφαρμογή της μεθόδου generatecharacters() που στέλνει μια γραμμή τη φορά έχοντας συμπεριλάβει μια ολόκληρη γραμμή σε έναν πίνακα byte: public static void generatecharacters(outputstream out) throws IOException { int firstprintablecharacter = 33; int numberofprintablecharacters = 94; int numberofcharactersperline = 72; int start = firstprintablecharacter; byte[] line = new byte[numberofcharactersperline+2]; // the +2 is for the carriage return and linefeed while (true) { /* infinite loop */ for (int i = start; i < start+numberofcharactersperline; i++) { line[i-start] = (byte) ((i-firstprintablecharacter) % numberofprintablecharacters + firstprintablecharacter); line[72] = (byte) '\r'; // carriage return line[73] = (byte) '\n'; // line feed out.write(line); start = ((start+1)-firstprintablecharacter) % numberofprintablecharacters + firstprintablecharacter; Ο αλγόριθμος υπολογισμού των bytes που θα εγγραφούν είναι ίδιος όπως στην προηγούμενη εφαρμογή. Η κρίσιμη διαφορά είναι ότι τα byte εγγράφονται σε ένα πίνακα byte πριν την εγγραφή τους στο δίκτυο. Επίσης, το αποτέλεσμα int του υπολογισμού πρέπει να μετατραπεί σε byte πριν αποθηκευτεί στον πίνακα. Αυτό δεν ήταν αναγκαίο στην προηγούμενη εφαρμογή, διότι η μέθοδος της εγγραφής single-byte write() παίρνει ένα int ως argument. Τα streams μπορούν να αποθηκευτούν με λογισμικό τρόπο άμεσα στον κώδικα Java, καθώς και στο hardware υλικό του δικτύου. Τυπικά, αυτό επιτυγχάνεται με αλυσιδωτή σύνδεση μιας -42-

BufferedOutputStream ή μιας BufferedWriter στο υποκείμενο stream, μια τεχνική που θα διερευνηθεί στη συνέχεια. Κατά συνέπεια, αν η εγγραφή δεδομένων ολοκληρωθεί, είναι σημαντικό το stream εξόδου να καθαρίζεται. Για παράδειγμα, ας υποθέσουμε ότι έχει γραφτεί ένα αίτημα 300 byte σε ένα διακομιστή HTTP 1.1 που χρησιμοποιεί την HTTP Keep-Alive. Γενικά, είναι επιθυμητή η αναμονή για λήψη μιας απάντησης πριν την αποστολή περισσότερων δεδομένων. Ωστόσο, εάν το stream εξόδου έχει ένα buffer των 1024-byte, το stream μπορεί να περιμένει για την άφιξη περισσότερων δεδομένων πριν να στείλει δεδομένα από το δικό του buffer. Δεν πρόκειται να υπάρξουν άλλα δεδομένα εγγραφής στο stream μέχρι να έρθει η απάντηση από τον server, αλλά η απάντηση δεν πρόκειται ποτέ να φτάσει, επειδή η αίτηση δεν έχει σταλεί ακόμα! Η εικόνα 6 απεικονίζει αυτό το catch-22. Η μέθοδος flush() σπάει αυτό το αδιέξοδο αναγκάζοντας το buffer του stream να στείλει τα δεδομένα του έστω και αν το buffer δεν είναι ακόμη πλήρες. Εικόνα 6: Δεδομένα μπορούν να χαθούν αν δεν καθαριστούν πρώτα τα sreams Ο καθαρισμός των stream είναι πολύ σημαντικός. Το αν ένα stream έχει δεδομένα ή όχι στο buffer του, μπορεί να γίνει γνωστό ή όχι ανάλογα με το πώς έχει ληφθεί μια αναφορά για το stream. (Για παράδειγμα, η System.out αποθηκεύεται πάντα). Αν και ο καθαρισμός δεν είναι απαραίτητος για ένα συγκεκριμένο stream, είναι μια λειτουργία πολύ χαμηλού κόστους. Ωστόσο, εάν είναι αναγκαίος, είναι πολύ ουσιαστικό να γίνει. Αν δεν γίνει καθαρισμός όταν αυτό απαιτείται, μπορεί να οδηγήσει σε απρόβλεπτα, ανεπανάληπτα κολλήματα του προγράμματος που είναι εξαιρετικά δύσκολο να διαγνωστούν αν δεν υπάρχει ιδέα για το πηγάζει το πρόβλημα. Ως επιστέγασμα όλων αυτών, είναι ο απαραίτητος καθαρισμός των -43-

stream αμέσως και πάντα πριν το κλείσιμό τους. Διαφορετικά, τα δεδομένα που μένουν στο buffer όταν κλείσει το stream μπορεί να χαθούν. Μετά την ολοκλήρωσή του, ένα stream μπορεί να κλείσει με κλήση της μεθόδου close(). Η μέθοδος αυτή απελευθερώνει οποιουσδήποτε πόρους που σχετίζονται με το stream, όπως χειρισμούς αρχείων ή θύρες. Εάν το stream προέρχεται από μια σύνδεση δικτύου, τότε, το κλείσιμο του stream τερματίζει τη σύνδεση. Μόλις ένα stream εξόδου κλείσει, η οποιαδήποτε προσπάθεια για περαιτέρω εγγραφές σ αυτό θα έχει ως αποτέλεσμα την εμφάνιση μιας εξαίρεσης IOException. Ωστόσο, ορισμένα είδη streams μπορεί να επιτρέψουν την εκτέλεση εντολών ακόμα και μετά το κλείσιμό τους. Για παράδειγμα, ένα κλειστό ByteArrayOutputStream μπορεί ακόμη να μετατραπεί σε ένα πραγματικό πίνακα byte και ένα κλειστό DigestOutputStream μπορεί ακόμα να επιστρέψει τα περιεχόμενά του. Αν δεν κλείσει το stream ενός προγράμματος που τρέχει για πολύ ώρα μπορεί να δημιουργηθούν προβλήματα διαρροής σε χειρισμούς αρχείων, θύρες δικτύου και άλλους πόρους. Κατά συνέπεια, στην Java 6 αλλά και σε προηγούμενες εκδόσεις, είναι σοφό το κλείσιμο ενός stream με ένα block finally. Για τη σωστή εμβέλεια των μεταβλητών, θα πρέπει πρώτα να γίνει η δήλωση των μεταβλητών του stream έξω από το block try, αλλά η αρχικοποίησή του θα πρέπει να γίνει μέσα στο block try. Επιπλέον, για να αποφευχθεί η ουδέτερη PointerExceptions θα πρέπει να γίνει έλεγχος για τον μηδενισμό των μεταβλητών του stream πριν από το κλείσιμό του. Τέλος, συνήθως προτιμάται η αγνόηση τυχόν εξαιρέσεων, ή τουλάχιστον η καταγραφή τους, που εμφανίζονται κατά τη διάρκεια του κλεισίματος του stream. Για παράδειγμα: OutputStream out = null; try { out = new FileOutputStream("/tmp/data.txt"); // work with the output stream... catch (IOException ex) { System.err.println(ex.getMessage()); finally { if (out!= null) { try { out.close(); catch (IOException ex) { // ignore Η τεχνική αυτή μερικές φορές ονομάζεται πρότυπο διάθεσης (dispose pattern) και είναι κοινή για κάθε αντικείμενο που πρέπει να καθαριστεί πριν τη συλλογή των σκουπιδιών του. Η -44-

τεχνική αυτή δεν χρησιμοποιείται μόνο στα streams, αλλά και στα sockets, στα κανάλια, στις συνδέσεις και δηλώσεις JDBC και σε πολλά άλλα. Η Java 7, για να κάνει αυτό το ξεκαθάρισμα καλύτερο, εισάγει τη ιδέα της δοκιμής των πόρων (try with resources construct). Αντί η δήλωση των μεταβλητών του stream να γίνεται έξω από το block try, γίνεται μέσα σε μια λίστα από argument του block try. Για παράδειγμα, το προηγούμενο απόσπασμα κώδικα γίνεται τώρα πολύ απλούστερο: try (OutputStream out = new FileOutputStream("/tmp/data.txt")) { // work with the output stream... catch (IOException ex) { System.err.println(ex.getMessage()); Στην περίπτωση αυτή, το κλείσιμο finally δεν είναι αναγκαίο. Η Java κάνει αυτόματη κλήση της close() ή οποιουδήποτε αντικειμένου AutoCloseable που δηλώνεται εντός της λίστας των argument του block try. 2.3. Ροές εισόδου (Input streams) Η βασική κλάση εισόδου της Java είναι η java.io.inputstream: public abstract class InputStream Η κλάση αυτή περιέχει τις θεμελιώδεις μεθόδους που απαιτούνται για την ανάγνωση δεδομένων ως ακατέργαστα (raw) bytes. Οι μέθοδοι αυτές είναι οι ακόλουθες: public abstract int read() throws IOException public int read(byte[] input) throws IOException public int read(byte[] input, int offset, int length) throws IOException public long skip(long n) throws IOException public int available() throws IOException public void close() throws IOException Οι συμπαγείς υποκλάσεις της InputStream χρησιμοποιούν αυτές τις μεθόδους για την ανάγνωση δεδομένων από συγκεκριμένα μέσα. Για παράδειγμα, η FileInputStream διαβάζει δεδομένα από ένα αρχείο, η TelnetInputStream διαβάζει δεδομένα από μια σύνδεση δικτύου και η ByteArrayInputStream διαβάζει δεδομένα από ένα πίνακα με bytes. Όποια όμως και αν είναι η πηγή της ανάγνωσης, ως επί το πλείστον μόνο αυτές οι έξι μέθοδοι χρησιμοποιούνται. Μερικές φορές δεν είναι γνωστό το είδος του stream από το οποίο γίνεται η ανάγνωση των δεδομένων. Για παράδειγμα, η TelnetInputStream είναι μια undocumented κρυμμένη κλάση στο εσωτερικό του sun.net πακέτου. Στιγμιότυπά της (Instances) επιστρέφουν με διάφορες μεθόδους στο java.net πακέτο (π.χ., η μέθοδος openstream() της -45-

java.net.url). Ωστόσο, αυτές οι μέθοδοι επιστρέφουν μόνο InputStream και όχι την πιο συγκεκριμένη υποκλάση TelnetInputStream. Η διαδικασία αυτή αποτελεί για ακόμα μια φορά πολυμορφισμό. Το στιγμιότυπο της υποκλάσης μπορεί να χρησιμοποιηθεί με διαφάνεια και ως στιγμιότυπο της υπερκλάσης (superclass) της. Με τον τρόπο αυτό, δεν απαιτείται συγκεκριμένη γνώση της υποκλάσης. Βασική μέθοδος της InputStream είναι η μέθοδος read() που δεν έχει arguments. Η μέθοδος αυτή διαβάζει ένα μόνο byte δεδομένων από την πηγή του stream εισόδου και επιστρέφει έναν int από το 0 έως το 255. Το τέλος του stream καθορίζεται με επιστροφή -1. Η μέθοδος read() περιμένει και αναιρεί την εκτέλεση οποιουδήποτε κώδικα την ακολουθεί μέχρι να είναι διαθέσιμο για ανάγνωση το επόμενο byte δεδομένων. Επειδή η διαδικασία εισόδου και εξόδου (Ι/Ο) μπορεί να είναι αργή, στην περίπτωση που ένα πρόγραμμα εκτελεί μια διαδικασία μεγαλύτερης σημασίας, καλό θα είναι το Ι/Ο να μπει στο δικό του thread. Η μέθοδος read() θεωρείται αφηρημένη διότι οι υποκλάσεις θα πρέπει να την τροποποιήσουν προκειμένου να χειριστούν το συγκεκριμένο μέσο από το οποίο διαβάζουν δεδομένα. Για παράδειγμα, ένα ByteArrayInputStream μπορεί να εφαρμόσει τη μέθοδο αυτή με καθαρό κώδικα Java που αντιγράφει το byte από τον πίνακά του. Ωστόσο, ένα TelnetInputStream πρέπει να χρησιμοποιήσει μια φυσική βιβλιοθήκη που καταλαβαίνει πως να διαβάσει τα δεδομένα από τη διεπαφή δικτύου της πλατφόρμας του host. Το παρακάτω κομμάτι κώδικα διαβάζει 10 byte από το InputStream in και τα αποθηκεύει στο input ενός πίνακα byte. Ωστόσο, ο βρόχος τερματίζεται συντομότερα όταν ανιχνεύεται το τέλος του stream: byte[] input = new byte[10]; for (int i = 0; i < input.length; i++) { int b = in.read(); if (b == -1) break; input[i] = (byte) b; Αν και η read() διαβάζει μόνο ένα byte, επιστρέφει ένα int. Γι αυτό, είναι απαραίτητη μια μετατροπή πριν την αποθήκευση του αποτελέσματος στον πίνακα των byte. Η μετατροπή αυτή δημιουργεί προσημασμένα byte από το -128 έως το 127 αντί των μη προσημασμένων byte από το 0 έως το 255 που επιστρέφει η μέθοδος read(). Ωστόσο, εάν είναι σαφής ποια από τις δύο περιπτώσεις (ακέραιοι με ή χωρίς πρόσημο) είναι απαραίτητη στην εφαρμογή, το πρόβλημα δεν είναι μεγάλο. Κάθε προσημασμένο byte μπορεί να μετατραπεί σε μη προσημασμένο με τον παρακάτω τρόπο: int i = b >= 0? b : 256 + b; -46-

Η ανάγνωση ενός μόνο byte τη φορά είναι τόσο αναποτελεσματική όσο και η εγγραφή ενός byte δεδομένων τη φορά. Κατά συνέπεια, υπάρχουν δύο υπερφορτωμένες μέθοδοι read() που γεμίζουν ένα καθορισμένο πίνακα με πολλαπλά byte δεδομένων τα οποία διαβάζονται από τα stream read(byte[] input) και read(byte[] input, int offset, int length). Η πρώτη μέθοδος επιχειρεί να γεμίσει τον καθορισμένο input πίνακα. Η δεύτερη επιχειρεί να γεμίσει τον καθορισμένο input υποπίνακα, αρχίζοντας με offset και συνεχίζοντας με length byte. Στις παραπάνω προτάσεις το ρήμα επιχειρεί σημαίνει ότι η εκάστοτε μέθοδος όντως προσπαθεί να συμπληρώσει τον πίνακα χωρίς αυτό να σημαίνει κατ 'ανάγκην ότι θα το πετύχει. Μια προσπάθεια μπορεί να αποτύχει με διάφορους τρόπους. Για παράδειγμα, δεν είναι σπάνιο το φαινόμενο της αποσύνδεσης των χρηστών λόγω εμφάνισης σφάλματος στα κεντρικά γραφεία μιας τηλεφωνικής εταιρείας κατά την ώρα που τα προγράμματα που τρέχουν στους υπολογιστές τους διαβάζουν δεδομένα από έναν απομακρυσμένο web server μέσω DSL. Κάτι τέτοιο θα μπορούσε να προκαλέσει μια IOException. Συχνότερα, ωστόσο, μια προσπάθεια ανάγνωσης δεν αποτυγχάνει εντελώς, αλλά και δεν είναι και πλήρως επιτυχημένη. Μερικά από τα bytes που έχουν ζητηθεί προς ανάγνωση, μπορούν να διαβαστούν, αλλά όχι όλα. Για παράδειγμα, γίνεται προσπάθεια ανάγνωσης 1.024 bytes από μια σύνδεση δικτύου, όταν μόνο τα 512 έχουν πραγματικά φθάσει από τον server και τα υπόλοιπα είναι ακόμα υπό μεταφορά. Όταν θα φτάσουν τελικά, εκείνη ακριβώς τη στιγμή μπορεί να μην είναι διαθέσιμα για ανάγνωση. Για να αντιμετωπιστεί αυτό το πρόβλημα, οι μέθοδοι ανάγνωσης πολλαπλών byte επιστρέφουν τον αριθμό των byte που πραγματικά διαβάστηκαν. Το παρακάτω κομμάτι κώδικα αποτελεί ένα παράδειγμα: byte[] input = new byte[1024]; int bytesread = in.read(input); Προσπαθεί να διαβάσει 1.024 bytes από το InputStream in στον πίνακα input. Παρόλα αυτά, αν είναι διαθέσιμα μόνο τα 512 byte, τόσα μόνα θα διαβάσει και η bytesread θα πάρει την τιμή 512. Για να εξασφαλιστεί η ανάγνωση όλων των bytes, η διαδικασία ανάγνωσης μπαίνει σε ένα βρόγχο που διαβάζει συνεχώς μέχρι την πλήρωση του πίνακα. Για παράδειγμα: int bytesread = 0; int bytestoread = 1024; byte[] input = new byte[bytestoread]; while (bytesread < bytestoread) { bytesread += in.read(input, bytesread, bytestoread - bytesread); -47-

Η τεχνική αυτή είναι ιδιαίτερα σημαντική για τα streams του δικτύου. Οι πιθανότητες είναι ότι εάν ένα αρχείο είναι διαθέσιμο, τότε και όλα τα bytes του είναι επίσης διαθέσιμα. Ωστόσο, επειδή η ταχύτητα του δικτύου είναι μικρότερη από ότι των επεξεργαστών (CPUs), είναι πολύ εύκολο για ένα πρόγραμμα να αδειάσει το buffer του δικτύου πριν την ολοκλήρωση της λήψης όλων των δεδομένων. Στην πραγματικότητα, εάν μία από αυτές τις δύο μεθόδους προσπαθήσει να διαβάσει από ένα προσωρινά άδειο αλλά ανοικτό buffer του δικτύου, γενικά η μέθοδος θα επιστρέψει 0, υποδεικνύοντας ότι δεν υπάρχουν διαθέσιμα δεδομένα χωρίς όμως ακόμη να έχει κλείσει το stream. Η διαδικασία αυτή είναι συχνά προτιμότερη σε σχέση με την συμπεριφορά της μεθόδου ανάγνωσης ενός byte, η οποία αποκλείει το thread που εκτελείται στις ίδιες περιστάσεις. Και οι τρεις μέθοδοι read() επιστρέφουν -1 για να σηματοδοτήσουν το τέλος του stream. Αν το stream τερματιστεί ενώ υπάρχουν ακόμα δεδομένα που δεν έχουν διαβαστεί, οι μέθοδοι read() πολλαπλών byte επιστρέφουν τα δεδομένα μέχρι να αδειάσει το buffer. Η επόμενη κλήση οποιασδήποτε μεθόδου read() θα επιστρέψει -1. Το -1 δεν τοποθετείται ποτέ στον πίνακα. Ο πίνακας περιέχει μόνο τα πραγματικά δεδομένα. Το προηγούμενο κομμάτι κώδικα έχει ένα σφάλμα, διότι δεν έχει ληφθεί υπόψη το ενδεχόμενο ότι και τα 1.024 bytes δεν έχουν φτάσει (σε αντίθεση με το να μην είναι άμεσα διαθέσιμα). Η διόρθωση αυτού του σφάλματος απαιτεί τη δοκιμή της τιμής επιστροφής της read() πριν από την προσθήκη της στην bytesread. Για παράδειγμα: int bytesread = 0; int bytestoread = 1024; byte[] input = new byte[bytestoread]; while (bytesread < bytestoread) { int result = in.read(input, bytesread, bytestoread - bytesread); if (result == -1) break; // end of stream bytesread += result; Αν δεν είναι επιθυμητή η αναμονή της άμεσης διαθεσιμότητας όλων των bytes, μπορεί να γίνει χρήση της μεθόδου available() με τον καθορισμό του αριθμού των bytes που μπορούν να διαβαστούν χωρίς αποκλεισμό. Η μέθοδος αυτή επιστρέφει τον ελάχιστο αριθμό bytes που μπορούν να διαβαστούν. Μπορεί να διαβαστούν και περισσότερα, όμως το σίγουρο είναι ότι θα διαβαστούν τουλάχιστον όσα bytes αναφέρει η available(). Για παράδειγμα: int bytesavailable = in.available(); byte[] input = new byte[bytesavailable]; -48-

int bytesread = in.read(input, 0, bytesavailable); // continue with rest of program immediately... Σε αυτή την περίπτωση, είναι αναμενόμενο ότι η bytesread θα είναι ακριβώς ίση με την bytesavailable. Δεν είναι αναμενόμενο ωστόσο, ότι η bytesread θα είναι μεγαλύτερη από μηδέν. Είναι πιθανό να μην υπάρχουν διαθέσιμα bytes. Στο τέλος του stream, η available() επιστρέφει 0. Σε γενικές γραμμές, η read(byte[] input, int offset, int length) επιστρέφει -1 στο τέλος του stream. Στην περίπτωση αυτή, αν το length είναι 0, τότε το τέλος του stream δεν γίνεται κατανοητό και αντ αυτού επιστρέφει 0. Σε σπάνιες περιπτώσεις, υπάρχει η επιθυμία παράκαμψης των δεδομένων χωρίς την ανάγνωσή τους. Η διαδικασία αυτή γίνεται με χρήση της μεθόδου skip(). Η μέθοδος αυτή είναι λιγότερο χρήσιμη στις συνδέσεις δικτύου από ότι στην ανάγνωση από αρχεία. Οι συνδέσεις δικτύου είναι διαδοχικές και συνήθως αρκετά αργές. Για το λόγο αυτό η ανάγνωση των δεδομένων δεν παίρνει περισσότερο χρόνο από την παράκαμψή τους. Επειδή η πρόσβαση στα αρχεία είναι τυχαία, η παράκαμψη είναι προτιμότερο να υλοποιηθεί με απλή επανατοποθέτηση του δείκτη αρχείου παρά με την επεξεργασία κάθε byte που θα παρακαμφθεί. Όπως και στην περίπτωση των stream εξόδου, ένα stream εισόδου θα πρέπει να κλείνει τη στιγμή που το πρόγραμμα έχει τελειώσει μαζί του, κάτι που επιτυγχάνεται με κλίση της μεθόδου close(). Η μέθοδος αυτή απελευθερώνει τυχόν πόρους που σχετίζονται με το stream, όπως χειρισμούς αρχείων ή θύρες. Μόλις ένα stream εισόδου κλείσει, η οποιαδήποτε προσπάθεια για περαιτέρω ανάγνωση από αυτό θα έχει ως αποτέλεσμα την εμφάνιση μιας εξαίρεσης IOException. Ωστόσο, ορισμένα είδη streams μπορεί να επιτρέψουν την εκτέλεση εντολών ακόμα και μετά το κλείσιμό τους. Για παράδειγμα, δεν είναι επιθυμητή πάντα η ανάκτηση του μηνύματος της java.security.digestinputstream μέχρι την ανάγνωση των δεδομένων και το κλείσιμο του stream. 2.3.1 Σήμανση και Επαναφορά (Marking and Resetting) Η κλάση InputStream έχει τρεις λιγότερο χρησιμοποιούμενες μεθόδους που επιτρέπουν τη δημιουργία αντιγράφων ασφαλείας (back up) και την εκ νέου ανάγνωση δεδομένων που έχουν ήδη διαβαστεί. Οι μέθοδοι αυτές είναι οι εξής: public void mark(int readaheadlimit) public void reset() throws IOException public boolean marksupported() -49-

Για την εκ νέου ανάγνωση των δεδομένων, απαιτείται η σήμανση της τρέχουσας θέσης στο stream με χρήση της μεθόδου mark(). Σε μεταγενέστερο στάδιο, το stream μπορεί να επανέλθει στο σημείο σήμανσης με χρήση της μεθόδου reset(). Μεταγενέστερες αναγνώσεις θα επιστρέψουν δεδομένα αρχίζοντας από τη θέση σήμανσης. Ωστόσο, η επιστροφή μπορεί να μην είναι τόσο πίσω όσο είναι επιθυμητό. Ο αριθμός των bytes που μπορούν να αναγνωστούν από το σημείο σήμανσης και επαναφοράς καθορίζεται από το argument readaheadlimit της mark(). Αν γίνει προσπάθεια για μακρινότερη προς τα πίσω επαναφορά θα προκύψει μια εξαίρεση IOException. Επιπλέον, σε δεδομένη στιγμή, σε ένα stream μπορεί να υπάρχει μόνο μία σήμανση. Η σήμανση σε μια δεύτερη θέση θα έχει ως αποτέλεσμα τη διαγραφή της πρώτης. Οι διαδικασίες της σήμανσης και της επαναφοράς υλοποιούνται συνήθως με την αποθήκευση κάθε byte που διαβάζεται από το σημείο σήμανσης σε ένα εσωτερικό buffer. Ωστόσο, οι διαδικασίες αυτές δεν υποστηρίζονται από όλα τα stream εισόδου. Πριν την χρησιμοποίησή τους, μπορεί να γίνει έλεγχος της υποστήριξής τους μέσω της μεθόδου marksupported(). Αν οι διαδικασίες υποστηρίζονται τότε η μέθοδος αυτή θα επιστρέψει true. Σε αντίθετη περίπτωση, η μέθοδος mark() δεν θα κάνει τίποτα ενώ με την reset() θα προκύψει IOException. Οι μόνες κλάσεις stream εισόδου στην java.io που υποστηρίζουν πάντα τη σήμανση είναι οι BufferedInputStream και η ByteArrayInputStream. Ωστόσο, και άλλες input streams, όπως η TelnetInputStream, μπορούν να υποστηρίξουν τη σήμανση αρκεί πρώτα να έχουν συνδεθεί αλυσιδωτά με το buffered input stream. 2.4. Φίλτρα Ροών (Filter Streams) Οι InputStream και OutputStream είναι αρκετά ακατέργαστες (raw) κλάσεις. Το μόνο που κάνουν είναι να διαβάζουν και να γράφουν bytes μεμονωμένα ή σε ομάδες. Η απόφαση του τι σημαίνουν αυτά τα bytes, αν είναι ακέραιοι ή αριθμοί κινητής υποδιαστολής IEEE 754 ή κείμενο Unicode, εξαρτάται αποκλειστικά από τον προγραμματιστή και τον κώδικα. Ωστόσο, υπάρχουν ορισμένες ιδιαίτερα κοινές μορφές δεδομένων, που μπορούν να επωφεληθούν από μια στερεά εφαρμογή στην βιβλιοθήκη κλάσεων. Για παράδειγμα, πολλοί ακέραιοι που έχουν περάσει ως μέρη των πρωτοκόλλων δικτύου είναι 32-bit ακέραιοι big-endian. Μεγάλο μέρος του κειμένου που αποστέλλεται μέσω του Web είναι είτε ASCII 7-bit, 8-bit Latin-1, ή multibyte UTF-8. Πολλά αρχεία που μεταφέρονται μέσω FTP αποθηκεύονται σε μορφή ZIP. Η Java παρέχει μια σειρά από κλάσεις φίλτρων που μπορούν να επισυναφθούν σε -50-

ακατέργαστα streams για τη μετάφραση των ακατέργαστων bytes σε αυτές και άλλες μορφές, αλλά και το αντίστροφο. Υπάρχουν δύο κατηγορίες φίλτρων: τα φίλτρα συνεχούς ροής δεδομένων (filter streams) και οι Readers και Writers. Τα filter streams εργάζονται κατά κύριο λόγο με τα ακατέργαστα δεδομένα ως bytes, για παράδειγμα, με τη συμπίεση των δεδομένων ή την ερμηνεία τους ως δυαδικούς αριθμούς. Οι Readers και Writers διαχειρίζονται ειδικές περιπτώσεις κειμένου με κωδικοποίηση, όπως UTF-8 και ISO 8859-1. Εικόνα 7: Ροή δεδομένων μέσω αλυσίδας φίλτρων -51-