Ξεκινάμε την παρουσίαση του προγραμματισμού σε χαμηλό επίπεδο (sockets) με το πρωτόκολλο UDP. Αυτό γίνεται γιατί το UDP, αν και δεν εγγυάται τη μετάδοση των δεδομένων μας, έχει ορισμένα χαρακτηριστικά που διευκολύνουν τον προγραμματισμό διαδικτυακών εφαρμογών:
Χρησιμοποιούμε το socket module της standard βιβλιοθήκης. Αυτό δεν είναι παρά ένα περιτύλιγμα των κλασσικών διαδικτυακών βιβλιοθηκών συστήματος σε C. Συνεπώς μπορούμε να ανατρέξουμε και στα αντίστοιχα εγχειρίδια, εάν η τεκμηρίωση του module δεν μας καλύπτει.
Χωρίς να αναφερθούμε στη θεωρία των διαδικτυακών πρωτοκόλλων (θεωρούμε ότι γνωρίζουμε τα βασικά!), παραθέτουμε μια σειρά εννοιών που είναι σχετικές τόσο με το UDP, όσο και με το TCP:
Διευθύνσεις: αποτελούνται από δύο μέρη,
Οι διευθύνσεις στην Python είναι πάντα μια πλειάδα (tuple) με δύο μέρη: (IP address,port).
- Το IP address είναι πάντα τύπου string και το port αριθμός.
- Η ειδική διεύθυνση IP “INADDR_ANY” (οποιαδήποτε IP address) συμβολίζεται με το κενό string ''.
- Η ειδική διεύθυνση 'localhost' (127.0.0.1) διακινεί πακέτα μέσα στον υπολογιστή μας, χωρίς έξοδο στο διαδίκτυο.
Μέγιστος αριθμός λαμβανόμενων δεδομένων: όλες οι συναρτήσεις λήψης για το UDP ή το TCP, δέχονται ως παράμετρο bufsize τον μέγιστο αριθμό δεδομένων που μπορούν να επιστρέψουν.
Note
Συνήθως χρησιμοποιούμε ως bufsize έναν αριθμό δύναμη του 2, μεταξύ των 1024 και 4096. Αν και κάποια στιγμή θα μπούμε στον πειρασμό να χρησιμοποιήσουμε μεγαλύτερα νούμερα, δεν υπάρχει πρακτικό όφελος.
For best match with hardware and network realities, the value of bufsize
should be a relatively small power of 2, for example, 4096.
-- Python Standard Libray Documentation, socket module.
Δημιουργία sockets: Χρησιμοποιούμε τη μέθοδο socket.socket() για τη δημιουργία αντικειμένων socket. Η μέθοδος δέχεται διάφορες παραμέτρους, όπως:
‘Δέσιμο’ με διεύθυνση λήψης: μετά τη δημιουργία του, ένα socket είναι ‘unbound’. Για να ‘δεθεί’ με συγκεκριμένη διεύθυνση χρησιμοποιούμε τη μέθοδο bind(). Αυτό χρειάζεται μόνο για τα sockets των εφαρμογών server.
Κλείσιμο socket: Η σωστή τακτική είναι να χρησιμοποιούμε ρητά τη μέθοδο close(). H Python πάντως θα κλείσει αυτόματα οποιαδήποτε socket είναι ανοικτά κατά τον τερματισμό του προγράμματος.
Στο παράδειγμα που ακολουθεί, παρουσιάζεται ο κώδικας για έναν απλό UDP server:
import socket
# create a datagram socket
serversock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# Bind server socket to an arbitrary non-privileged port number.
# Here host is '', meaning INADDR_ANY (any interface)
serversock.bind(('',50007)) # NOTE: tuple argument!
# run until manually killed, serversock will be garbage collected
while True:
requestdata,addr = serversock.recvfrom(1024) # max read at once 1024 bytes - blocking call!!
print "server: from %s received data=%s" % (repr(addr),requestdata)
Ο αντίστοιχος UDP client:
import socket
import sys
# check if an addr is given as argument
host = 'localhost'
if len(sys.argv)>1: host = sys.argv[1]
# create the client socket object - no difference from 'server' socket!
clientsock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
# get a series of msgs from user
tosend = raw_input("client: enter string to send>")
if tosend=='': break
# send string
clientsock.sendto(tosend,(host,50007))
# close socket
clientsock.close()