Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 WinSock σε C Επιμέλεια παρουσίασης : Ζδράγκας Σωτήρης Κονταξής Αναστάσιος Ντακούλας Αντώνιος Επιβλέπων καθηγητής : Φουληράς Π. Ανάπτυξη Δικτύων Τελευταία ενημέρωση: 16/8/2014
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 -API ΥποδοχέςAPI Υποδοχές -Λειτουργίες ΥποδοχώνΛειτουργίες Υποδοχών -Βασικές ΣυναρτήσειςΒασικές Συναρτήσεις -Συναρτήσεις Αποστολής ΔεδομένωνΣυναρτήσεις Αποστολής Δεδομένων -Συναρτήσεις Λήψης ΔεδομένωνΣυναρτήσεις Λήψης Δεδομένων Ιστορικά - Εισαγωγή
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Ειδικά Θέματα -Εκδόσεις WinSockΕκδόσεις WinSock -Κύρια Πρωτόκολλα Μεταφοράς - TCPTCP - UDPUDP - ΤΥΠΟΙ ΥΠΟΔΟΧΩΝΤΥΠΟΙ ΥΠΟΔΟΧΩΝ -Προσδιορισμός IP με WinSockΠροσδιορισμός IP με WinSock -Επιλογή Αριθμού Θύρας ServerΕπιλογή Αριθμού Θύρας Server
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 -Κώδικας Client με TCP (Διαφάνειες 1, 2, 3, 4, 5, 6 ) Κώδικας Server με TCP (Διαφάνειες 1, 2, 3, 4, 5, 6 ) Κώδικες
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 API Υποδοχές -Διασύνδεση προγραμματισμού εφαρμογών -BSD UNIX -Ενσωμάτωση σε άλλα λειτουργικά -Βιβλιοθήκες υποδοχών -Ορισμός τους από το λειτουργικό
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Λειτουργίες Υποδοχών - Πρωτόκολλα επικοινωνίας / API - Ενοποιημένες με έννοιες στο Unix - open, read, write, close - Νήματα
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Βασικές Συναρτήσεις - Δημιουργία υποδοχής: περιγραφέας = socket(οικογένεια πρωτοκόλλων, τύπος, πρωτόκολλο ) - Τερματισμός χρήσης της υποδοχής Close(υποδοχή) [closesocket στα Windows] - Παροχή αριθμού θύρας πρωτοκόλλου Bind(υποδοχή, τοπική διεύθυνση, μήκος διεύθυνσης) - Τοποθέτηση υποδοχής σε παθητική κατάσταση Listen(υποδοχή, μέγεθος ουράς) -Αποδοχή νέας αίτησης σύνδεσης Νέα υποδοχή =accept(υποδοχή, διεύθ.πελάτη, μήκος διεύθ.πελάτη) -Εγκαθίδρυση σύνδεσης πελάτη με συγκεκριμένο διακομιστή Connect(υποδοχή, διεύθ.διακομιστή, μήκος διεύθ.διακομιστή)
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Συναρτήσεις Αποστολής Δεδομένων - Μεταφορά δεδομένων (συνδεσμική μεταφορά) Send(υποδοχή, δεδομένα, μήκος, σημαίες) -Μεταφορά δεδομένων (ασυνδεσμική μεταφορά) Sendto(υποδοχή, δεδομένα, μήκος, σημαίες, διεύθ.προορισμού, μήκος διεύθυνσης) Sendmsg(υποδοχή, δομή μηνύματος, σημαίες)
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Συναρτήσεις Λήψης Δεδομένων -Λήψη δεδομένων (συνδεσμική μεταφορά) Recv(υποδοχή, buffer, μήκος, σημαίες) -Λήψη δεδομένων (ασυνδεσμική μεταφορά) Recvfrom(υποδοχή, buffer, μήκος, σημαίες, διεύθυνση αποστολέα, μήκος διεύθυνσης αποστολέα) Recvmsg(υποδοχή, δομή μηνύματος, σημαίες) >
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Εκδόσεις Winsock Διασύνδεση προγραμματισμού εφαρμογών (API) για το λειτουργικό σύστημα Windows βασισμένη στο υπόδειγμα των υποδοχών Υπάρχουν δύο εκδόσεις WinSock. Οι ευρύτερα διαδε- δομένες είναι οι: -WinSock 1.1 (Παλαιότερη) -WinSock (Η πιο πρόσφατη) +Υποστήριξη πολλαπλών πρωτοκόλλων μεταφοράς WinSock vs WinSock 1.1 +Εφικτή η συγγραφή προγραμμάτων που τρέχουν ανεξάρτητα του χρησιμοποιούμενου πρωτοκόλλου
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 TCP Πρωτόκολλο Eλέγχου Mετάδοσης (Transmission Control Protocol, TCP) +100% Επιτυχία στη μεταφορά δεδομένων +Ενώνει επιμέρους αποστολές και τις αποστέλλει συγκεντρωτικά (Αλγόριθμος Nagle) Πλεονεκτήματα
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 UDP Πρωτόκολλο Αυτοδύναμων Πακέτων Χρήστη (User Datagram Protocol,UDP) +Πιο οικονομικό σε σχέση με το TCP (8 bytes Header) Πλεονεκτήματα +Πιο γρήγορο (Λείπουν οι αλγόριθμοι Nagle και Delayed ACK) +Μικρότερο διάστημα λανθάνουσας κατάστασης μεταξύ άφιξης πακέτου στην κάρτα δικτύου και παράδοσής του στην εφαρμογή (Απαιτείται λιγότερος κώδικας) +Μόνο UDP πακέτα μπορούν να είναι εκπεμπόμενα και πολυεκπεμπόμενα
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Προσδιορισμός IP με Winsock Τρεις τρόποι προσδιορισμού: 1.Καλώντας την συνάρτηση getsockname() σε μια συνδεδεμένη υποδοχή 2.Καλώντας την συνάρτηση gethostname() επιστρέφεται μια τιμή η χρησιμοποιείται από την gethostbyname() 3. Με την επιλογή SIO_GET_INTERFACE_LIST της νέας συνάρτησης WSAIoctl()*. Ένα από τα bit πληροφοριών που επιστρέφεται είναι οι IP διευθύνσεις κάθε μιας διεπαφής του συστήματος
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Επιλογή Αριθμού Θύρας Server Χρησιμοποιούνται ήδη προσδιορισμένοι αριθμοί θυρών στα γνωστά πρωτόκολλα. Κανόνες επιλογής: δεσμευμένες θύρες για καθορισμένα πρωτ. διαθέσιμες θύρες δυναμικές θύρες εύρος επιλογής τοπικών θυρών ασφαλές εύρος για επιλογή θύρας
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Client με TCP /* * Program: client * * Purpose: αναθέτει σε ένα socket,συνδέεται σε ένα server και τυπώνει τα output * * Syntax: client [ host [port] ] * * host - όνομα του υπολογιστή στον οποίο εκτελείται ο server * port - αριθμός θύρας πρωτοκόλλου που ο server χρησιμοποιεί * * Note: Και το host και το port είναι προαιρετικά. Αν δεν δίνεται όνομα host ο client χρησιμοποιεί το ‘localhost’.Αν δεν δίνεται το protocol port ο client δίνει το αρχικό από το PROTOPORT. * * */ 1, 2, 3, 4, 5, 6 >> >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Client με TCP ( συνέχεια) /* client.c – κώδικας για παράδειγμα client που χρησιμοποιεί tcp */ #ifndef unix#define WIN32 #include #else#define closesocket close #include #endif#include #include #define PROTOPORT 5193 /* αρχικός αριθμός port*/ extern int errno;char localhost[] = "localhost"; /* αρχικός αριθμός host << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Client με TCP (συνέχεια) main(argc, argv) int argc; char *argv[]; { struct hostent *ptrh; /* pointer σε ένα host table entry */ struct protoent *ptrp; /* pointer σε ένα protocol table entry */ struct sockaddr_in sad; /* δομή που κρατά μια IP address */ int sd; /* περιγράφει τα socket */ int port; /* protocol port number */ char *host; /* pointer στο host name */ int n; /* αριθμός χαρακτήρων που διαβάστηκαν */ char buf[1000]; /* buffer για δεδομένα από τον server */ #ifdef WIN32 WSADATA wsaData; WSAStartup(0x0101, &wsaData); << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Client με TCP (συνέχεια) #endif memset((char *)&sad,0,sizeof(sad)); /* καθάρισε την δομή sockaddr*/ sad.sin_family = AF_INET; /* βάλε family to Internet */ /* εξετάζει την εντολή στη γραμμή εντολών για το protocol number */ /* port number αν αυτό δίνεται. Αλλιώς πάρε το default */ /* port value δίνεται από το constant PROTOPORT */ if (argc > 2) { /* αν δίνεται το protocol number */ port = atoi(argv[2]); /* μετέτρεψε σε δυαδικό */ } else { port = PROTOPORT; /* πάρε το default port number */ } if (port > 0) /*εξέτασε για αποδεκτή τιμή */ sad.sin_port = htons((u_short)port); else { /* μήνυμα για λανθασμένη πληκτρολόγηση και έξοδος */ fprintf(stderr,"bad port number %s\n",argv[2]); exit(1); } << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Client με TCP (συνέχεια) /* εξετάζω το host argument και αποδίδω host name. */ if (argc > 1) { host = argv[1]; /* αν το host argument είναι καθορισμένο */ } else { host = localhost; } /* μετατροπή του host name σε IP address και αντιγραφή στο sad. */ ptrh = gethostbyname(host); if ( ((char *)ptrh) == NULL ) { fprintf(stderr,"invalid host: %s\n", host); exit(1); } memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length); /* αποδίδω το TCP transport protocol name σε protocol number. */ if ( ((int)(ptrp = getprotobyname("tcp"))) == 0) { fprintf(stderr, "cannot map \"tcp\" to protocol number"); exit(1); } /* δημιουργία socket. */ sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto); if (sd < 0) { fprintf(stderr, "socket creation failed\n"); exit(1); } << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Client με TCP /* σύνδεση του socket με τον καθορισμένο server. */ if (connect(sd, (struct sockaddr *)&sad, sizeof(sad)) < 0) { fprintf(stderr,"connect failed\n"); exit(1); } /* συνεχόμενο διάβασμα data από το socket και τύπωμα στην οθόνη του χρήστη */ n = recv(sd, buf, sizeof(buf), 0); while (n > 0) { write(1,buf,n); n = recv(sd, buf, sizeof(buf), 0); } /* κλείσιμο του socket. */ closesocket(sd); /* τερματισμός του προγράμματος client */ exit(0);} <<<< 1, 2, 3, 4, 5,
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Server με TCP /* * πρόγραμμα: server * * σκοπός : ανάθεση ενός socket και επαναλαμβανόμενη εκτέλεση των παρακάτω : * (1) περιμένω για την επόμενη σύνδεση client * (2) στέλνω ένα μικρό μήνυμα στον client * (3) Κλείνω την σύνδεση * (4) γυρνώ ξανά στο βήμα (1) * * σύνταξη : server [ port ] * * port - αριθμός protocol port που χρησιμοποιείται * * Note: ο αριθμός protocol port δεν είναι υποχρεωτικός. Αν δεν δίνεται παίρνουμε αυτόν που δίνεται από το PROTOPORT. * * */ 1, 2, 3, 4, 5, 6 >> >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Server με TCP ( συνέχεια) /* server.c – κώδικας παραδείγματος server που χρησιμοποιεί tcp*/ #ifndef unix #define WIN32 #include #else #define closesocket close #include #endif#include #include #define PROTOPORT 5193 /* default protocol port number */ #define QLEN 6 /* μέγεθος της ζητούμενης ουράς */ int visits = 0; /* μετρά τις συνδέσεις του client */ << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Server με TCP ( συνέχεια) main(argc, argv) int argc; char *argv[]; { struct hostent *ptrh; /* pointer σε ένα host table entry */ struct protoent *ptrp; /* pointer σε ένα protocol table entry */ struct sockaddr_in sad; /* δομή που κρατά την διεύθυνση του server*/ struct sockaddr_in cad; /* δομή που κρατά την διεύθυνση του client*/ int sd, sd2; /* περιγράφει τα sockets */ int port; /* protocol port number */ int alen; /* μήκος της διεύθυνσης */ char buf[1000]; /* buffer για το string που στέλνει ο server*/ << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Server με TCP ( συνέχεια) #ifdef WIN32 WSADATA wsaData; WSAStartup(0x0101, &wsaData); #endif memset((char *)&sad,0,sizeof(sad)); /* καθαρίζω το sockaddr structure */ sad.sin_family = AF_INET; /* βάζω το family στο Internet */ sad.sin_addr.s_addr = INADDR_ANY; /* βάζω την τοπική IP address */ /* εξετάζω την εντολή στη γραμμή εντολών για το protocol port */ /* port number αν κάποιο έχει οριστεί. Αλλιώς χρησιμοποιώ το default */ /* η τιμή του port δίνεται από την constant PROTOPORT */ if (argc > 1) { /* αν η τιμή είναι ορισμένη */ port = atoi(argv[1]); /* μετατρέπω την τιμή σε δυαδικό */ } else { port = PROTOPORT; /* χρησιμοποίησε default port number */ } if (port > 0) /* εξετάζω για μη αποδεκτές τιμές */ sad.sin_port = htons((u_short)port); else { /* τυπώνω μήνυμα λάθους και έξοδος */ fprintf(stderr,"bad port number %s\n",argv[1]); exit(1); } << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Server με TCP ( συνέχεια) /* μετατροπή του TCP transport protocol name σε protocol number */ if ( ((int)(ptrp = getprotobyname("tcp"))) == 0) { fprintf(stderr, "cannot map \"tcp\" to protocol number"); exit(1); } /* δημιουργία socket */ sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto); if (sd < 0) { fprintf(stderr, "socket creation failed\n"); exit(1); } /* δέσμευση μιας τοπικής διεύθυνσης για το socket */ if (bind(sd, (struct sockaddr *)&sad, sizeof(sad)) < 0) { fprintf(stderr,"bind failed\n"); exit(1); } << > >>
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Κώδικας Server με TCP ( συνέχεια) /* καθορίζω το μήκος της ζητούμενης ουράς */ if (listen(sd, QLEN) < 0) { fprintf(stderr,"listen failed\n"); exit(1); } /* βασικό loop του server – δέχεται και χειρίζεται αιτήσεις */ while (1) { alen = sizeof(cad); if ( (sd2=accept(sd, (struct sockaddr *)&cad, &alen)) < 0) { fprintf(stderr, "accept failed\n"); exit(1); } visits++; sprintf(buf,"This server has been contacted %d time%s\n", visits,visits==1?".":"s."); send(sd2,buf,strlen(buf),0); closesocket(sd2); }} <<<< 1, 2, 3, 4, 5,
Ειδικά Θέματα Κώδικες Ιστορικά - Εισαγωγή Αρχική σελίδα 16/8/2014 Τύποι Υποδοχών -Δημιουργία υποδοχής TCP με την εισαγωγή SOCK_STREAM ως δευτέρου ορίσματος της συνάρτησης socket(). -Δημιουργία υποδοχής UDP με την εισαγωγή SOCK_DGRAM ως δευτέρου ορίσματος της συνάρτησης socket(). -Δημιουργία υποδοχής ανεπεξέργαστων δεδομένων με την εισαγωγή SOCK_RAW ως δεύτερου ορίσματος της συνάρτησης socket(). -Σχεδιάστηκαν ακόμη δυο τύποι υποδοχών οι οποίοι δεν υλοποιήθηκαν.