SYSTÈME D’EXPLOITATION I SIF-1015
Contenu du cours 7 Communication par socket Autre implantation Concepts et opérations de base Communication réseau par socket Autre implantation IPC par socket LECTURES: Chapitre 3 (OSC) Chapitre 14 (Mitchell) Chapitres 5 et 8 (Beck) Chapitre 16 (Johnson) http://csapp.cs.cmu.edu/
Concepts et opérations de base Les IPC étudiés jusqu’à maintenant (tube anonyme, tube nommé, messages, mémoire partagée) supportent seulement la communication entre processus sur un même ordinateur Les sockets offrent pour leur part une interface de program-mation permettant de communiquer par réseau et aussi localement sur un ordinateur Cette interface offre l’avantage de programmer des applications réseaux en utilisant le concept de descripteur de fichier UNIX Les échanges par sockets sont alors effectués par des opérations standards d’I/O (read(), write()) en utilisant les descripteurs de socket appropriés
Concepts et opérations de base Communication réseau Un ordinateur branché à un réseau peut communiquer avec un autre ordinateur en créant par exemple un paquet (données et informations protocolaires) et en l’acheminant vers le routeur le plus proche, qui lui achemine le paquet vers le prochain routeur jusqu’à l’ordinateur de destination L’échange d’informations entre ordinateurs est régit par des protocoles Les principaux protocoles: IP (Internet Protocol) : supporte un mode d’identification de base et le transfert non fiable de paquets de données (datagrams) d’un hôte à un autre UDP (Unreliable Datagram Protocol): Protocole orienté-paquet ne supportant pas le séquençage des paquets et le contrôle d’erreurs TCP de TCP/IP: Protocole à flot de données (streaming) qui supporte le séquençage et le contrôle des erreurs
Concepts et opérations de base Les applications réseaux sont basées sur le modèle client-serveur: Un processus serveur et un ou plusieurs processus client Le serveur gère des ressources Le serveur offre des services en manipulant des ressources pour les clients 1. client sends request client process server process resource 4. client handles response 3. server sends response 2. server handles request Note: clients et serveurs sont des processus s’exécutant sur un ou plusieurs hôtes
Concepts et opérations de base: Organisation matérielle d’un hôte en réseau register file CPU chip ALU system bus memory bus main memory MI I/O bridge Expansion slots I/O bus USB controller graphics adapter disk controller network adapter mouse keyboard monitor disk network
Concepts et opérations de base: Réseaux d’ordinateurs Un réseau est un ensemble hiérarchique de machines interreliées et organisées en fonction de leur proximité géographique LAN (local area network): réseau local d’un édifice ou d’un campus Réseau Ethernet WAN (wide-area network): réseau étendu à une province, un pays, au monde Typiquement des liens haute-vitesse comme les réseaux à fibres optiques L’internet est une interconnection d’un ensemble de réseaux Réseau INTERNET IP
Concepts et opérations de base: Segment ETHERNET Le segment Ethernet consiste en une collection d’hôtes (hosts) connectés (twisted pairs) à des hub (répétiteurs) Peut déservir un laboratoire ou un étage dans un édifice Opération Chaque adapteur Ethernet possède une adresse de 48 bits Les hôtes acheminent les bits aux autres hôtes en blocs appelés frames Les hub copient chaque bit de chaque port à tous les autres ports Chaque hôte voit alors chaque bit host host host 100 Mb/s 100 Mb/s hub ports
Concepts et opérations de base Communication réseau
Concepts et opérations de base: Les ponts Permet d’étendre un réseau à un édifice Les ponts permettent de distribuer les paquets d’information en associant les ports entre eux A B host host host host host X hub bridge hub 100 Mb/s 100 Mb/s 1 Gb/s host host 100 Mb/s 100 Mb/s hub bridge hub Y host host host host host C
Concepts et opérations de base: INTERNETs Les routeurs permettent de connectés plusieurs LAN Les réseaux interconnectés sont appelés internet. ... ... host host host host host host LAN 1 LAN 2 router router router WAN WAN LAN 1 et LAN 2 peuvent être complètement différents (ex: Ethernet et ATM)
Concepts et opérations de base: La notion de protocole internet Comment est-il possible de transférer des bits entre LANs ou WANs incompatibles ? Solution: Le protocol software s’exécutant dans chaque hôte et routeur permet d’harmoniser les différences entre les réseaux Ce logiciel implémente un protocole internet (i.e., un ensemble de règles d’échange) qui gouverne la manière dont les hôtes et les routeurs doivent coopérer lorsqu’ils échangent des données d’un réseau à un autre TCP/IP est le protocole de l’internet global
Concepts et opérations de base: La notion de protocole internet Identification uniforme Le protocole internet définit un format uniforme d’identification des hôtes (adresse) Chaque hôte (et routeur) est associé à au moins une de ces adresses internet qui les identifient de façon unique Mécanisme de transfert Le protocole internet définit le format de l’unité de transfert de base: le paquet (packet) Les paquets sont composés d’une en-tête et des données en-tête: contient de l’information comme la dimension du paquet, les adresses source et la destination données: contient les bits de données échangées entre les hôtes
Concepts et opérations de base: Transfert de données sur un internet Host A Host B client server (1) (8) data data protocol software protocol software internet packet (2) (7) data PH FH1 data PH FH2 LAN1 frame LAN1 adapter LAN2 adapter Router (3) (6) data PH FH1 data PH FH2 LAN1 adapter LAN2 adapter LAN1 LAN2 LAN2 frame (4) data PH FH1 (5) data PH FH2 protocol software
Concepts et opérations de base: Internet IP Global L’exemple le plus important d’un internet Basé sur la famille de protocoles TCP/IP IP (Protocole Internet) Permet l’identification et le transfert non-fiable de paquets (datagrams) d’un hôte à l’autre UDP (Unreliable Datagram Protocol) Utilise l’IP pour l’échange non-fiable de paquets de processus à processus TCP (Transmission Control Protocol) Utilise l’IP pour transférer de façon sécuritaire des flots d’octets (ex: fichiers) de processus à processus Accessible par un mélange d’I/O fichier UNIX et d’appels de fonction à l’interface socket de Berkeley
Concepts et opérations de base: Organisation d’une application Internet Internet client host Internet server host client server user code sockets interface (system calls) TCP/IP TCP/IP kernel code hardware interface (interrupts) network adapter network adapter hardware Global IP Internet
Concepts et opérations de base: L’INTERNET vu par le programmeur Chaque hôte est représenté par une adresse IP de 32 bits 128.2.203.179 Un ensemble d’adresses IP peut être associé à un d’identificateur de domaine (domain names) 128.2.203.179 est associé au nom de domaine www.cs.cmu.edu Un processus sur un hôte communique avec un autre hôte via une connexion
Concepts et opérations de base: Adresses IP Les adresses IP de 32 bits sont stockées dans une structure in_addr Les adresses IP sont toujours stockées en mémoire selon un ordonnancement d’octet réseau (big-endian) /* Internet address structure */ struct in_addr { unsigned int s_addr; /* network byte order (big-endian) */ }; Fonctions d’ordonnancement d’octets réseau: htonl: convertir des long int du format hôte à réseau htons: convertir des short int du format hôte à réseau ntohl: convertir des long int du format réseau à hôte ntohs: convertir des short int du format réseau à hôte
Concepts et opérations de base: Adresses IP Par convention, chaque adresse IP peut être représentée dans une chaîne de nombres décimaux séparés par des points Adresse IP 0x8002C2F2 = 128.2.194.242 Fonctions permettant la conversion d’adresses IP d’un format binaire à un format dotted-decimal: inet_aton: convertir une chaîne dotted-decimal à une adresse IP binaire en ordre réseau inet_ntoa: convertir une adresse IP en ordre réseau à une chaîne dotted-decimal “n” pour réprésentation réseau et “a” pour une représentation application
Concepts et opérations de base: Noms de domaines IP unnamed root first-level domain names mil edu gov com mit cmu berkeley amazon second-level domain names cs ece www 208.216.181.15 third-level domain names cmcl pdl kittyhawk 128.2.194.242 imperial 128.2.189.40
Concepts et opérations de base: Domain Naming System (DNS) L’Internet maintient dans une base de données distribuée appelée DNS, une correspondance entre les adresses IP et le nom de domaine Conceptuellement, cette base de données DNS est en fait un ensemble de structures hostent (host entry): /* DNS host entry structure */ struct hostent { char *h_name; /* official domain name of host */ char **h_aliases; /* null-terminated array of domain names */ int h_addrtype; /* host address type (AF_INET) */ int h_length; /* length of an address, in bytes */ char **h_addr_list; /* null-terminated array of in_addr structs*/ }; Fonctions permettant d’obtenir une structure hostent du DNS: gethostbyname: recherche avec le nom de domaine DNS gethostbyaddr: recherche par l’adresse IP
Concepts et opérations de base: Domain Naming System (DNS) Chaque structure hostent est une classe d’équivalence entre des noms de domaine et des adresses IP Chaque hôte possède un nom de domaine local localhost lequel correspond à l’adresse loopback 127.0.0.1 Différents types de correspondance sont possibles: Correspondance 1-1 entre le nom de domaine et l’adresse IP: kittyhawk.cmcl.cs.cmu.edu correspond à 128.2.194.242 Correspondance de plusieurs noms de domaine à une adresse IP : eecs.mit.edu et cs.mit.edu correspondent à 128.62.1.6 Correspondance de plusieurs noms de domaines à plusieurs adresses IP: aol.com et www.aol.com correspondent à trois différentes adresses IP
Concepts et opérations de base: Domain Naming System (DNS) int main(int argc, char **argv) { /* argv[1] is a domain name char **pp; * or dotted decimal IP addr */ struct in_addr addr; struct hostent *hostp; if (inet_aton(argv[1], &addr) != 0) hostp = Gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET); else hostp = Gethostbyname(argv[1]); printf("official hostname: %s\n", hostp->h_name); for (pp = hostp->h_aliases; *pp != NULL; pp++) printf("alias: %s\n", *pp); for (pp = hostp->h_addr_list; *pp != NULL; pp++) { addr.s_addr = *((unsigned int *)*pp); printf("address: %s\n", inet_ntoa(addr)); }
Concepts et opérations de base: Connexions Internet Clients et serveurs échangent des flots d’octets par des connexions: point-to-point, full-duplex, et fiable Un socket est une terminaison d’une connexion L’adresse d’un socket est une paire IPaddress:port Un port est un entier de 16 bits qui identifie un processus: Ports éphémères: assignés automatiquement à un client qui demande une connexion Ports connus: associés à des services offerts par un serveur (ex: port 80 associé aux serveurs WEB) Une connexion est identifiée de façon unique par les adresses socket de ses terminaisons (cliaddr:cliport, servaddr:servport)
connection socket pair Concepts et opérations de base: Connexions Internet client socket address 128.2.194.242:51213 server socket address 208.216.181.15:80 client server (port 80) connection socket pair (128.2.194.242 :51213, 208.216.181.15:80) client host address 128.2.194.242 server host address 208.216.181.15
Communication réseau par socket: Modèle Client-server Les applications réseaux sont basées sur le modèle client-server: L’application est un processus serveur et un ou plusieurs processus clients Le serveur gère des ressources, et offre des services en manipulant des ressources pour les clients. Chaque client fait des requêtes pour un service Le serveur offre des services en manipulant des ressources au nom du client et en retournant une réponse 1. client sends request client process server process resource 4. client handles response 3. server sends response 2. server handles request
Communication réseau par socket: Clients Examples de programme client Web browsers, ftp, telnet, ssh Comment le client trouve-t-il le serveur? L’addresse du processus serveur a deux parties: IPaddress:port L’ IP address est un entier positif de 32 bits qui identifie l’hôte Forme dotted-decimal: 0x8002C2F2 = 128.2.194.242 Le port est un entier positif associé à un service donc à un processus serveur sur un machine port 7: echo server port 23: telnet server port 25: mail server port 80: web server
Communication réseau par socket: Ports comme identificateur de service server machine 128.2 194.242 client machine service request for 128.2.194.242:80 (i.e., the Web server) Web server (port 80) client kernel Echo server (port 7) Web server (port 80) service request for 128.2.194.242:7 (i.e., the echo server) client kernel Echo server (port 7)
Communication réseau par socket: Serveurs Les serveurs sont des processus qui s’exécutent sur une longue période de temps (daemons) Créer au boot-time (typiquement) par le processus init (process 1) Roule continuellement Chaque serveur attend des requêtes sur des ports connus, chacun associé à un service port 7: echo server port 25: mail server port 80: http server port 20, 21: FTP server Port 23: Telnet server Voir le répertoire /etc/services pour obtenir la liste des services disponibles sur une machine Linux
Communication réseau par socket: L’interface Sockets Berkeley Créer au début des années 80, et faisait partie de la distribution de UNIX Berkeley qui contenait les prémices des protocoles Internet Offrait une interface usager au réseau Constitue la base de toutes les applications Internet Basée sur le modèle client/server
Communication réseau par socket: Socket Un socket est un descripteur qui permet à une application de faire des I/O du/au réseau Unix utilise la même abstraction pour les I/O fichier et celles réseau Les clients et serveurs communiquent entre eux en effectuant des I/O sur les descripteurs de socket Utilisant des opérations UNIX read et write La seule différence réside dans la manière d’ouvrir le socket (création du descripteur)
Communication réseau par socket: Structures de données importantes Définit dans /usr/include/netinet/in.h Les sockets Internet sont caractérisés par une adresse IP de 32 bits et un numéro de port /* Internet address */ struct in_addr { unsigned int s_addr; /* 32-bit IP address */ }; /* Internet style socket address */ struct sockaddr_in { unsigned short int sin_family; /* Address family (AF_INET) */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* IP address */ unsigned char sin_zero[...]; /* Pad to sizeof “struct sockaddr” */
Communication réseau par socket: Structures de données importantes Définie dans /usr/include/netdb.h hostent est un descripteur d’hôte qui associe un domain name (ex:, cmu.edu) avec une adresse IP (128.2.35.186) Peut être obtenue par programmation gethostbyname() [par le domain name] gethostbyaddr() [par l’adresse IP] Aussi par la commande shell nslookup ou dig /* Domain Name Service (DNS) host entry */ struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses */ }
Communication réseau par socket: Client local simple // Créer un socket // Nommer le socket
Communication réseau par socket: Serveur local simple Exécution: >server1 & [1] 1094 server waiting >client1 char from server = B // Supprimer un socket existant // Donner un nom au socket // Écouter une connexion // Créer une connexion active
Communication réseau par socket: Client local simple
Communication réseau par socket: Serveur local simple
Communication réseau par socket: L’interface Client Server socket socket bind open_listenfd open_clientfd listen connection request connect accept writen readline Await connection request from next client readline writen EOF close readline close
Communication réseau par socket: Client Echo int main(int argc, char **argv) { int clientfd, port; char *host, buf[MAXLINE]; if (argc != 3) { fprintf(stderr, "usage: %s <host> <port>\n", argv[0]); exit(0); } host = argv[1]; port = atoi(argv[2]); clientfd = open_clientfd(host, port); while (Fgets(buf, MAXLINE, stdin) != NULL) { Writen(clientfd, buf, strlen(buf)); Readline(clientfd, buf, MAXLINE); Fputs(buf, stdout); Close(clientfd);
Communication réseau par socket: Client Echo open_clientfd() int open_clientfd(char *hostname, int port) { int clientfd; struct hostent *hp; struct sockaddr_in serveraddr; clientfd = Socket(AF_INET, SOCK_STREAM, 0); /* fill in the server's IP address and port */ hp = Gethostbyname(hostname); bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; bcopy((char *)hp->h_addr, (char *)&serveraddr.sin_addr.s_addr, hp->h_length); serveraddr.sin_port = htons(port); /* establish a connection with the server */ Connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr)); return clientfd; }
Communication réseau par socket: Client Echo open_clientfd() (socket) Le client crée un socket qui sera utilisé comme terminaison d’une connexion (SOCK_STREAM) Internet (AF_INET) socket() retoune un entier qui représente le descipteur de socket int clientfd; /* socket descriptor */ clientfd = Socket(AF_INET, SOCK_STREAM, 0);
Communication réseau par socket: Client Echo open_clientfd()(gethostbyname) Le client construit alors l’adresse Internet du serveur int clientfd; /* socket descriptor */ struct hostent *hp; /* DNS host entry */ struct sockaddr_in serveraddr; /* server’s IP address */ typedef struct sockaddr SA; /* generic sockaddr */ ... /* fill in the server's IP address and port */ hp = Gethostbyname(hostname); bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; bcopy((char *)hp->h_addr, (char *)&serveraddr.sin_addr.s_addr, hp->h_length); serveraddr.sin_port = htons(port);
Communication réseau par socket: Client Echo open_clientfd()(connect) Le client crée alors une connexion avec le serveur Le processus client est suspendu (blocks) tant que la connexion n’est pas créée avec le serveur Le client est alors prêt à échanger des messages avec le serveur par des appels d’I/O UNIX sur le descripteur sockfd int clientfd; /* socket descriptor */ struct sockaddr_in serveraddr; /* server address */ ... /* establish a connection with the server */ Connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr));
Communication réseau par socket: Server Echo int main(int argc, char **argv) { int listenfd, connfd, port, clientlen; struct sockaddr_in clientaddr; struct hostent *hp; char *haddrp; port = atoi(argv[1]); /* the server listens on a port passed on the command line */ listenfd = open_listenfd(port); while (1) { clientlen = sizeof(clientaddr); connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET); haddrp = inet_ntoa(clientaddr.sin_addr); printf("server connected to %s (%s)\n", hp->h_name, haddrp); echo(connfd); Close(connfd); }
Communication réseau par socket: Server Echo open_listenfd() int open_listenfd(int port) { int listenfd; int optval; struct sockaddr_in serveraddr; /* create a socket descriptor */ listenfd = Socket(AF_INET, SOCK_STREAM, 0); /* eliminates "Address already in use" error from bind. */ optval = 1; Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); ... (more)
Communication réseau par socket: Server Echo open_listenfd()suite ... /* listenfd will be an endpoint for all requests to port on any IP address for this host */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)port); Bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)); /* make it a listening socket ready to accept connection requests */ Listen(listenfd, LISTENQ); return listenfd; }
Communication réseau par socket: Server Echo open_listenfd() (socket) socket() crée un descripteur de socket AF_INET: indique que le socket est associé à un protocole Internet SOCK_STREAM: sélectionne une connexion à flot d’octets fiable int listenfd; /* listening socket descriptor */ listenfd = Socket(AF_INET, SOCK_STREAM, 0);
Communication réseau par socket: Server Echo open_listenfd() (setsockopt) Le socket peut avoir des attributs Truc permettant de redémarrer le serveur immédiatement après l’avoir arrêté: Sinon, il faut attendre 15 secs Élimine l’erreur “Address already in use” du bind() /* eliminates "Address already in use" error from bind. */ optval = 1; Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
Communication réseau par socket: Server Echo open_listenfd() (init Communication réseau par socket: Server Echo open_listenfd() (init. adresse du socket) Initialisation du socket avec l’adresse Internet du serveur (adresse IP et port) L’adresse IP et le port sont stockés en ordre réseau (big-endian) htonl() convertir des longs du format hôte au format réseau htons() convertir des shorts du format hôte au format réseau struct sockaddr_in serveraddr; /* server's socket addr */ /* listenfd will be an endpoint for all requests to port on any IP address for this host */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)port);
Communication réseau par socket: Server Echo open_listenfd() (bind) bind() associe le socket avec l’adresse correspondante du serveur int listenfd; /* listening socket */ struct sockaddr_in serveraddr; /* server’s socket addr */ /* listenfd will be an endpoint for all requests to port on any IP address for this host */ Bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr));
Communication réseau par socket: Server Echo open_listenfd()(listen) listen() indique que le socket peut accepter des requêtes de connexions (connect) de clients int listenfd; /* listening socket */ /* make listenf it a server-side listening socket ready to accept connection requests from clients */ Listen(listenfd, LISTENQ);
Communication réseau par socket: Server Echo main loop Le serveur boucle sans fin, en attente de requêtes de connexion, lisant l’input du client, et faisant un écho au client main() { /* create and configure the listening socket */ while(1) { /* Accept(): wait for a connection request */ /* echo(): read and echo input line from client */ /* Close(): close the connection */ }
Communication réseau par socket: Server Echo accept() accept() se met en attente de requêtes de connexions accept() retourne un descripteur de socket connecté (connfd) avec les mêmes propriétés que le descripteur listening (listenfd) Retourne quand la connexion entre le client et le serveur est complète Toute les I/O avec le client sont faites via le socket connecté accept()crée aussi l’adresse du client int listenfd; /* listening descriptor */ int connfd; /* connected descriptor */ struct sockaddr_in clientaddr; int clientlen; clientlen = sizeof(clientaddr); connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
Illustration du fonctionnement du accept() listenfd(3) 1. Server blocks in accept, waiting for connection request on listening descriptor listenfd. client server clientfd connection request listenfd(3) client server 2. Client makes connection request by calling and blocking in connect. clientfd listenfd(3) 3. Server returns connfd from accept. Client returns from connect. Connection is now established between clientfd and connfd. client server clientfd connfd(4)
Le serveur peut déterminer le nom de domaine et l’adresse IP du client Communication réseau par socket: Server Echo (Identification du client) Le serveur peut déterminer le nom de domaine et l’adresse IP du client struct hostent *hp; /* pointer to DNS host entry */ char *haddrp; /* pointer to dotted decimal string */ hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET); haddrp = inet_ntoa(clientaddr.sin_addr); printf("server connected to %s (%s)\n", hp->h_name, haddrp);
Communication réseau par socket: Server Echo (echo()) Le serveur utilise les I/O Unix pour lire et faire écho de lignes de texte tant que un EOF (end-of-file) n’est pas rencontré EOF est causé par le client qui appel la fonction close(clientfd) NOTE: EOF est une condition, pas un octet de donnée void echo(int connfd) { size_t n; char buf[MAXLINE]; while((n = Readline(connfd, buf, MAXLINE)) != 0) { printf("server received %d bytes\n", n); Writen(connfd, buf, n); }
Communication réseau par socket: Exécuter l’application Écho client-serveur bass> echoserver 5000 server established connection with KITTYHAWK.CMCL (128.2.194.242) server received 4 bytes: 123 server received 7 bytes: 456789 ... kittyhawk> echoclient bass 5000 Please enter msg: 123 Echo from server: 123 Please enter msg: 456789 Echo from server: 456789 kittyhawk>
Autre implantation (Johnson) Fonctions utilitaires (Voir sockutil.c) copyData(): Permet la lecture de données à partir d’un descripteur de fichier et l’écriture sur un autre descripteur tant que des données sont disponibles en lecture die(): Permet de terminer le programme
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Création: L’appel système socket() retourne un descripteur de fichier pour un socket non initialisé Le socket est associé à un protocole particulier lors de la création mais n’est pas connecté à rien, donc aucune lecture ou écriture ne peut être effectuée avec ce socket Comme avec l’appel open(), socket() retourne une valeur négative si une erreur d’ouverture d’un socket survient ou une valeur supérieure ou égale à 0 correspondant au descripteur de fichier associé au socket
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Création #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: Permet de spécifier la famille du protocole utilisé PF_UNIX (UNIX domain) PF_INET (TCP/IP) type: Permet de spécifier si le protocole est paquet-orienté ou flot-orienté SOCK_STREAM (ex: TCP) SOCK_DGRAM (ex: UDP) protocol: Permet de spécifier quel protocole choisir. Avec la valeur 0, le noyau utilise alors le protocole par défaut correspondant au type et la famille spécifiés
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Attacher une adresse: L’appel système bind() permet d’indiquer au système quelle adresse locale utiliser pour un socket Les processus serveurs et clients même si ils ont des tâches différentes doivent définir une adresse, qui associée à un socket devient une terminaison locale Serveur: Création des sockets, préparation des sockets pour des connexions, attendre une connexion Client: Création d’un socket, indique au système à quelle adresse il veut se connecter, tenter d’établir une connexion
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Attacher une adresse #include <sys/socket.h> int bind(int sock, struct sockaddr * my_addr, int addrlen); Le premier argument représente un descripteur de fichier correspondant à un socket. Le second paramètre représente l’adresse de la terminaison locale
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Attendre une connexion: Après avoir créer un socket, un serveur attache ce socket à une adresse locale sur laquelle il pourra éventuellement écouter. Après avoir attacher une adresse à un socket, un processus serveur peut indiquer au système qu’il est disposé à laisser d’autres processus établir une connexion à ce socket et ce par l’appel système listen() Avant d’établir une connexion, un serveur doit d’abord accepter la connexion par un appel système accept()
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Attendre une connexion #include <sys/socket.h> int listen(int sock, int backlog); int accept(int sock, struct sockaddr *addr, int *addrlen); backlog: permet de spécifier le nombre (généralement 5) de connexions possibles sur le socket sock Les connexions réseaux ne sont établies que lorsque le serveur a accepté ces connexions (accept()), les connexions sont en mode attente listen() retourne 0 sur une réussite accept() permet de sortir une connexion de son mode d’attente et d’établir cette connexion. La nouvelle connexion est associée à un nouveau descripteur de fichier retourné par accept(). Le nouveau descripteur hérite des attributs du socket sur lequel écoutait le serveur
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Attendre une connexion #include <sys/socket.h> int listen(int sock, int backlog); int accept(int sock, struct sockaddr *addr, int *addrlen); Les champs addr et addrlen pointent sur des données fournit par le noyau. addr correspond à l’adresse du client représentant l’autre extrémité de la connexion accept() retourne un nouveau descripteur de fichier ou une valeur négative si un problème survient
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Connexion à un serveur: Comme un serveur, un client peut faire un bind() immédiatement après avoir créer un socket. Généralement, le client n’a pas besoin de l’adresse locale donc le bind() peut être laissé au noyau Le client veut plutôt se connecter à un serveur #include <sys/socket.h> int connect(int sock, struct sockaddr * servaddr, int addrlen); Le premier argument correspond au socket sur lequel s’établit la connexion et le second l’adresse du socket éloigné
Autre implantation: Concepts et opérations de base Opérations de base sur les sockets Connexion à un serveur
Autre implantation: IPC par socket Les sockets du domaine UNIX ne permettent de connecter des sockets que sur la même machine Ce type de socket constitue par contre un mécanisme d’IPC flexible Dans ce cas, ces sockets sont attachés à des adresses qui sont des noms de fichier, ayant donc une entrée dans le système de fichiers Avec UNIX, une interface de transfert de données par flot (stream) est offerte et ressemble aux tubes nommés mais ne sont pas identiques
Autre implantation: IPC par socket Avec les tubes nommés, chaque processus ayant ouvert la FIFO peut lire un message provenant des autres processus Les socket d’UNIX, sont orientée-connexion, chaque connexion à un socket résulte en un nouveau canal de communication. Le serveur, qui peut gérer plusieurs connexions simultanées, détient un descripteur de fichier pour chacune d’elles Des services LINUX, tel que le système X WINDOW fonctionne avec ce type d’IPC
Autre implantation: IPC par socket Adresses du domaine UNIX Ces adresses sont des entrées (nom de fichier) dans le système de fichiers Lorsque le fichier n’existe pas déjà, il est créé et sera associé au type socket par l’appel système bind() bind() retourne le code d’erreur EADDRINUSE si le nom de fichier fournit avec l’adresse correspond à un fichier (ou socket) déjà ouvert bind() initialise les droits d’accès des fichiers socket à 0666 Pour permettre la connexion (connect()) à un socket, un processus doit posséder les droits d’accès en lecture et écriture et en exécution sur les répertoires traversés dans le nom de fichier (pathname)
Autre implantation: IPC par socket Adresses du domaine UNIX #include <sys/socket.h> #include <sys/un.h> struct sockaddr_un { unsigned short sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ } UNIX_PATH_MAX: Initialiser à 108 sun_family doit contenir AF_UNIX pour indiquer qu’une adresse UNIX est contenue dans le structure sun_path contient le chemin d’accès (nom de fichier) La longueur de ce type d’adresse est le nombre de caractères du pathname et du champ sun_family
Autre implantation: IPC par socket Attente d’une connexion (Voir userver.c) L’écoute d’une connexion par un serveur requiert les procédures suivantes: Création d’un socket bind() d’une adresse au socket créé Indiquer au système d’écouter en attente d’une connexion sur ce socket (listen()) Accepter (accept()) une connexion éventuelle userver.c implémente un serveur qui accepte une connexion à la fois avec un socket UNIX (fichier sample-socket sur le répertoire courant) et fait la lecture de toutes les données disponibles sur ce socket et les affichent sur stdout Ce serveur est itératif puisqu’il ne traite qu’une connexion à la fois. Une version concurrente permettrait de gérer plusieurs clients à la fois
Autre implantation IPC par socket Attente d’une connexion (Voir userver.c) L’appel système unlink() appelé avant le bind() permet au programme d’être exécuté plusieurs fois sans avoir à effacer le fichier socket Ex: unlink( '' ./sample-socket '' ); Le pointeur sur la structure struct sockaddr_un subit une conversion de type (typecast) au niveau des appels système bind() et accept() et est transformée en un pointeur sur la structure générique struct sockaddr * bind(sock, (struct sockaddr *) &address, addrlength);
Autre implantation: IPC par socket Connexion à un serveur (Voir uclient.c) La connexion à un serveur, consiste à créer un socket (client) et se connecter (connect()) au serveur à une adresse désirée uclient.c se connecte au même socket du programme userver.c et copie son stdin vers le serveur Le programme client est différent du programme serveur au niveau de la séquence bind(), listen(), accept() du serveur qui est remplacée par un simple appel système connect()
Autre implantation: Communication réseau par socket Connexion réseau avec TCP/IP L’utilisation principale des sockets réside dans la communication de machines distantes Le protocole TCP/IP est utilisé sur l’Internet, le plus grand ensemble de machines connectées réseau du monde LINUX offre une implémentation du protocole TCP/IP lui permettant d’agir comme serveur et client TCP/IP Ordonnancement des octets Puisque le protocole TCP/IP utilise des quantités multioctets (ex: short int => 2 octets), il est alors convenu que ces quantités soient transmises selon un ordre prédéterminé Un ordonnancement big-endian (octets plus significatifs en premier) des octets transmis sur le réseau est alors préconisé
Autre implantation: Communication réseau par socket Ordonnancement des octets Quatre fonctions permettent la conversion entre l’ordre des octets de la machine hôte et l’ordre des octets réseau #include <netinet/in.h> unsigned int htonl(unsigned int hostlong); unsigned short htons(unsigned short hostshort); unsigned int ntohl(unsigned int netlong); unsigned short ntohs(unsigned short netshort); htonl() et htons() convertissent des quantités long (32 bits) et short, respectivement, de l’ordre de l’hôte vers l’ordre du réseau ntohl() et ntohs() convertissent des quantités long et short, respectivement, de l’ordre du réseau vers l’ordre de l’hôte
Autre implantation: Communication réseau par socket Adressage réseau IPv4 Les connexions IPv4 correspondent à un quadruplet (local host, local port, remote host, remote port) Les champs local et remote host, représentent les adresses IP des machines connectées Les adresses IP sont des quantités de 32 bits (4 octets) et sont uniques au travers du réseau de machines connectées Ces adresses sont écrites en notation point-décimale: aaa.bbb.ccc.ddd, ex: 132.209.3.131 Pour différentier plusieurs applications TCP/IP concurrentes, il faut aussi fournir un numéro de port Le numéro de port est une quantité de 16 bits qui identifie de façon unique la terminaison d’une connexion sur un hôte La combinaison de l’adresse IP et du numéro de port identifie une terminaison n’importe où sur un réseau TCP/IP Deux terminaisons d’une connexion forment une connexion TCP, deux combinaisons numéro IP/numéro de port identifient de façon unique une connexion TCP/IP sur un réseau Les numéros de ports disponibles en mode user sont dans l’intervalle [1025, 65535]
Autre implantation: Communication réseau par socket Adresses socket réseau IP Les adresses IP sont stockées dans la structure sockaddr_in #include <sys/socket.h> #include <netinet/in.h> struct sockaddr_in { short int sin_family; /* AF_INET */ unsigned short int sin_port; /* port number */ struct in_addr sin_addr; /* IP address */ } Le premier argument AF_INET indique la présence d’une adresse IP Les autres paramètres représentent le numéro de port (donné en ordre réseau) et l’adresse IP (donnée en format binaire)
Autre implantation: Communication réseau par socket Manipulation des adresses IP Certaines fonctions permettent de convertir une adresse IP entre sa forme point-décimale et sa représentation binaire (struct in_addr) #include <netinet/in.h> #include <arpa/inet.h> char * inet_ntoa(struct in_addr address); inet_ntoa() prend en argument une adresse IP sous forme binaire et retourne un pointeur sur une chaîne de caractère sous forme point-décimale
Autre implantation: Communication réseau par socket Manipulation des adresses IP #include <netinet/in.h> #include <arpa/inet.h> int inet_aton(const char * ddaddress, struct in_addr * address); inet_aton() prend en argument une adresse IP sous forme point-décimale, fait pointer address sur une adresse IP sous forme binaire et retourne 0 si une erreur survient
Autre implantation: Communication réseau par socket Attente de connexions TCP (Voir tserveur.c) L’attente de connexions TCP est similaire à l’attente de connexions du domaine UNIX. Les différences résident dans le protocole et la famille d’adresses L’adresse IP attachée au socket spécifie un numéro de port (ex: 1234) mais pas d’adresse IP comme telle (voir fonction memset() qui initialise le champ sin_addr à 0). Le noyau est alors libre d’assigner l’adresse IP qu’il veut L’appel système setsockopt() permet d’établir des options sur les sockets et protocoles Dans le cas du serveur décrit dans le programme tserveur.c, setsockopt() permet la réutilisation rapide d’une adresse IP
Autre implantation: Communication réseau par socket Attente de connexions TCP (Voir tserveur.c) #include <sys/socket.h> int setsockopt(int sock, int level, int option, const void *valptr, int vallength); Le premier argument sock est un socket pour lequel nous établissons les options level spécifie le type d’options établit. SOL_SOCKET indique que l’option de socket générique est utilisée option spécifie l’option à changer (ex: SO_REUSEADDR) valptr est un pointeur vers la nouvelle valeur de l’option (ex: 1 active l’option, 0 désactive le mode reuse) vallength est la dimension de valptr
Autre implantation: Communication réseau par socket Client TCP Les clients TCP sont aussi similaires aux clients du domaine UNIX Un socket est créé et est immédiatement connecté (connect()) au serveur Dans le cas du client TCP il faut initialiser la structure sockaddr_in avant l’appel à connect() Pour initialiser le champ sin_addr de la structure sockaddr_in vous pouvez utiliser la fonction inet_aton() dont le paramètre ddaddress est donné sous forme point-décimale (ex: 132.209.3.131) et dont le paramètre address qui pointe sur une structure in_addr peut servir à initialiser le champ sin_addr inet_aton() peut alors permettre le remplacement de la fonction memcpy() dans tclient.c