Cocoa, sockets και Bonjour

Στο Δ’ εξάμηνο στην Πληροφορική Αθηνών μας παραδίδεται υποχρεωτικά το μάθημα της εισαγωγής στα δίκτυα υπολογιστών. Εντάξει, σαν ύλη έχει τα αναμενόμενα: θύρες, πρωτόκολλα, πολυεπίπεδη οργάνωση δικτύων, πακέτα, καθυστερήσεις, όλα τα καλά. Το κλου όμως: δίνουν και μία εργασία που μπορείς να εκπονήσεις μέχρι το τέλος του εξαμήνου, και η οποία – αν την έχεις σωστή – σου προσθέτει ένα 5% στον τελικό βαθμό. Μισό στα δέκα έξτρα δηλαδή, για να εξηγούμαστε.

Το φετινό θέμα ήταν, πολύ απλά, να γράψουμε δυο προγράμματα που να επικοινωνούν μεταξύ τους τύπου client/server, με χρήση sockets, και να μπορούν να αποστέλλουν μηνύματα το ένα στο άλλο – τύπου IM δηλαδή, με timestamping και τα λοιπά. Η επιλογή γλώσσας, πλατφόρμας και περιβάλλοντος δόθηκε στον καθένα μας, και φυσικά (δε θέλει και ρώτημα) με το καλημέρα σας διάλεξα Objective-C και Cocoa.

Λοιπόν, μερικά πραγματάκια για τους προγραμματιστές αναγνώστες. Όσον αφορά τα διαδικαστικά του interface δεν έχω πολλά να πω: ό,τι γράφουν τα guides της Apple επαρκούν. Φροντίστε να τα διαβάσετε – αν πάτε π.χ. όπως εγώ να προσθέσετε κείμενο στο τέλος μίας NSTextView στα κουτουρού και ψάχνοντας από τις περιγραφές των APIs θα προσπαθείτε να καταλάβετε γιατί δε σας δένει η σάλτσα. Όλα τα υπόλοιπα είναι αυτοεπεξηγηματικά: μέχρι και bindings να θελήσετε να κάνετε, δε θα έχετε ιδιαίτερο πρόβλημα. Στα υπόλοιπα προκαταρκτικά, χρήσιμη ως απαραίτητη είναι η κατανόηση της έννοιας των delegates και των callback συναρτήσεων.

Θέλω να σταθώ κυρίως σε δυο θέματα: τη χρήση sockets στο OS X και την τεχνολογια Bonjour (κατά το προτυπότερον, zeroconf).

Το θέμα sockets θέλει ψάξιμο. Υπάρχουν διάφοροι τρόποι για να στήσει ο προγραμματιστής τόσο listening socket, όσο και socket για σύνδεση από τη μεριά του client. Η ίδια η διαδικασία της δημιουργίας μπορεί να γίνει με πολλούς τρόπους, από τα κλασικά C BSD sockets, μέχρι κλάσεις του Foundation (CFSocket) και της Cocoa (NSSocketPort). Ο τρόπος δεν παίζει ιδιαίτερο ρόλο, στην τελική ο στόχος μας είναι να πάρουμε ένα έτοιμο, καταχωρημένο από το σύστημα socket που να μπορούμε να χρησιμοποιήσουμε ως file descriptor για να γράψουμε και να διαβάσουμε. Οι διάφορες είναι περισσότερο τεχνικές: η διάφορα είναι πως με χρήση της κλασικής βιβλιοθήκης έχουμε περισσότερο έλεγχο, η NSSocketPort απλουστεύει τη διαδικασία (αλλά παραμένει απλή μόνο για TCP πρωτόκολλο) – η τελευταία χρησιμοποιείται και από το σύστημα Distributed Objects messaging της Cocoa μεταξύ εφαρμογών που βρίσκονται σε διαφορετικά μηχανήματα του δικτύου, αλλά στην περίπτωσή μας εξυπηρετεί και χωρίς πολλά πολλά. Η μέση λύση είναι η CFSocket, η οποία προσφέρει σχεδόν το σύνολο του ελέγχου της C βιβλιοθήκης, και έχει το πλεονέκτημα ότι υποστηρίζει run loop integration: δημιουργείς νέο στιγμιότυπο της κλάσεως, το ρυθμίζεις καταλλήλως και το δηλώνεις σε ένα run loop πριν το ανοίξεις. Όταν το socket που έφτιαξες δέχεται εισερχόμενη σύνδεση ή είναι έτοιμο για χρήση καλείται η callback που είχες ρυθμίσει και αναλαμβάνεις από εκεί. Αν είναι να μη χρησιμοποιήσεις αυτή τη δυνατότητα της CFSocket μην ασχοληθείς καν.

Με τον έναν ή τον άλλον τρόπο λοιπόν έχεις έτοιμο socket για χρήση. Υπάρχουν δύο τινά με τα οποία μπορείς να πάρεις και να στείλεις δεδομένα: ή με τη χρήση της NSFileHandle, η με τη χρήση των σαφών υποτύπων της NSStream (NSInputStream και NSOutputStream). Η πρώτη επιλογή είναι η απλούστερη και πιο μοντέρνα: χρησιμοποιείς το socket σου ως file descriptor και ανοίγεις ένα νέο file handle από το οποίο μπορείς να διαβάσεις και να γράψεις. Για ασύγχρονη ανάγνωση (για να μην κολλάει το προγραμμα στα lags) δηλώνεις τον εαυτό σου observer στο default notification center για συγκεκριμένα notifications που σου έρχονται όταν υπάρχουν έτοιμα δεδομένα προς ανάγνωση και οταν είναι εφικτό θα κληθεί η κατάλληλη delegate μέθοδος. Προσοχή όμως: όταν υπάρχει νέα εισερχόμενη σύνδεση ή όταν υπάρχουν νέα δεδομένα για ανάγνωση τα notifications που έρχονται περιέχουν νέο NSFileHandle από το οποίο γίνεται η ανάγνωση – το κύριο αντικείμενο χρησιμοποιείται μόνο για λόγους αναμονής για τη σύνδεση από τον server. Επίσης, κάθε φορά που έρχεται ένα notification πρέπει να λέμε στο handle να συνεχίσει να παρακολουθεί για events αλλιώς δε θα λάβουμε περαιτέρω ειδοποιήσεις. Με αυτό το μηχανισμό ελέγχουμε και το πόσες εισερχόμενες συνδέσεις θελουμε. Ένα τελευταίο tip: η NSFileHandle είναι η απλούστερη λύση αλλά έχει το μειονέκτημα πως η έγγραφη στο stream εξόδου γίνεται αναγκαστικά σύγχρονα οπότε αν προβλεπετε καθυστερήσεις θα πρέπει η έγγραφη να γίνεται σε δικό της block ή thread.

Η δεύτερη λύση είναι η χρήση του NSStream. Και πάλι με χρήση του έτοιμου από πριν socket συνδεόμαστε με τον server και ζητάμε να μας δώσει έτοιμα το εισερχόμενο και εξερχόμενος stream δεδομένων (ή ένα μόνο από τα δύο). Τους δηλώνουμε τον εαυτό μας ως delegate, τα περνάμε στο run loop πριν τα ανοίξουμε και μετά παίρνουμε τα events που παράγουν όταν θέλουν την προσοχή μας – και για ελεγχόμενη και ασύγχρονη εγγραφή στο ρεύμα εξόδου. Προσοχή, θέλουν retain μετά τη δημιουργία τους γιατί επιστρέφονται χωρίς… τόκο (ήτοι, με autorelease). Από εκεί και πέρα δε διαφέρει πολύ η χρήση, με μια βασική εξαίρεση: οι υποτάξεις της NSStream δε μπορούν να χρησιμοποιηθούν για ακρόαση από τον server. Εκεί η μοναδική λύση πέραν της NSFileHandle είναι η καταφυγή στην CFSocket, δήλωση στο run loop, και όταν ενημερώσει το socket πως υπάρχει εισερχόμενη σύνδεση, μέσα στην callback πλέον μας επιστρέφονται πλέον τα – προσέξτε – CFReadStream και CFWriteStream αντικείμενα που αντιστοιχούν στα ρεύματα εισόδου/εξόδου. Από εκεί και πέρα, χάρη στο toll-free bridging μεταξύ Cocoa και Foundation, αυτά τα αντικείμενα μετατρέπονται άμεσα σε NSStreams που ο προγραμματιστής δουλεύει κατα βούλησιν. Επιλογή σας το πώς θέλετε να δουλέψετε.

Τώρα, πριν κλείσουμε θέλω να πω δυο λόγια για το Bonjour και το Net Services framework της Cocoa. Είναι φοβερή τεχνολογία – για όσους δε γνωρίζουν και χωρίς να μπαίνω σε τεχνικές λεπτομέρειες, αφορά την αυτόματη διαφήμιση και ανακάλυψη υπηρεσιών σε ένα δίκτυο/domain με χρήση multicast DNS. Με απλά λόγια, αν έχεις έναν file server σε ένα μηχάνημα και αυτός δηλωθεί στο Bonjour, όλα τα υπόλοιπα μηχανήματα στο δίκτυο που τρέχουν τους ανάλογους clients τον βλέπουν αυτόματα, χωρίς να χρειάζεται ο χρήστης να περνά με το χέρι θύρες και διευθύνσεις δικτύου. Γι’ αυτό και το γενικότερο, non Apple specific όνομα της υπηρεσίας: zeroconf(iguration).

Η χρήση του Bonjour έχει ως εξής πολύ συνοπτικά: ο server δηλώνει μέσω της NSNetService τον εαυτό του στο σύστημα, προσδιορίζοντας το όνομα του και το descriptor της υπηρεσίας που παρέχει. Αυτό ήταν: ο client αρχικοποιεί ένα αντίγραφο της κλάσεως NSNetServicesBrowser και αφού το ρυθμίσει καταλλήλως του ζητάει να ξεκινήσει την αναζήτηση για διαθέσιμους servers. Από εκεί και πέρα όταν αρχίζει/σταματάει η αναζήτηση, όταν βρίσκεται ή χάνεται ένας server και επί σφαλμάτων, καλούνται οι δηλωθείσες από τον προγραμματιστή delegate methods που αναλαμβάνουν τον έλεγχο των υπηρεσιών, το γέμισμα του πίνακα που τις παρακολουθεί (και αν δεν κάνουμε χρήση bindings, την ενημέρωση του interface). Η μαγκία είναι πως όταν θες να συνδεθεις με έναν server ζητάς από το NSNetService αντικείμενο που τον αναπαριστά και που ανακαλυψες αυτόματα να σου ανοίξει τα απαραίτητα NSStreams… και τέλος! Ούτε sockets ούτε συνδέσεις ούτε τίποτα:) Δεύτερο ατού, πολλές παραδοσιακές υπηρεσίες, όπως το FTP, το AFP, το HTTP, το SSH και άλλες έχουν ήδη έτοιμα descriptors για το Bonjour, οπότε με χρήση της τεχνολογίας ο οποιοσδήποτε προγραμματιστής μπορεί να ανακαλύψει αυτόματα τέτοιους servers και να συνδεθεί αυτόματα σ’ αυτούς.

Γενικώς είναι καλά δομημένα τα frameworks και σου δίνουν χέρι να κάνεις αυτά που θέλεις. Απλώς θέλει λίγο διάβασμα ώστε να μπορείς να φέρεις εις πέρας γρηγορότερα και πιο αποτελεσματικά τη δουλειά σου:)

2 Responses to “Cocoa, sockets και Bonjour”


  1. 1 javapapo 11 Απριλίου 2010 στο 5:24 μμ

    1. Μια ταπεινήπ παρατήρηση σε τέτοια θέματα πρέπει να βάζεις κώδικα αλλιώς με οτ μπλα μπλά χάνεται η μπάλα!

    2. δεν ειμαι cocoa developer αλλά απο μια μικρή έρευνα που έκανα – μιας και διάβασα το post σου – τα foundation classes που υπάρχουν δεν είναι και τότο απλουστευμένα ούτε ραφιναρισμένα – ιδιαίτερα για νέους προγραμματιστές.

    Δηλαδή – απλά και σύντομα ποιο ειναι το implementation το οποιο χρησιμοποιεί selectors (non blocking multiplex_) . Λίγο χάθηκα!

    3. Πωω ρε φίλε πραγματικά – η Objective C ειναι στην ανάγνωση πιο μπουρδέλο και απο την C++,,δηλάδή χίλιες φορές να έγραφα απλή C.

  2. 2 Flareman 11 Απριλίου 2010 στο 8:17 μμ

    @papo:

    1. Duly noted, όπως πάντα σωστός.

    2. Φίλε πρόσεξε, τα Foundation classes είναι όντως αρκετά ζόρικα (και μονόδρομος για μια πιο προηγμένη χρήση) αλλά όπως λέει και το όνομα είναι εργαλεία υποδομής – πάνω στο Foundation πατάει η Cocoa που είναι πιο υψηλού επιπέδου. Αρκετά classes της Cocoa (NS*) είναι wrappers για δυνατότητες που προσφέρονται ουσιαστικά από το Foundation framework, απλώς αφαιρούν την πολυπλοκότητα. Σαφώς προτιμαμε την Cocoa όπου γίνεται, απλουστεύει πολύ τα πράγματα. Ως προς τα CF* structures έχεις δίκιο πάντως, αρκετές ρουτίνες τους θυμίζουν πολύ OpenGL και αντίστοιχα toolkits που θέλουν εφτά δείκτες/αναφορές και δεκαπέντε ορισματα για να πάρεις έτοιμο για χρήση αντικείμενο.

    3. Εδώ διαφωνούμε – η καθαρή Cocoa είναι πολύ καθαρή και απλή στην ανάγνωση. Αν τώρα αρχίσει ο coder να μπλέξει standard C, callbacks, ObjC messages και λίγο από Core Foundation… εκεί είναι λίγο fail όντως!

    respect που λες κι εσύ:)


Σχολιάστε

Εισάγετε τα παρακάτω στοιχεία ή επιλέξτε ένα εικονίδιο για να συνδεθείτε:

Λογότυπο WordPress.com

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό WordPress.com. Αποσύνδεση / Αλλαγή )

Φωτογραφία Twitter

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Twitter. Αποσύνδεση / Αλλαγή )

Φωτογραφία Facebook

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Facebook. Αποσύνδεση / Αλλαγή )

Φωτογραφία Google+

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Google+. Αποσύνδεση / Αλλαγή )

Σύνδεση με %s




Κατηγορίες

ΗΜΕΡΟΛΟΓΙΟ

Απριλίου 2010
Δ T Τ T Π S S
« Mar   May »
 1234
567891011
12131415161718
19202122232425
2627282930  

ΠΑΛΑΙΟΤΕΡΕΣ ΣΕΖΟΝ…

del.icio.us

Twitter

ASK2USE

ΔΙΑΦΟΡΑ

Μας διαβάζουν τακτικά:

Counter free

Αρέσει σε %d bloggers: