Vous êtes sur la page 1sur 42

Programmations des Sockets

Benmoussa Yahia
Université M’hamed Bougara de Boumerdès
Yahia.benm@gmail.com
Objectifs

„ Différencier entre les modes de transport orientés


connexion et non-orientés connexion
„ Comprendre l’utilité des numéros de ports utilisés
dans TCP & UDP
„ Utiliser les sockets pour écrire des applications
réseaux au dessus de la pile de protocoles fournie
par le système d’exploitation
„ Comprendre la difficulté d’écrire des applications
réseaux en utilisant les sockets

2
TCP/IP

„ Une suite de protocoles ayant comme objectif de


fournir un outil universel d’interconnexion à travers
des réseaux physiques hétérogènes
„ TCP & IP sont les protocole les plus importants mais
existent d’autre protocoles dans la suite TCP/IP :
– UDP : protocole de transport
– FTP, TELNET, SSH, SMTP, HTTP, …etc :
protocoles de la couche application.

3
TCP/IP & le modèle OSI

ftp, telnet, ssh,


Application smtp, http, …etc
Présentation
Session TCP/IP
Transport TCP/UDP
Réseau IP
Liaison
Physique

4
Les protocoles de transport TCP et UDP

„ Protocole de transport point-à-point


„ Permettent le transport de données entre
applications distantes
„ Dans une communication point-à-point, plusieurs
application de chaque coté échangent des données
simultanément
„ La séparation entre les données des différentes
applications est garantie par l’utilisation de numéro
de ports distincts

5
Les protocoles de transport TCP et UDP

Pour transférer des fichiers, j’utilise FTP sur le port 21


Pour me connecter à distance, j’utilise SSH sur le port 22
Pour envoyer des e-mails, j’utilise SMTP sur le port 25
Pour consulter le WEB, j’utilise HTTP sur le port 80

Vers serveur FTP

Vers serveur SSH

Vers serveur SMTP

Vers serveur HTTP

TCP/UDP
TCP/UDP

IP
IP

6
Les protocoles de transport TCP et UDP

Numéro de port dans un segment TCP


7
Les protocoles de transport TCP et UDP

Numéro de port dans un segment UDP


8
TCP vs UDP

„ TCP
– Garantit la transmission des données
– Garantit l’ordre de transmission
„ UDP
– Ne garantit la transmission des données
– Ne garantit l’ordre de transmission

9
Mise en œuvre des applications réseaux

„ Implémentation des applications réseaux au dessus


de systèmes d’exploitation réseaux
„ Les fonctionnalités réseaux sont implémenté au
niveau d’une pile de protocoles
„ L‘accès à la pile de protocole se fait via une API

10
Mise en œuvre des applications réseaux

Application Application Application


réseau réseau réseau

Système Système Système


API Système d’exploitation d’exploitation d’exploitation
Pile de
protocoles

Réseau de communication
11
Les Sockets

„ Interface de programmation réseau générique


„ Introduite la première fois dans UNIX BSD 4.2
„ Dans Unix/Linux, une socket est comme un
descripteur de fichier sur lequel on effectue des
opérations de Lecture/Ecriture classiques
„ Conçues pour utiliser différentes familles de
protocoles réseaux et différents types de protocoles
de transport

12
Familles de protocoles

„ AF_UNIX, AF_LOCAL : communication


interprocessus local
„ AF_INET : Communication via ipv4
„ AF_INET6 : Communication via ipv6
„ AF_IPX : Communication via IPX de Novell
„ AF_APPLTALK ...

13
Familles de protocoles

„ AF_UNIX, AF_LOCAL : communication


interprocessus local
„ AF_INET : Communication via ipv4
„ AF_INET6 : Communication via ipv6
„ AF_IPX : Communication via IPX de Novell
„ AF_APPLTALK ...

14
Type de sockets

„ SOCK_STREAM
– Mode de transport orienté connexion
– Le choix du type STREAM force l’utilisation de
TCP
„ SOCK_DGRAM
– Mode de transport non-orienté connexion
– Le choix du type DGRAM force l’utilisation de
UDP

15
Création d’une Socket (1)

„ Création d’un descripteur pour la socket


„ int socket (int sa_familly, int type, int protocol);
– sa_familly : AF_UNIX, AF_INET, …
– type : SOCK_STREAM, SOCK_DGRAM, …
– protocole : mis à 0 pour un choix automatique
– Valeur de retour : descripteur de la socket si créé
sans erreur sinon -1

16
Initialisation de l’adresse d’une socket
AF_INET (2)
„ L’adresse d’une socket dépend de la famille de Protocol
utilisé. Dans le cas AF_INET, c’est une structure
sockaddr_in (voir man 7 ip)
„ struct sockaddr_in {
sa_family_t sin_family; /* famille : AF_INET */
in_port_t sin_port; /* N° port au format réseau */
struct in_addr sin_addr; /* l’@ IP au format réseau */
};
struct in_addr { in_addr_t s_addr; };

17
Initialisation de l’adresse d’une socket
AF_INET (2)
struct sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_port=htons(21); // FTP
sa.sin_addr.s_addr=htonl(0x7f000001); //127.0.0.1

Si NUMERO_PORT=0 alors le système choisit un port aléatoire.


Si ADRESSE_IP= INADDR_ANY alors la socket écoute sur toutes
adresse disponibles dans le système
Si ADRESSE_IP= INADDR_LOOPBACK alors la socket écoute sur
l’adresse de bouclage.

18
Initialisation de l’adresse d’une socket
AF_INET
„ Représentation réseau vs représentions hôte (Big andian &
Little andian)
– Dans les CPU Intel, les entiers sont stockés en mémoire
en commençant par l’octet le moins significatif
– Dans les CPU Motorola, les entiers sont stockés en
mémoire en commençant par l’octet le plus significatif
„ Pour lever toute ambiguïté, on utilise un ensemble to fonction
de conversion (voir man byteorder)
– htons() host to network short
– htonl() host to network long
– ntohs() network to host short
– stohl() short network to host long

19
Initialisation de l’adresse d’une socket
AF_INET (2)

Bits plus significatifs Bits moins significatifs

192.168.196.1=11000000.10101000.11000100.00000001

11000000 00000001
10101000 11000100
11000100 10101000
00000001 11000000

CPU Motorola CPU Intel

20
Initialisation de l’adresse d’une socket
AF_INET (2)

Bits plus significatifs Bits moins significatifs

192.168.196.1=11000000.10101000.11000100.00000001

11000000 00000001


10101000 11000100
11000100 10101000
00000001 11000000

CPU Motorola CPU Intel

21
Initialisation de l’adresse d’une socket
AF_INET (2)
„ Dans le cas ou l’adresse IP est disponible sous
format chaine de caractères, on utilise inet_addr()
„ inet_addr() permet de convertir une adresse IP au
format chaine de caractère au format binaire réseau
(Big andian)
„ La fonction qui convertit une adresse du format
réseau en un chaine de caractère est inet_ntop()

22
Communication Client/Serveur

„ Chacun des client et du serveur doivent créer une


socket
„ Le serveur initialise l’adresse de la socket sur
laquelle il va écouter les requêtes entrantes et le
client initialise l’adresse de la socket du serveur qu’il
va contacter
„ Le scénario de communication dépend par la suite
du mode de transport de données (orienté
connection/ non-orienté connexion)

23
Client/Serveur en mode connecté

1- Création s1=socket

socket() 1- Création
2- Attachement bind()

3- Attente de connexions listen() connect() 2- Initiation de connexion

4- Accepter une connexion s2=accept() write() 3- Envoyer des données

5- Lire des données Read()


read() 4- Lire des données

6- Envoyer des données Write()


Close() 5- Fermer la socket
4- Fermer la socket Close()
24
Client/Serveur en mode non-connecté

1- Création s1=socket

socket()
2- Attachement bind()
sendto()

3- Attente de messages recvefrom() recvefrom()

Close()
3- Envoie de messages sendto()

4- Fermeture de la socket Close()


25
Attachement d’une socket à une adresse (2)

„ Opération effectué coté serveur (dans les deux


modes)
„ int bind(int sfd, struct sockaddr *sd, socklen_t
addrlen);
„ bind retourne 0 si l’attachement de la socket est
réussie sinon elle retourne -1

26
Création d’une file d’attente de connections
(3)
„ Opération effectuée du coté serveur en mode
connecté seulement
„ Cette opération définit la taille de la files d’attente
„ int listen(int s, int taille_file_attente);

27
Accepter les connexion (4)

„ Opération effectuée du coté serveur en mode


connecté seulement
„ Cette opération retire la connexion de la file
d’attente et récupère l’adresse de la socket paire
(du client)
„ int accept(int sock, struct sockaddr *adresse,
socklen_t *longueur);

28
Initiation d’une connexion par un client (5)

„ Opération effectuée du coté client en mode


connecté seulement
„ int connect(int sockfd, struct sockaddr *serv_addr,
socklen_t addrlen);

29
Envoie/Réception de données (6)

„ read() / write() reste valide


„ recv() / sendto() sont plus adapté au sockets
„ recvfrom() / sendto() sont utilisé en mode non-
connecté
„ Voir les pages de manuels pour plus de détails

30
Ou utiliser quelle fonction ?

Etablissement
de la
Mode de connexion Envoie Réception
connexion

Serveur connecté bind() send() recv()


listen() sendto() recvfrom()
accept() write() read()
Client connecté connect() send() recv()
sendto() recvfrom()
write() read()
Serveur non-connecté bind() sendto() recvfrom()

Client non-connecté N/A sendto() recvfrom()

31
„ /* Serveur TCP */

1. #define MAX_SIZE 128


2. int main () {
3. int dfs_serveur, dfs_client, long_adr_serveur, long_adr_client;
4. int struct sockaddr_in adresse_serveur , adresse_client;
5. char buf[MAX_SIZE];

6. dfs_serveur = socket (AF_INET, SOCK_STREAM, 0); // Création de la socket

7. adresse_serveur.sin_family = AF_INET; // Initialisation


8. adresse_serveur.sin_addr.s_addr=inet_addr ("127.0.0.1 ") ; // de l'adresse
9. adresse_serveur.sin_port = htons(1234); // de la socket
10. long_adr_serveur = sizeof (adresse_serveur); // Association de l'adresse
11. bind (dfs_serveur, (struct sockaddr *) &adresse_serveur,long_adr_serveur); // à la socket
12. listen (dfs_serveur, 5); // Création d'une file d'attente de connexions pour les clients.
13. while (1)
14. {
15. // Accepter les connections
16. dfs_client = accept (dfs_serveur, (struct sockaddr *) &adresse_client, &long_adr_client);
17. read (dfs_client, buf, MAX_SIZE); // Lecture des données envoyées par le client
18. printf ("%s\n", buf);
19. close (dfs_client);
20. }
21. }

32
„ /* Client TCP */
1. int main ()
2. {
3. int dfs_serveur;
4. int len;
5. struct sockaddr_in adresse_serveur;
6. int result;
7. sin_addr.s_addr
8. dfs_serveur = socket (AF_INET, SOCK_STREAM, 0); // Création de la socket du client
9. adresse_serveur.sin_family = AF_INET; // initialisation
10. adresse_serveur.sin_addr.s_addr = inet_addr ("127.0.0.1"); // de l'adresse
11. adresse_serveur.sin_port = htons (1234); // du serveur
12. len = sizeof (adresse_serveur);
13. result = connect (dfs_serveur, (struct sockaddr *) &adresse_serveur, len); // Connection au serveur
14. write (dfs_serveur, "Hello word", 10); // Envoie de message au serveur
15. close (dfs_serveur);
16. exit (0);
17. }
18.

33
Gestion des connexions Clients

„ Un serveur doit gérer les requêtes de plusieurs


clients
„ Plusieurs techniques :
– Serveur itératif
– Serveur multiprocessus
– Serveur multithread

34
Gestion des connexions Clients

„ Serveur itératif
– Simple
Mais
– Gestion séquentielle des clients (non parallèle)
– Le serveur est souvent en attente bloquante
– L’attente non bloquante avec
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
utilise excessivement la CPU

35
Gestion des connexions Clients

„ Serveur multiprocessus

36
„ /* Serveur TCP */

1. #define MAX_SIZE 128


2. int main () {
3. int dfs_serveur, dfs_client, long_adr_serveur, long_adr_client;
4. int struct sockaddr_in adresse_serveur , adresse_client;
5. char buf[MAX_SIZE];

6. dfs_serveur = socket (AF_INET, SOCK_STREAM, 0); // Création de la socket

7. adresse_serveur.sin_family = AF_INET; // Initialisation


8. adresse_serveur.sin_addr.s_addr=inet_addr ("127.0.0.1 ") ; // de l'adresse
9. adresse_serveur.sin_port = htons(1234); // de la socket
10. long_adr_serveur = sizeof (adresse_serveur); // Association de l'adresse
11. bind (dfs_serveur, (struct sockaddr *) &adresse_serveur,long_adr_serveur); // à la socket
12. listen (dfs_serveur, 5); // Création d'une file d'attente de connexions pour les clients.
13. while (1)
14. {
15. / Accepter les connections
16. dfs_client = accept (dfs_serveur, (struct sockaddr *) &adresse_client, &long_adr_client);
if ( (childpid = fork() == 0) { /* Processus fils */
17. close((dfs_serveur); /* close listening socket */
18. read (dfs_client, buf, MAX_SIZE);
19. exit 0);
20. }
21. close(dfs_client); /* Le processus parent ferme la socket associé au client */
22. }}}

37
Gestion des connexions Clients

„ Serveur multiprocessus
– Domaine d’exécution séparé pour chaque client
– Sécurité, Robustesse, Programmation facile
Mais
– Le fork() est couteux (Temps et Mémoire)
– Nécessite des mécanisme IPC pour faire
communiquer les différent processus serveurs

38
Gestion des connexions Clients

„ Serveur Multithread

39
„ /* Serveur TCP */
void * server_thread(void *arg) {
1. #define MAX_SIZE 128 read ((int)arg, buf, MAX_SIZE);
2. int main () { printf ("%s\n", buf);
3. int dfs_serveur, dfs_client, long_adr_serveur, long_adr_client; close ((int) arg);
4. int struct sockaddr_in adresse_serveur , adresse_client; /*
5. char buf[MAX_SIZE]; Il faut pas oublier de gérer les
accès conçurent à la variable buf
6. dfs_serveur = socket (AF_INET, SOCK_STREAM, 0); */
}
7. adresse_serveur.sin_family = AF_INET;
8. adresse_serveur.sin_addr.s_addr=inet_addr ("127.0.0.1 ") ;
9. adresse_serveur.sin_port = htons(1234);
10. long_adr_serveur = sizeof (adresse_serveur);
11. bind (dfs_serveur, (struct sockaddr *) &adresse_serveur,long_adr_serveur);
12. listen (dfs_serveur, 5); // Création d'une file d'attente de connexions pour les clients.
13. while (1)
14. {
15. long_adr_client = sizeof (adresse_client);
16. dfs_client = accept (dfs_serveur, (struct sockaddr *) &adresse_client, &long_adr_client);

17. pthread_create(NULL, NULL, &server_thread, (void *) dfs_client):


}
18. }

40
Gestion des connexions Clients

„ Serveur Multithread
– Performance
– Supporte un nombre important de clients
– Communication facile à l’aide de variables
Mais …
– Nécessité d’une gestion explicite de l’exclusion
mutuelle entre les threads.
– La défection d’un thread entraine la défection
des autre.

41
Références

„ Unix Network Programming Vol.1. R. Stevens


„ Beej's Guide to Network Programming Using
Internet Sockets. www.beej.us
„ Beginning Linux Programming. Neil Matthew,
Richard Stones.
„ TCP/IP Tutorial and Technical Overview
http://www.redbooks.ibm.com/

42

Vous aimerez peut-être aussi