programmation syst`eme et réseau sous unix

95
Programmation Syst` eme et R´ eseau sous Unix M. Billaud [email protected] 4 f´ evrier 2012 esum´ e Ce document est un support de cours pour les enseignements de Syst` eme et de R´ eseau. Il pr´ esente quelques appels syst` eme Unix n´ ecessaires ` a la r´ ealisation d’applications communicantes. Une premi` ere partie rappelle les notions de base indispensables ` a la programmation en C : printf, scanf, exit, communication avec l’environnement, allocation dynamique, gestion des erreurs. Ensuite on pr´ esente de fa¸con plus d´ etaill´ ees les entr´ ees-sorties g´ en´ erales d’UNIX : fichiers, tuyaux, r´ epertoires etc., ainsi que la communication inter-processus par le m´ ecanisme des sockets locaux par flots et datagrammes. Viennent ensuite les processus et les signaux. Les m´ ecanismes associ´ es aux threads Posix sont d´ etaill´ es : s´ emaphores, verrous, conditions. Une autre partie d´ ecrit les IPC, que l’on trouve plus couramment sur les divers UNIX : segments partag´ es s´ emaphores et files de messages. La derni` ere partie aborde la communication r´ eseau par l’interface des sockets, et montre des exemples d’applications client-serveur avec TCP et UDP. Table des mati` eres 1 Avant-Propos 3 1.1 Objectifs .......................................... 3 1.2 Copyright ......................................... 4 1.3 Obtenir la derni` ere version ................................ 4 2 Rappels divers 5 2.1 printf()/scanf() .................................... 5 2.2 sprintf()/sscanf() .................................. 5 2.3 system() ......................................... 5 3 Communication avec l’environnement 6 3.1 Param` etres de main(...) ................................ 6 3.2 Variables d’environnement ................................. 8 3.3 exit() : Fin de programme ................................ 9 4 Erreurs 9 4.1 errno, perror() ..................................... 9 4.2 Traitement des erreurs, branchements non locaux .................... 10 5 Allocation dynamique 11 6 Manipulation des fichiers, op´ erations de haut niveau 13 6.1 Flots standards ...................................... 13 6.2 Op´ erations sur les flots .................................. 14 6.3 Positionnement ...................................... 16 6.4 Divers ........................................... 16 1

Upload: duongnguyet

Post on 05-Jan-2017

229 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Programmation Syst`eme et Réseau sous Unix

Programmation Systeme et Reseau sous Unix

M. Billaud [email protected]

4 fevrier 2012

Resume

Ce document est un support de cours pour les enseignements de Systeme et de Reseau. Ilpresente quelques appels systeme Unix necessaires a la realisation d’applications communicantes.Une premiere partie rappelle les notions de base indispensables a la programmation en C : printf,scanf, exit, communication avec l’environnement, allocation dynamique, gestion des erreurs.

Ensuite on presente de facon plus detaillees les entrees-sorties generales d’UNIX : fichiers,tuyaux, repertoires etc., ainsi que la communication inter-processus par le mecanisme des socketslocaux par flots et datagrammes.

Viennent ensuite les processus et les signaux. Les mecanismes associes aux threads Posixsont detailles : semaphores, verrous, conditions. Une autre partie decrit les IPC, que l’on trouveplus couramment sur les divers UNIX : segments partages semaphores et files de messages. Laderniere partie aborde la communication reseau par l’interface des sockets, et montre des exemplesd’applications client-serveur avec TCP et UDP.

Table des matieres

1 Avant-Propos 31.1 Objectifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Copyright . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.3 Obtenir la derniere version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Rappels divers 52.1 printf()/scanf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 sprintf()/sscanf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 system() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Communication avec l’environnement 63.1 Parametres de main(...) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63.2 Variables d’environnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.3 exit() : Fin de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

4 Erreurs 94.1 errno, perror() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94.2 Traitement des erreurs, branchements non locaux . . . . . . . . . . . . . . . . . . . . 10

5 Allocation dynamique 11

6 Manipulation des fichiers, operations de haut niveau 136.1 Flots standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136.2 Operations sur les flots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146.3 Positionnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166.4 Divers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1

Page 2: Programmation Syst`eme et Réseau sous Unix

7 Manipulation des fichiers, operations de bas niveau 167.1 Ouverture, fermeture, lecture, ecriture . . . . . . . . . . . . . . . . . . . . . . . . . . 167.2 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187.3 Positionnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187.4 Verrouillage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187.5 Informations sur les fichiers/repertoires/... . . . . . . . . . . . . . . . . . . . . . . . . 197.6 Parcours de repertoires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207.7 Duplication de descripteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217.8 mmap() : fichiers ”mappes” en memoire . . . . . . . . . . . . . . . . . . . . . . . . . 22

8 Pipes et FIFOs 248.1 FIFOs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248.2 Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248.3 Pipes depuis/vers une commande . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

9 select() : attente de donnees 269.1 Attente de donnees provenant de plusieurs sources . . . . . . . . . . . . . . . . . . . . 269.2 Attente de donnees avec delai maximum . . . . . . . . . . . . . . . . . . . . . . . . . 28

10 Communication interprocessus par sockets locaux 3110.1 Creation d’un socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3110.2 Adresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3110.3 Communication par datagrammes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

10.3.1 La reception de datagrammes . . . . . . . . . . . . . . . . . . . . . . . . . . . 3210.3.2 Emission de datagrammes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3310.3.3 Emission et reception en mode connecte . . . . . . . . . . . . . . . . . . . . . 35

10.4 Communication par flots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3510.4.1 Architecture client-serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

10.5 socketpair() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

11 Processus 4611.1 fork(), wait() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4611.2 waitpid() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4811.3 exec() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4911.4 Numeros de processus : getpid(), getppid() . . . . . . . . . . . . . . . . . . . . . 5011.5 Programmation d’un demon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

12 Signaux 5212.1 signal() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5212.2 kill() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5312.3 alarm() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5312.4 pause() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

13 Les signaux Posix 5313.1 Manipulation des ensembles de signaux . . . . . . . . . . . . . . . . . . . . . . . . . . 5313.2 sigaction() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

14 Les processus legers (Posix 1003.1c) 5514.1 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5614.2 Verrous d’exclusion mutuelle (mutex) . . . . . . . . . . . . . . . . . . . . . . . . . . . 5614.3 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5714.4 Semaphores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5814.5 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

2

Page 3: Programmation Syst`eme et Réseau sous Unix

15 Communication entre processus (IPC System V) 5915.1 ftok() constitution d’une cle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5915.2 Memoires partagees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5915.3 Semaphores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6315.4 Files de messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

16 Communication par le reseau TCP-IP 6916.1 Sockets, addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6916.2 Remplissage d’une adresse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

16.2.1 Preparation d’une adresse distante . . . . . . . . . . . . . . . . . . . . . . . . 6916.2.2 Preparation d’une adresse locale . . . . . . . . . . . . . . . . . . . . . . . . . 7016.2.3 Examen d’une adresse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

16.3 Fermeture d’un socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7116.4 Communication par datagrammes (UDP) . . . . . . . . . . . . . . . . . . . . . . . . 71

16.4.1 Creation d’un socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7116.4.2 Connexion de sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7116.4.3 Envoi de datagrammes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7116.4.4 Reception de datagrammes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7116.4.5 Exemple UDP : serveur d’echo . . . . . . . . . . . . . . . . . . . . . . . . . . 72

16.5 Communication par flots de donnees (TCP) . . . . . . . . . . . . . . . . . . . . . . . 7616.5.1 Programmation des clients TCP . . . . . . . . . . . . . . . . . . . . . . . . . 7616.5.2 Exemple : client web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7616.5.3 Realiser un serveur TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

17 Exemples TCP : serveurs Web 7917.1 Serveur Web (avec processus) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

17.1.1 Principe et psedo-code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7917.1.2 Code du serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8017.1.3 Discussion de la solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

17.2 Serveur Web (avec threads) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8317.2.1 Principe et pseudo-code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8317.2.2 Code du serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8317.2.3 Discussion de la solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

17.3 Parties communes aux deux serveurs . . . . . . . . . . . . . . . . . . . . . . . . . . . 8717.3.1 Declarations et entetes de fonctions . . . . . . . . . . . . . . . . . . . . . . . 8717.3.2 Les fonctions orientees-reseau . . . . . . . . . . . . . . . . . . . . . . . . . . . 8717.3.3 Les fonction de dialogue avec le client . . . . . . . . . . . . . . . . . . . . . . 8917.3.4 Exercices, extensions... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9117.3.5 Transmission d’un descripteur . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

18 Documentation 95

1 Avant-Propos

1.1 Objectifs

Ce document presente quelques appels systeme utiles a la realisation d’application communicantessous UNIX.

Pour ecrire de telles applications il faut savoir faire communiquer de processus entre eux, que cesoit sur la meme machine ou sur des machines reliees en reseau (Internet par exemple).

Pour cela, on passe par des appels systemes pour demander au systeme d’exploitation d’effecter desactions : ouvrir des voies de communication, expedier des donnees, creer des processus etc. On parle

3

Page 4: Programmation Syst`eme et Réseau sous Unix

de programmation systeme lorsqu’on utilise explicitement ces appels sans passer par des bibliothequesou des modules de haut niveau qui les encapsulent pour en cacher la complexite (supposee). 1.

Les principaux appels systemes sont presentes ici, avec des exemples d’utilisation. 2

1.2 Copyright

(c) 1998-2012 Michel BillaudCe document peut etre reproduit en totalite ou en partie, sans frais, sous reserve des restrictions

suivantes :– cette note de copyright et de permission doit etre preservee dans toutes copies partielles ou

totales– toutes traductions ou travaux derives doivent etre approuves par l’auteur en le prevenant avant

leur distribution– si vous distribuez une partie de ce travail, des instructions pour obtenir la version complete

doivent egalement etre fournies– de courts extraits peuvent etre reproduits sans ces notes de permissions.L’auteur decline tout responsabilite vis-a-vis des dommages resultant de l’utilisation des informations

et des programmes qui figurent dans ce document.

1.3 Obtenir la derniere version

La derniere version de ce document peut etre obtenue depuis la page Web http://www.labri.

fr/~billaud

1. Sur le marche, on trouve par exemple des composants � serveur-TCP � tout faits pour tel ou tel langage deprogrammation

2. Attention, ce sont des illustrations des appels, pas des recommandations sur la bonne maniere de les employer. Enparticulier, les controles de securite sur les donnees sont tres sommaires.

4

Page 5: Programmation Syst`eme et Réseau sous Unix

2 Rappels divers

2.1 printf()/scanf()

i n t p r i n t f ( const char ∗ format , . . . ) ;i n t s c a n f ( const char ∗ format , . . . ) ;

Ces instructions font des ecritures et des lectures formattees sur les flots de sortie et d’entreestandard. Les specifications de format sont decrites dans la page de manuel printf(3).

2.2 sprintf()/sscanf()

i n t s p r i n t f ( char ∗ s t r , const char ∗ format , . . . ) ;i n t s s c a n f ( const char ∗ s t r , const char ∗ format , . . . ) ;

Similaires aux precedentes, mais les operations lisent ou ecrivent dans le tampon str.Remarque : la fonction sprintf() ne connait pas la taille du tampon str ; il y a donc un risque

de debordement. Il faut prevoir des tampons assez larges, ou (mieux) utiliser la fonction

#inc lude <s t d i o . h>i n t s n p r i n t f ( char ∗ s t r , s i z e t s i z e , const char ∗ format , . . . ) ;

de la bibliotheque GNU, qui permet d’indiquer une taille a ne pas depasser.

2.3 system()

#inc lude < s t d l i b . h>i n t system ( const char ∗ s t r i n g ) ;

permet de lancer une ligne de commande (shell) depuis un programme. L’entier retourne par system()est le code de retour fourni en parametre a exit() par la commande.

Exemple :

/∗∗ D i v e r s / e n v o i f i c h i e r . c∗∗ I l l u s t r a t i o n de system ( ) ;∗/

#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

#def ine TAILLE MAX COMMANDE 100#def ine TAILLE MAX ADRESSE 100#def ine TAILLE MAX NOMFICHIER 100

i n t main ( void ){

char d e s t i n a t a i r e [ TAILLE MAX ADRESSE ] ;char n o m f i c h i e r [ TAILLE MAX NOMFICHIER ] ;char commande [ TAILLE MAX COMMANDE ] ;i n t r e p o n s e ;

p r i n t f ( ”e−m a i l d e s t i n a t a i r e ?\n” ) ;s c a n f ( ”%s ” , d e s t i n a t a i r e ) ; /∗ dangereux ∗/p r i n t f ( ”nom du f i c h i e r a e n v o y e r ?\n” ) ;s c a n f ( ”%s ” , n o m f i c h i e r ) ; /∗ dangereux ∗/

5

Page 6: Programmation Syst`eme et Réseau sous Unix

s n p r i n t f ( commande , TAILLE MAX COMMANDE,” uuencode %s %s | m a i l %s ” ,n o m f i c h i e r , n o m f i c h i e r , d e s t i n a t a i r e ) ;

r e p o n s e = system ( commande ) ;i f ( r e p o n s e == EXIT SUCCESS ) {

p r i n t f ( ”OK\n” ) ;} e l s e {

p r i n t f ( ”La commande r e t o u r n e : %d\n” , r e p o n s e ) ;}return EXIT SUCCESS ;

}

3 Communication avec l’environnement

3.1 Parametres de main(...)

Le lancement d’un programme C provoque l’appel de sa fonction principale main(...) qui a 2parametres optionnels :

– argc : nombre de parametres sur la ligne de commande (y compris le nom de l’executablelui-meme) ;

– argv : tableau de chaınes contenant les parametres de la ligne de commande.Remarque : les noms argc, argv sont purement conventionnels.Exemple :

1/∗∗ D i v e r s § e n v . c∗/

5#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

i n t main ( i n t argc , char ∗ a r g v [ ] ){

10i n t k ;

p r i n t f ( ” Appel avec %d p a r a m e t r e s \n” , a r g c ) ;

f o r ( k=0; k<a r g c ; k++)15p r i n t f ( ” %d : %s \n” , k , a r g v [ k ] ) ;

return EXIT SUCCESS ;}

L’analyse des options d’une ligne de commande est facilite par l’emploi de getopt().

#inc lude <u n i s t d . h>

i n t g e t o p t ( i n t argc , char ∗const a r g v [ ] , const char ∗ o p t s t r i n g ) ;

extern char ∗ o p t a r g ;extern i n t opt ind , o p t e r r , o p t o p t ;

getopt() analyse le tableau de parametres argv a argc elements, en se basant sur la chaınede specification d’options optstring. Par exemple la chaıne "vhx:y:" declare 4 options, les deuxdernieres etant suivies d’un parametre.

6

Page 7: Programmation Syst`eme et Réseau sous Unix

A chaque etape, optarg retourne le nom de l’option (ou un point d’interrogation pour une optionnon reconnue), et fournit eventuellement dans optarg la valeur du parametre associe.

A la fin getopt retourne -1, et le tableau argv a ete rearrange pour que les parametressupplementaires soient stockes a partir de l’indice optind.

1/∗ D i v e r s / e s s a i−g e t o p t . c ∗/

#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

5#inc lude <u n i s t d . h>

i n t main ( i n t argc , char ∗ a r g v [ ] ){

char ∗ o p t a = NULL ;10i n t o p t x = 0 ;

i n t i n d e x ;char c ;

whi le ( ( c = g e t o p t ( argc , argv , ” hxa : ” ) ) != −1) {15switch ( c ) {

case ’ h ’ :p r i n t f ( ” Help : %s [ o p t i o n s . . . ] p a r a m e t r e s . . . \n\n” ,

a r g v [ 0 ] ) ;p r i n t f ( ” Opt ions :\ n”

20”−h\ tCe message d ’ a i d e \n””−x\ t o p t i o n x\n””−a nom\ t pa ra me t re o p t i o n n e l \n” ) ;

return EXIT SUCCESS ;case ’ x ’ :

25o p t x = 1 ;break ;

case ’ a ’ :o p t a = o p t a r g ;break ;

30case ’ ? ’ :f p r i n t f ( s t d e r r , ” Opt ion i n c o n n u e ‘−%c ’ .\ n” , o p t o p t ) ;return EXIT FAILURE ;

d e f a u l t :return EXIT FAILURE ;

35}}p r i n t f ( ”= o p t i o n ‘−x ’ %s \n” ,

( o p t x ? ” a c t i v e e ” : ” d e s a c t i v e e ” ) ) ;

40i f ( o p t a == NULL)p r i n t f ( ”= pa ra me t r e ‘−a ’ a b s e n t \n” ) ;

e l s ep r i n t f ( ”= pa ra me t r e ‘−a ’ p r e s e n t = %s \n” , o p t a ) ;

45p r i n t f ( ”%d p a r a m e t r e s s u p p l e m e n t a i r e s \n” , argc−o p t i n d ) ;f o r ( i n d e x = o p t i n d ; i n d e x < a r g c ; i n d e x++)

p r i n t f ( ” −> %s \n” , a r g v [ i n d e x ] ) ;

return EXIT SUCCESS ;

7

Page 8: Programmation Syst`eme et Réseau sous Unix

50}

Exemple.

% e s s a i−g e t o p t −a un deux t r o i s −x q u a t r e= o p t i o n ‘−x ’ a c t i v e e= pa ra me t r e ‘−a ’ p r e s e n t = un3 p a r a m e t r e s s u p p l e m e n t a i r e s

−> deux−> t r o i s−> q u a t r e

3.2 Variables d’environnement

La fonction getenv() permet de consulter les variables d’environnement :

#inc lude < s t d l i b . h>char ∗ g e t e n v ( const char ∗name ) ;

Exemple :

1/∗ D i v e r s / get te rm . c ∗/

#inc lude < s t d l i b . h>#inc lude <s t d i o . h>

5i n t main ( void ){

char ∗ t e r m i n a l = g e t e n v ( ”TERM” ) ;p r i n t f ( ” Le t e r m i n a l e s t ” ) ;

10i f ( t e r m i n a l == NULL)p r i n t f ( ” inconnu \n” ) ;

e l s ep r i n t f ( ”un %s \n” , t e r m i n a l ) ;

return EXIT SUCCESS ;15}

Exercice : Ecrire un programme exoenv.c qui affiche les valeurs des variables d’environnementindiquees. Exemple d’execution :

% exoenv TERM LOGNAME PWDTERM=xtermLOGNAME=b i l l a u dPWD=/n et / p r o f s / b i l l a u d / e s s a i s%

Voir aussi les fonctions

¡verb¿ int putenv(const char *string) ; int setenv(const char *name, const char *value, int over-write) ; void unsetenv(const char *name) ; ¡/verb¿

qui permettent de modifier les variables d’environnement du processus courant et de ses fils. Il n’ya pas de moyen de modifier les variables du processus pere.

Exercice. Ecrire un petit programme pour mettre en evidence le fait que le troisieme parametrede main(...) indique les valeurs des variables d’environnement au moment de l’appel, et non pas lesvaleurs courantes.

8

Page 9: Programmation Syst`eme et Réseau sous Unix

3.3 exit() : Fin de programme

L’execution d’un programme se termine– soit par un return dans la fonction main()

– soit par un appel a la fonction exit()

#inc lude < s t d l i b . h>void e x i t ( i n t s t a t u s ) ;

Le parametre status est le code de retour du processus. On utilisera de preference les deuxconstantes EXIT SUCCESS et EXIT FAILURE definies dans stdlib.h.

4 Erreurs

4.1 errno, perror()

La plupart des fonctions du systeme peuvent echouer pour diverses raisons. On peut alors examinerla variable errno pour determiner plus precisement la cause de l’echec, et agir en consequence.

#inc lude <e r r n o . h>extern i n t e r r n o ;

La fonction perror() imprime sur la sortie d’erreur standard un message decrivant la derniereerreur qui s’est produite, precede par la chaıne s.

#inc lude <s t d i o . h>void p e r r o r ( const char ∗ s ) ;

Enfin, la fonction strerror() retourne le texte (en anglais) du message d’erreur correspondant aun numero.

#inc lude < s t r i n g . h>char ∗ s t r e r r o r ( i n t errnum ) ;

Exemple : programme qui change les droits d’acces a des fichiers grace a la commande systemechmod(2).

1/∗ D i v e r s / d r o i t s . c ∗/

/∗∗ met l e s d r o i t s 0600 s u r un ou p l u s i e u r s f i c h i e r s

5∗ ( i l l u s t r a t i o n de chmod ( ) e t e r r n o )∗/

#inc lude < s t d l i b . h>#inc lude <s t d i o . h>

10#inc lude <s y s / s t a t . h>#inc lude <e r r n o . h>#inc lude < s t r i n g . h>

void e c r i r e m e s s a g e ( i n t numero )15{

switch ( numero ) {case EACCES :

p r i n t f ( ” i m p o s s i b l e de c o n s u l t e r un des ”” r e p e r t o i r e s du chemin ” ) ;

20break ;case ELOOP :

9

Page 10: Programmation Syst`eme et Réseau sous Unix

p r i n t f ( ” t r o p de l i e n s s y m b o l i q u e s ( b o u c l e s ?) ” ) ;break ;

case ENAMETOOLONG :25p r i n t f ( ” l e nom e s t t r o p l o n g ” ) ;

break ;case ENOENT :

p r i n t f ( ” l e f i c h i e r n ’ e x i s t e pas ” ) ;break ;

30case EPERM :p r i n t f ( ” p e r m i s s i o n r e f u s e e ” ) ;break ;

d e f a u l t :p r i n t f ( ” e r r e u r %s ” , s t r e r r o r ( numero ) ) ;

35break ;}

}

40i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t k ;f o r ( k=1; k<a r g c ; k++) {

p r i n t f ( ”%s : ” , a r g v [ k ] ) ;45i f ( chmod ( a r g v [ k ] , S IREAD | S IWRITE ) == 0) {

p r i n t f ( ” f i c h i e r p r o t e g e ” ) ;} e l s e {

e c r i r e m e s s a g e ( e r r n o ) ;}

50p r i n t f ( ”\n” ) ;}return EXIT SUCCESS ;

}

4.2 Traitement des erreurs, branchements non locaux

#inc lude <se t jmp . h>

i n t se t jmp ( jmp buf env ) ;void longjmp ( jmp buf env , i n t v a l ) ;

Ces deux fonctions permettent de realiser un branchement d’une fonction a une autre (la premieredoit avoir ete appelee, au moins indirectement, par la seconde). C’est un moyen primitif de realiser untraitement d’erreurs par exceptions.

La fonction setjmp() sauve l’environnement (contexte d’execution) dans la variable tampon env,et retourne 0 si elle a ete appelee directement.

La fonction longjmp() retablit le dernier environnement qui a ete sauve dans env par un appel asetjmp(). Le programme continue a l’endroit du setjmp() comme si celui-ci avait retourne la valeurval. (Si on met val a 0 la valeur retournee est 1).

Exemple.

1/∗ D i v e r s / jump . c ∗/

#inc lude <se t jmp . h>#inc lude <s t d i o . h>

10

Page 11: Programmation Syst`eme et Réseau sous Unix

5#inc lude < s t d l i b . h>

#def ine EXCEPTION PAS DE SOLUTION 1#def ine EXCEPTION EQUATION TRIVIALE 2

10jmp buf e r r e u r ;

f l o a t r e s o l u t i o n ( i n t a , i n t b ){

15i f ( a==0) {i f ( b==0)

longjmp ( e r r e u r , EXCEPTION EQUATION TRIVIALE ) ;e l s e

longjmp ( e r r e u r , EXCEPTION PAS DE SOLUTION ) ;20} ;

return ( −b / ( f l o a t ) a ) ;}

i n t main ( void )25{

i n t a , b ;f l o a t x ;i n t r e t ;

30p r i n t f ( ” C o e f f i c i e n t s de ax+b=0\n” ) ;s c a n f ( ”%d %d” , &a , &b ) ;

r e t = set jmp ( e r r e u r ) ;

35i f ( r e t == 0 ) {x = r e s o l u t i o n ( a , b ) ;p r i n t f ( ” S o l u t i o n = %f \n” , x ) ;return EXIT SUCCESS ;

}40

switch ( r e t ) {case EXCEPTION PAS DE SOLUTION :

p r i n t f ( ” C e t t e e q u a t i o n n ’ a pas de s o l u t i o n \n” ) ;break ;

45case EXCEPTION EQUATION TRIVIALE :p r i n t f ( ” C e t t e e q u a t i o n e s t t o u j o u r s v r a i e .\ n” ) ;break ;

}return EXIT FAILURE ;

50}

5 Allocation dynamique

#inc lude < s t d l i b . h>void ∗m a l l o c ( s i z e t s i z e ) ;void f r e e ( void ∗ p t r ) ;void ∗ r e a l l o c ( void ∗ ptr , s i z e t s i z e ) ;

11

Page 12: Programmation Syst`eme et Réseau sous Unix

malloc() demande au systeme d’exploitation l’allocation d’un espace memoire de taille superieureou egale a size octets. La valeur retournee est un pointeur sur cet espace (NULL en cas d’echec).free() restitue cet espace au systeme. realloc() permet d’agrandir la zone allouee.

Il est tres frequent de devoir allouer une zone memoire pour y loger une copie d’une chaıne decaracteres. On utilise pour cela la fonction strdup()

#inc lude < s t r i n g . h>char ∗ s t r d u p ( const char ∗ s ) ;

L’instruction “nouveau = strdup(ancien)” est approximativement equivalente a :

nouveau = s t r c p y ( m a l l o c (1+ s t r l e n ( a n c i e n ) ) , a n c i e n ) ;

Exemple : la fonction lireligne() ci-dessous lit une ligne de l’entree standard et retourne cetteligne dans un tampon d’une taille suffisante. Elle renvoie le pointeur NULL si il n’y a plus de place enmemoire.

1/∗ l i r e l i g n e . c ∗/

#inc lude < s t d l i b . h>#inc lude <s t d i o . h>

5#def ine TAILLE INITIALE 16

char ∗ l i r e l i g n e ( void ){

10/∗Renvo ie un tampon de t e x t e c o n t e n a n t une l i g n el u e s u r l ’ e n t r e e s t a n d a r d .Un nouveau tampon e s t c r e e a chaque i n v o c a t i o n .Renvo ie NULL en c a s de prob l eme d ’ a l l o c a t i o n

15∗/

char ∗ c h a i n e ;i n t t a i l l e a l l o u e e , t a i l l e c o u r a n t e ;i n t c ;

20c h a i n e = m a l l o c ( TAILLE INITIALE ) ;i f ( c h a i n e == NULL)

return NULL ;t a i l l e c o u r a n t e = 0 ;

25t a i l l e a l l o u e e = TAILLE INITIALE ;

whi le ( 1 ) {c = g e t c h a r ( ) ;i f ( ( c==’ \n ’ ) | | ( c==EOF) ) break ;

30c h a i n e [ t a i l l e c o u r a n t e ++] = c ;i f ( t a i l l e c o u r a n t e == t a i l l e a l l o u e e ) {

char ∗ tmp ;t a i l l e a l l o u e e ∗= 2 ;tmp = r e a l l o c ( c h a in e , t a i l l e a l l o u e e ) ;

35i f ( tmp == NULL) {f r e e ( c h a i n e ) ;return NULL ;

}c h a i n e = tmp ;

12

Page 13: Programmation Syst`eme et Réseau sous Unix

40}} ;c h a i n e [ t a i l l e c o u r a n t e ] = ’ \0 ’ ;return c h a i n e ;

}45

i n t main ( void ){

char ∗ c h a i n e ;p r i n t f ( ” t a p e z une grande c h a ı n e \n” ) ;

50c h a i n e = l i r e l i g n e ( ) ;i f ( c h a i n e == NULL) {

f p r i n t f ( s t d e r r , ” P l u s de p l a c e en memoire\n” ) ;return EXIT FAILURE ;

}55p r i n t f ( ”%s \n” , c h a i n e ) ;

f r e e ( c h a i n e ) ;return EXIT SUCCESS ;

}

Attention : dans l’exemple ci-dessus la fonction lirechaine() alloue un nouveau tampon a chaqueinvocation. Il est donc de la responsabilite du programmeur de liberer ce tampon apres usage pour eviterles fuites memoire.

6 Manipulation des fichiers, operations de haut niveau

Ici on utilise le terme � fichier � dans son sens Unixien le plus large, ce qui inclue les peripheriques(comme /dev/tty, /dev/audio,...) aussi bien que les � pseudo-fichiers � comme /proc/cpuinfo,/proc/sound, etc.

6.1 Flots standards

Il y a trois flots predeclares, qui correspondent a l’entree et la sortie standards, et a la sortie d’erreur :

#inc lude <s t d i o . h>FILE ∗ s t d i n ;FILE ∗ s t d o u t ;FILE ∗ s t d e r r ;

Quelques fonctions agissent implicitement sur ces flots :

i n t p r i n t f ( const char ∗ format , . . . ) ;i n t s c a n f ( const char ∗ format , . . . ) ;i n t g e t c h a r ( void ) ;char ∗ g e t s ( char ∗ s ) ;

printf(...) ecrit sur stdout la valeur d’expressions selon un format donne. scanf(...) lit surstdin la valeur de variables.

1/∗ f a c t u r e . c ∗/

/∗ exemple p r i n t f ( ) , s c a n f ( ) ∗/

5#inc lude < s t d l i b . h>#inc lude <s t d i o . h>

i n t main ( void )

13

Page 14: Programmation Syst`eme et Réseau sous Unix

{10char a r t i c l e [ 1 0 ] ;

f l o a t p r i x ;i n t q u a n t i t e ;i n t n ;

15p r i n t f ( ” a r t i c l e , p r i x u n i t a i r e , q u a n t i t e ?\n” ) ;n = s c a n f ( ”%s %f %d” ,

a r t i c l e ,&p r i x ,&q u a n t i t e ) ;

20i f ( n != 3) { /∗ on n ’ a pas r e u s s i a l i r e 3 c h o s e s ? ∗/

p r i n t f ( ” E r r e u r dans l e s donn ees ” ) ;return EXIT FAILURE ;

}25

p r i n t f ( ”%d %s a %10.2 f = %10.2 f \n” ,q u a n t i t e ,a r t i c l e ,p r i x ,

30p r i x ∗ q u a n t i t e ) ;

return EXIT SUCCESS ;}

scanf() renvoie le nombre d’objets qui ont pu etre effectivement lus sans erreur.gets() lit des caracteres jusqu’a une marque de fin de ligne ou de fin de fichier, et les place

(marque non comprise) dans le tampon donne en parametre, suivis par un caractere NUL. gets()renvoie finalement l’adresse du tampon. Attention, prevoir un tampon assez grand, ou (beaucoupmieux) utilisez fgets().

getchar() lit un caractere sur l’entree standard et retourne sa valeur sous forme d’entier positif,ou la constante EOF (-1) en fin de fichier.

6.2 Operations sur les flots

#inc lude <s t d i o . h>FILE ∗ fo pe n ( char ∗path , char ∗mode ) ;i n t f c l o s e ( FILE ∗ s t ream ) ;i n t f p r i n t f ( FILE ∗ stream , const char ∗ format , . . . ) ;i n t f s c a n f ( FILE ∗ stream , const char ∗ format , . . . ) ;i n t f g e t c ( FILE ∗ s t ream ) ;char ∗ f g e t s ( char ∗ s , i n t s i z e , FILE ∗ s t ream ) ;

fopen() tente d’ouvrir le fichier designe par la chaıne path selon le mode indique, qui peut etre"r" (lecture seulement), "r+" (lecture et ecriture), "w" (ecriture seulement), "w+" (lecture et ecriture,effacement si le fichier existe deja), "a" (ecriture a partir de la fin du fichier si il existe deja), "a+"(lecture et ecriture, positionnement a la fin du fichier si il existe deja).

Si l’ouverture echoue, fopen() retourne le pointeur NULL.

i n t f p r i n t f ( FILE ∗ stream , const char ∗ format , . . . ) ;i n t f s c a n f ( FILE ∗ stream , const char ∗ format , . . . ) ;i n t f g e t c ( FILE ∗ s t ream ) ;char ∗ f g e t s ( char ∗ s , i n t s i z e , FILE ∗ s t ream ) ;

14

Page 15: Programmation Syst`eme et Réseau sous Unix

Les trois premieres fonctions ne different de printf(), scanf() et getchar() que par le premierparametre, qui precise sur quel flot porte l’operation.

Comme gets(), fgets() lit une ligne de caracteres pour la placer dans un tampon, mais1. la longueur de ce tampon est precisee (ceci empeche les debordements)

2. le caractere de fin de ligne (newline) est effectivement stocke dans le tampon.

Exemple : comptage du nombre de caracteres et de lignes d’un fichier. Affichage du resultat surla sortie standard.

1/∗ D i v e r s / comptage . c ∗/

#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

5void abandon ( char r a i s o n [ ] ){

p e r r o r ( r a i s o n ) ;e x i t ( EXIT FAILURE ) ;

10}

void compter ( char n o m f i c h i e r [ ] , FILE ∗ f ){

i n t c ;15i n t n b c a r a c t e r e s =0, n b l i g n e s =0;

whi le ( ( c = f g e t c ( f ) ) != EOF) {n b c a r a c t e r e s ++;i f ( c == ’ \n ’ ) n b l i g n e s ++;

20} ;p r i n t f ( ”%s : %d c a r s , %d l i g n e s \n” ,

n o m f i c h i e r ,n b c a r a c t e r e s ,n b l i g n e s ) ;

25}

i n t main ( i n t argc , char ∗ a r g v [ ] ){

char ∗ n o m f i c h i e r ;30char ∗nom programme = a r g v [ 0 ] ;

FILE ∗ f ;

switch ( a r g c ) {case 1 :

35compter ( ” e n t r e e s t a n d a r d ” , s t d i n ) ;break ;

case 2 :n o m f i c h i e r = a r g v [ 1 ] ;f = fo pe n ( n o m f i c h i e r , ” r ” ) ;

40i f ( f == NULL) {f p r i n t f ( s t d e r r ,

”%s : f i c h i e r %s a b s e n t ou i l l i s i b l e \n” ,nom programme , n o m f i c h i e r ) ;

e x i t ( EXIT FAILURE ) ;45} ;

compter ( n o m f i c h i e r , f ) ;

15

Page 16: Programmation Syst`eme et Réseau sous Unix

f c l o s e ( f ) ;break ;

d e f a u l t :50f p r i n t f ( s t d e r r , ” Usage : %s [ f i c h i e r ]\ n” , nom programme ) ;

e x i t ( EXIT SUCCESS ) ;} ;return ( EXIT SUCCESS ) ;

}

6.3 Positionnement

i n t f e o f ( FILE ∗ s t ream ) ;long f t e l l ( FILE ∗ s t ream ) ;i n t f s e e k ( FILE ∗ stream , long o f f s e t , i n t whence ) ;

feof() indique si la fin de fichier est atteinte. ftell() indique la position courante dans le fichier(0 = debut). fseek() deplace la position courante : si whence est SEEK SET la position est donneepar rapport au debut du fichier, si c’est SEEK CUR : deplacement par rapport a la position courante,SEEK END : deplacement par rapport a la fin.

6.4 Divers

i n t f e r r o r ( FILE ∗ s t ream ) ;void c l e a r e r r ( FILE ∗ s t ream ) ;i n t f i l e n o ( FILE ∗ s t ream ) ;FILE ∗ fdopen ( i n t f i l d e s , char ∗mode ) ;

La fonctionferror() indique si une erreur a eu lieu sur un flot, clearerr() efface l’indicateurd’erreur et fileno() renvoie le numero de fichier de bas niveau (descripteur de fichier) correspondanta un flot. Inversement, fdopen() ouvre un fichier de haut niveau a partir d’un fichier de bas niveaudeja ouvert.

7 Manipulation des fichiers, operations de bas niveau

7.1 Ouverture, fermeture, lecture, ecriture

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s t a t . h>#inc lude < f c n t l . h>i n t open ( const char ∗pathname , i n t f l a g s , mode t mode ) ;

Ouverture d’un fichier nomme pathname. Les flags peuvent prendre l’une des valeurs suivantes :O RDONLY (lecture seulement), O WRONLY (ecriture seulement), O RDWR (lecture et ecriture). Cettevaleur peut etre combinee eventuellement (par un “ou logique”) avec des options : O CREAT (creationdu fichier si il n’existe pas deja), O TRUNC (si le fichier existe il sera tronque), O APPEND (chaque ecriturese fera a la fin du fichier), etc.

En cas de creation d’un nouveau fichier, le mode sert a preciser les droits d’acces. Lorsqu’un nouveaufichier est cree, mode est combine avec le umask du processus pour former les droits d’acces du fichier.Les permissions effectives sont alors (mode & ~umask)

Le parametre mode doit etre present quand les flags contiennent O CREAT. ¡p¿L’entier retourne par open() est un descripteur de fichier (-1 en cas d’erreur), qui sert a referencer

le fichier par la suite. Les descripteurs 0, 1 et 2 correspondent aux fichiers standards stdin, stdoutet stderr qui sont normalement deja ouverts (0=entree, 1=sortie, 2=erreurs).

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>

16

Page 17: Programmation Syst`eme et Réseau sous Unix

i n t c l o s e ( i n t f d ) ;i n t r e a d ( i n t fd , char ∗buf , s i z e t count ) ;s i z e t w r i t e ( i n t fd , const char ∗buf , s i z e t count ) ;

close() ferme le fichier indique par le descripteur fd. Retourne 0 en cas de succes, -1 en casd’echec. read() demande a lire au plus count octets sur fd, a placer dans le tampon buf. Retournele nombre d’octets qui ont ete effectivement lus, qui peut etre inferieur a la limite donnee pour causede non-disponibilite (-1 en cas d’erreur, 0 en fin de fichier). write() tente d’ecrire sur le fichier lescount premiers octets du tampon buf. Retourne le nombre d’octets qui ont ete effectivement ecrits,-1 en cas d’erreur.

Exemple :

1/∗ c o p i e . c ∗/

/∗E n t r e e s−s o r t i e s de bas n i v e a u

5Usages :1 : c o p i e ( e n t r e e−s t a n d a r d −> s o r t i e s t a n d a r d )2 : c o p i e f i c h i e r ( f i c h i e r −> s o r t i e s t a n d a r d )3 : c o p i e s o u r c e d e s t ( s o u r c e −> d e s t )

∗/10

#inc lude < s t d l i b . h>#inc lude <s t d i o . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s t a t . h>

15#inc lude < f c n t l . h>#inc lude <u n i s t d . h>

#def ine ENTREE STANDARD 0#def ine SORTIE STANDARD 1

20#def ine TAILLE TAMPON 4096

void abandon ( char message [ ] ){

f p r i n t f ( s t d e r r , ” E r r e u r f a t a l e %s \n” , message ) ;25e x i t ( EXIT FAILURE ) ;

}

void t r a n s f e r t ( i n t e n t r e e , i n t s o r t i e ){

30i n t n b l u s , n b e c r i t s ;char tampon [ TAILLE TAMPON ] ;

i f ( e n t r e e == −1) {abandon ( ” F i c h i e r d ’ e n t r e e i n t r o u v a b l e ” ) ;

35}i f ( s o r t i e == −1) {

abandon ( ”Ne peut pas o u v r i r l e f i c h i e r de s o r t i e ” ) ;}

40f o r ( ; ; ) {n b l u s = r e a d ( e n t r e e , tampon , TAILLE TAMPON ) ;i f ( n b l u s <= 0)

17

Page 18: Programmation Syst`eme et Réseau sous Unix

break ;n b e c r i t s = w r i t e ( s o r t i e , tampon , n b l u s ) ;

45i f ( n b e c r i t s != n b l u s )abandon ( ” Probleme d ’ e c r i t u r e ” ) ;

}}

50i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t e n t r e e , s o r t i e ;

switch ( a r g c ) {55case 1 :

t r a n s f e r t (ENTREE STANDARD, SORTIE STANDARD ) ;break ;

case 2 :e n t r e e = open ( a r g v [ 1 ] , O RDONLY ) ;

60t r a n s f e r t ( e n t r e e , SORTIE STANDARD ) ;c l o s e ( e n t r e e ) ;break ;

case 3 :e n t r e e = open ( a r g v [ 1 ] , O RDONLY ) ;

65s o r t i e = open ( a r g v [ 2 ] , O CREAT | O WRONLY | O TRUNC, 0 6 6 6 ) ;t r a n s f e r t ( e n t r e e , s o r t i e ) ;c l o s e ( e n t r e e ) ;c l o s e ( s o r t i e ) ;break ;

70d e f a u l t :abandon ( ” Usage : c o p i e [ s r c [ d e s t ] ] ” ) ;

}return EXIT SUCCESS ;

}

Probleme. Montrez que la taille du tampon influe sur les performances des operations d’entree-sortie. Pour cela, modifiez le programme precedent pour qu’il accepte 3 parametres : les noms desfichiers source et destination, et la taille du tampon (ce tampon sera alloue dynamiquement).

7.2 Suppression

#inc lude <s t d i o . h>i n t remove ( const char ∗pathname ) ;

Cette fonction supprime le fichier pathname, et retourne 0 en cas de succes (-1 sinon).Exercice : ecrire un substitut pour la commande rm.

7.3 Positionnement

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>

o f f t l s e e k ( i n t f i l d e s , o f f t o f f s e t , i n t whence ) ;

lseek() repositionne le pointeur de lecture. Similaire a fseek(). Pour connaıtre la position cou-rante faire un appel a stat().

Exercice. Ecrire un programme pour manipuler un fichier relatif d’enregistrements de taille fixe.

7.4 Verrouillage

18

Page 19: Programmation Syst`eme et Réseau sous Unix

#inc lude <s y s / f i l e . h>i n t f l o c k ( i n t fd , i n t o p e r a t i o n )

Lorsque operation est LOCK EX, il y a verrouillage du fichier designe par le descripteur fd. Lefichier est deverrouille par l’option LOCK UN.

Probleme. Ecrire une fonction mutex() qui permettra de delimiter une section critique dans unprogramme C. Exemple d’utilisation :

#inc lude ” mutex . h”. . .mutex ( ”/tmp/ f o o b a r ” ,MUTEX BEGIN ) ;. . .mutex ( ”/tmp/ f o o b a r ” ,MUTEX END ) ;

Le premier parametre indique le nom du fichier utilise comme verrou. Le second precise si il s’agitde verrouiller ou deverrouiller. Faut-il prevoir des options MUTEX CREATE, MUTEX DELETE ? Qu’arrive-t’ilsi un programme se termine en “oubliant” de fermer des sections critiques ?

Fournir le fichier d’interface mutex.h, l’implementation mutex.c, et des programmes illustrantl’utilisation de cette fonction.

7.5 Informations sur les fichiers/repertoires/...

#inc lude <s y s / s t a t . h>#inc lude <u n i s t d . h>i n t s t a t ( const char ∗ f i l e n a m e , s t r u c t s t a t ∗ buf ) ;i n t f s t a t ( i n t f i l e d e s , s t r u c t s t a t ∗ buf ) ;

Ces fonctions permettent de connaıtre diverses informations sur un fichier designe par un chemind’acces (stat()) ou par un descripteur (fstat()).

Exemple :

1/∗ D i v e r s / t a i l l e . c ∗//∗

i n d i q u e l a t a i l l e e t l a n a t u r edes ” f i c h i e r s ” c i t e s en p a r a m e t r e s

5∗/

#inc lude < s t d l i b . h>#inc lude <s t d i o . h>#inc lude <s y s / s t a t . h>

10#inc lude <e r r n o . h>#inc lude < s t r i n g . h>

char ∗nom mode ( mode t mode ){

15i f ( S ISREG ( mode ) ) return ” f i c h i e r ” ;i f ( S ISLNK ( mode ) ) return ” l i e n s y m b o l i q u e ” ;i f ( S ISDIR ( mode ) ) return ” r e p e r t o i r e ” ;i f ( S ISCHR ( mode ) ) return ” p e r i p h e r i q u e mode c a r a c t e r e ” ;i f ( S ISBLK ( mode ) ) return ” p e r i p h e r i q u e mode b l o c ” ;

20i f ( S ISFIFO ( mode ) ) return ” f i f o ” ;i f ( S ISSOCK ( mode ) ) return ” s o c k e t ” ;return ” inconnu ” ;

}

25i n t main ( i n t argc , char ∗ a r g v [ ] )

19

Page 20: Programmation Syst`eme et Réseau sous Unix

{i n t k ;s t r u c t s t a t s ;

30i f ( a r g c < 2) {

f p r i n t f ( s t d e r r , ” Usage : %s f i c h i e r . . . \n” , a r g v [ 0 ] ) ;e x i t ( EXIT FAILURE ) ;

} ;35f o r ( k=1 ; k<a r g c ; k++) {

p r i n t f ( ”%20s :\ t ” , a r g v [ k ] ) ;i f ( s t a t ( a r g v [ k ] , &s ) == 0) {

p r i n t f ( ” t a i l l e %8ld , t y p e %s ” ,s . s t s i z e ,

40nom mode ( s . st mode ) ) ;} e l s e {

switch ( e r r n o ) {case ENOENT :

p r i n t f ( ” l e f i c h i e r n ’ e x i s t e pas ” ) ;45break ;

d e f a u l t :p r i n t f ( ” e r r e u r %s ” , s t r e r r o r ( e r r n o ) ) ;break ;

}50}

p r i n t f ( ”\n” ) ;}return EXIT SUCCESS ;

}

7.6 Parcours de repertoires

Le parcours d’un repertoire, pour obtenir la liste des fichiers et repertoires qu’il contient, se faitgrace aux fonctions :

#inc lude <s y s / t y p e s . h>#inc lude <d i r e n t . h>DIR ∗ o p e n d i r ( const char ∗name ) ;i n t c l o s e d i r ( DIR ∗ d i r ) ;void r e w i n d d i r ( DIR ∗ d i r ) ;void s e e k d i r ( DIR ∗ d i r , o f f t o f f s e t ) ;o f f t t e l l d i r ( DIR ∗ d i r ) ;

Voir la documentation pour des exemples.Exercice : ecrire une version simplifiee de la commande ls.Exercice : ecrire une commande qui fasse apparaıtre la structure d’une arborescence. Exemple

d’affichage :

C++| CompiSep| F i c h i e r sSysteme| Semaphores| P i p e s| Poly| SVGD| E s s a i s

20

Page 21: Programmation Syst`eme et Réseau sous Unix

| F i f o s

Conseil : ecrire une fonction a deux parametres : le chemin d’acces du repertoire et le niveau derecursion.

7.7 Duplication de descripteurs

i n t dup ( i n t o l d f d ) ;i n t dup2 ( i n t o l d f d , i n t newfd ) ;

Ces deux fonctions creent une copie du descripteur oldfd. dup() utilise le plus petit numero dedescripteur libre. dup2() reutilise le descripteur newfd, en fermant eventuellement le fichier qui luietait anterieurement associe.

La valeur retournee est celle du descripteur, ou -1 en cas d’erreur.Exemple

1/∗ D i v e r s / r e d i r e c t i o n . c ∗/

/∗Le f i c h i e r c i t e en par am e t re e s t p a s s e a t r a v e r s

5l a commande wc .∗/

#inc lude <s y s / t y p e s . h>#inc lude < f c n t l . h>

10#inc lude <s t d i o . h>#inc lude < s t d l i b . h>#inc lude <u n i s t d . h>#inc lude <e r r n o . h>

15#def ine COMMANDE ”wc”

void abandon ( char message [ ] ){

p e r r o r ( message ) ;20e x i t ( EXIT FAILURE ) ;

}

i n t main ( i n t argc , char ∗ a r g v [ ] ){

25i n t f d ;

i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” Usage : %s f i c h i e r \n” , a r g v [ 0 ] ) ;abandon ( ” mauvais nombre de p a r a m e t r e s ” ) ;

30}

f d = open ( a r g v [ 1 ] , O RDONLY ) ;i f ( f d == −1)

abandon ( ” open ” ) ;35

/∗ t r a n s f e r t du d e s c r i p t e u r dans c e l u i de l ’ e n t r e e s t a n d a r d ∗/i f ( dup2 ( fd , 0) < 0)

abandon ( ” dup2 ” ) ;

21

Page 22: Programmation Syst`eme et Réseau sous Unix

40c l o s e ( f d ) ;

system (COMMANDE) ;i f ( e r r n o != 0)

abandon ( ” system ” ) ;45

return EXIT SUCCESS ;}

Exercice : que se produit-il si on essaie de rediriger la sortie standard d’une commande a la manierede l’exemple precedent ? (essayer avec “ls”, “ls -l”).

7.8 mmap() : fichiers ”mappes” en memoire

Un fichier ”mappe en memoire” apparaıt comme un tableau d’octets, ce qui permet de le parcouriren tous sens plus commodement qu’avec des seek(), read() et write().

C’est technique beaucoup plus economique que de copier le fichier dans une zone allouee enmemoire : c’est le systeme de memoire virtuelle qui s’occupe de lire et ecrire physiquement les pagesdu fichier au moment ou on tente d’y acceder, et gere tous les tampons.

#inc lude <u n i s t d . h>#inc lude <s y s /mman . h>

void ∗ mmap( void ∗ s t a r t , s i z e t l e n g t h ,i n t p r o t , i n t f l a g s ,i n t fd , o f f t o f f s e t ) ;

i n t munmap( void ∗ s t a r t , s i z e t l e n g t h ) ;

La fonction mmap() ”mappe” en memoire un morceau (de longueur length, en partant du offset-ieme octet) du fichier designe par le descripteur fd , et retourne un pointeur sur la zone de memoirecorrespondante.

On peut definir quelques options (protection en lecture seule, partage, etc) grace a prot et flags.Voir pages de manuel. munmap() ”libere” la memoire.

1/∗D i v e r s / i n v e r s e . c

A f f i c h a g e des l i g n e s d ’ un f i c h i e r en p a r t a n t de l a f i n5Exemple d ’ u t i l i s a t i o n de mmap

M. B i l l a u d , Octobre 2002∗/

10#inc lude <u n i s t d . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s t a t . h>

15#inc lude <s y s /mman . h>#inc lude < f c n t l . h>

void abandon ( char message [ ] )20{

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

22

Page 23: Programmation Syst`eme et Réseau sous Unix

25/∗ a f f i c h a g e a l ’ e n v e r s du contenu d ’ un tampon de t e x t e ∗/

void a f f i c h e r ( char tampon [ ] , i n t t a i l l e ){

char ∗ p t r ;30i n t nb = 1 ; /∗ l o n g u e u r l i g n e c ou ra nt e , y c o m p r i s ’\n ’ ∗/

f o r ( p t r = tampon+t a i l l e −1; p t r >= tampon ; pt r−−) {i f (∗ p t r == ’ \n ’ ) {

w r i t e ( 1 , p t r +1, nb ) ;35nb = 0 ;

}nb++;

}w r i t e ( 1 , p t r +1, nb ) ;

40}

i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t f d ;45s t r u c t s t a t s ;

char ∗ t ;

i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” Usage : %s f i c h i e r \n” , a r g v [ 0 ] ) ;

50return EXIT FAILURE ;}i f ( s t a t ( a r g v [ 1 ] , &s ) != 0)

abandon ( ” C o n t r o l e du t y p e ” ) ;

55i f ( ! S ISREG ( s . st mode ) ) {f p r i n t f ( s t d e r r , ”%s n ’ e s t pas un f i c h i e r \n” , a r g v [ 1 ] ) ;return EXIT FAILURE ;

}f d = open ( a r g v [ 1 ] , O RDONLY ) ;

60i f ( f d < 0)abandon ( ” O u v e r t u r e ” ) ;

t = mmap(NULL , s . s t s i z e , PROT READ, MAP PRIVATE , fd , 0 ) ;i f ( t == MAP FAILED)

65abandon ( ” Mise en memoire ” ) ;

a f f i c h e r ( t , s . s t s i z e ) ;

i f (munmap( t , s . s t s i z e ) < 0)70abandon ( ” Detachement ” ) ;

c l o s e ( f d ) ;return EXIT SUCCESS ;

}

23

Page 24: Programmation Syst`eme et Réseau sous Unix

8 Pipes et FIFOs

Les pipes et les FIFOs permettent de faire communiquer des processus d’une meme machine : cequ’un (ou plusieurs) processus ecrit peut etre lu par un autre.

8.1 FIFOs

Les FIFOs sont egalement appeles � tuyaux nommes �. Ce sont des objets visibles dans l’arbores-cence des fichiers et repertoires. Ce qu’un processus ecrit dans une FIFO peut etre lu immediatementpar d’autres processus.

#inc lude <s t d i o . h>i n t m k f i f o ( const char ∗path , mode t mode ) ;

La fonction mkfifo() cree un FIFO ayant le chemin indique par path et les droits d’acces donnespar mode. Si la creation reussit, la fonction renvoie 0, sinon -1. Exemple :

i f ( m k f i f o ( ”/tmp/ f i f o . c o u r r i e r ” ,0644) == −1)p e r r o r ( ” m k f i f o ” ) ;

Les FIFOS sont ensuite utilisables par open(), read(), write(), close(), fdopen() etc.Exercice. Regarder ce qui se passe quand– plusieurs processus ecrivent dans une meme FIFO (faire une boucle sleep-write).– plusieurs processus lisent la meme FIFO.Exercice. Ecrire une commande mutex qui permettra de delimiter une section critique dans des

shell-scripts. Exemple d’utilisation :

mutex −b /tmp/ f o o b a r. . .mutex −e /tmp/ f o o b a r

Le premier parametre indique si il s’agit de verrouiller (-b = begin) ou de deverrouiller (-e = end).Le second parametre est le nom du verrou.

Conseil : la premiere option peut s’obtenir en tentant de lire un jeton dans une FIFO. C’est laseconde option qui depose le jeton. Prevoir une option pour creer une FIFO ?

8.2 Pipes

On utilise un pipe (tuyau) pour faire communiquer un processus et un de ses descendants 3.

#inc lude <u n i s t d . h>i n t p i p e ( i n t f i l e d e s [ 2 ] ) ;

L’appel pipe() fabrique un tuyau de communication et renvoie dans un tableau une paire dedescripteurs. On lit a un bout du tuyau (sur le descripteur de sortie fildes[0]) ce qu’on a ecrit dansl’autre (filedes[1]). Voir exemple dans 11.1

Les pipes ne sont pas visibles dans l’arborescence des fichiers et repertoires, par contre ils sontherites lors de la creation d’un processus.

La fonction socketpair() (voir 10.5) generalise la fonction pipe.

8.3 Pipes depuis/vers une commande

#inc lude <s t d i o . h>FILE ∗popen ( const char ∗command , const char ∗ t y p e ) ;i n t p c l o s e ( FILE ∗ s t ream ) ;

3. ou des descendants - au sens large - du processus qui ont cree le tuyau

24

Page 25: Programmation Syst`eme et Réseau sous Unix

popen() lance la commande decrite par la chaıne command et retourne un flot.

Si type est "r" le flot retourne est celui de la sortie standard de la commande (on peut y lire). Sitype est "w" c’est son entree standard.

pclose() referme ce flot.

Exemple : envoi d’un � ls -l � par courrier

1/∗ D i v e r s / a v i s . c ∗/

/∗ I l l u s t r a t i o n de popen ( ) ∗/

5#inc lude <s y s / t y p e s . h>#inc lude < f c n t l . h>#inc lude < s t d l i b . h>#inc lude <u n i s t d . h>#inc lude <s t d i o . h>

10#def ine TAILLE MAX COMMANDE 100

void abandon ( char r a i s o n [ ] ){

15p e r r o r ( r a i s o n ) ;e x i t ( EXIT FAILURE ) ;

}

i n t main ( i n t argc , char ∗ a r g v [ ] )20{

char cmdmail [ TAILLE MAX COMMANDE ] ;FILE ∗ f m a i l , ∗ f l s ;i n t c ;

25i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” Usage : %s d e s t i n a t a i r e \n” , a r g v [ 0 ] ) ;e x i t ( EXIT FAILURE ) ;

} ;

30s n p r i n t f ( cmdmail , TAILLE MAX COMMANDE,” s e n d m a i l %s ” , a r g v [ 1 ] ) ;

f m a i l = popen ( cmdmail , ”w” ) ;i f ( f m a i l == NULL)

abandon ( ” popen ( s e n d m a i l ) ” ) ;35

f p r i n t f ( f m a i l , ” S u b j e c t : l s − l \n\n” ) ;f p r i n t f ( f m a i l , ” Cher %s ,\ n v o i c i mon r e p e r t o i r e :\ n” , a r g v [ 1 ] ) ;

40f l s = popen ( ” l s − l ” , ” r ” ) ;i f ( f l s == NULL)

abandon ( ” popen ( l s ) ” ) ;

whi le ( ( c = f g e t c ( f l s ) ) != EOF) {45f p u t c ( c , f m a i l ) ;

}p c l o s e ( f l s ) ;

25

Page 26: Programmation Syst`eme et Réseau sous Unix

f p r i n t f ( f m a i l , ”−−−\nLe Robot\n” ) ;50p c l o s e ( f m a i l ) ;

return EXIT SUCCESS ;}

9 select() : attente de donnees

Il est assez courant de devoir attendre des donnees en provenance de plusieurs sources. On utilisepour cela la fonction select() qui permet de surveiller plusieurs descripteurs simultanement.

#inc lude <s y s / t ime . h>#inc lude <s y s / t y p e s . h>#inc lude <u n i s t d . h>

i n t s e l e c t ( i n t n , f d s e t ∗ r e a d f d s ,f d s e t ∗w r i t e f d s ,f d s e t ∗ e x c e p t f d s ,s t r u c t t i m e v a l ∗ t i m e o u t ) ;

FD CLR ( i n t fd , f d s e t ∗ s e t ) ;FD ISSET ( i n t fd , f d s e t ∗ s e t ) ;FD SET ( i n t fd , f d s e t ∗ s e t ) ;FD ZERO( f d s e t ∗ s e t ) ;

Cette fonction attend que des donnees soient pretes a etre lues sur un des descripteurs de l’ensemblereadfs, ou que l’un des descripteurs de writefds soit pret a recevoir des ecritures, que des exceptionsse produisent (exceptfds), ou encore que le temps d’attente timeout soit epuise.

Lorsque select() se termine, readfds, writefds et exceptfds contiennent les descripteurs quiont change d’etat. select() retourne le nombre de descripteurs qui ont change d’etat, ou -1 en casde probleme.

L’entier n doit etre superieur (strictement) au plus grand des descripteurs contenus dans les 3ensembles (c’est en fait le nombre de bits significatifs du masque binaire qui represente les ensembles).On peut utiliser la constante FD SETSIZE.

Les pointeurs sur les ensembles (ou le delai) peuvent etre NULL, ils representent alors des ensemblesvides (ou une absence de limite de temps).

Les macros FD CLR, FD ISSET, FD SET, FD ZERO permettent de manipuler les ensembles de des-cripteurs.

9.1 Attente de donnees provenant de plusieurs sources

Exemple :

1/∗ D i v e r s / mix . c ∗/

/∗a f f i c h e l e s donn ees q u i p r o v i e n n e n t de 2 f i f o s

5usage : mix f 1 f 2∗/

#inc lude <s y s / t ime . h>#inc lude <s y s / t y p e s . h>

10#inc lude <s y s / s t a t . h>#inc lude <u n i s t d . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

26

Page 27: Programmation Syst`eme et Réseau sous Unix

#inc lude < f c n t l . h>15

#def ine TAILLE TAMPON 128

void abandon ( char message [ ] ){

20p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

/∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗25Mixe l e s donn ees en p r o v e n a n c e de deux

d e s c r i p t e u r s∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗/

void m i x e r ( i n t fd1 , i n t fd2 , i n t s o r t i e )30{

f d s e t o u v e r t s ; /∗ l e s d e s c r i p t e u r s o u v e r t s ∗/i n t n b o u v e r t s ;

FD ZERO (& o u v e r t s ) ;35FD SET ( fd1 ,& o u v e r t s ) ;

FD SET ( fd2 ,& o u v e r t s ) ;n b o u v e r t s = 2 ;

whi le ( n b o u v e r t s > 0) {40/∗ t a n t qu ’ i l r e s t e des

d e s c r i p t e u r s o u v e r t s . . . . ∗/f d s e t p r e t s ;char tampon [ TAILLE TAMPON ] ;

45/∗ on a t t e n d qu ’ un d e s c r i p t e u r s o i t p r e t . . . ∗/p r e t s = o u v e r t s ;i f ( s e l e c t ( FD SETSIZE , &p r e t s , NULL , NULL , NULL) < 0 )

abandon ( ” s e l e c t ” ) ;

50i f ( FD ISSET ( fd1 , &p r e t s ) ) {

/∗ s i fd 1 e s t p r e t . . . ∗/i n t n b l u s = r e a d ( fd1 , tampon , TAILLE TAMPON ) ;i f ( n b l u s >= 0) { /∗ on c o p i e ce qu ’ on a l u ∗/

55w r i t e ( s o r t i e , tampon , n b l u s ) ;} e l s e { /∗ f i n de f d1 : on l ’ e n l e v e ∗/

c l o s e ( fd 1 ) ;n b o u v e r t s −−;FD CLR ( fd1 , &o u v e r t s ) ;

60}}

i f ( FD ISSET ( fd2 , &p r e t s ) ) {/∗ s i fd 2 e s t p r e t . . . ∗/

65i n t n b l u s = r e a d ( fd2 , tampon , TAILLE TAMPON ) ;i f ( n b l u s >= 0) {

w r i t e ( s o r t i e , tampon , n b l u s ) ;

27

Page 28: Programmation Syst`eme et Réseau sous Unix

} e l s e {c l o s e ( fd 2 ) ;

70n b o u v e r t s −−;FD CLR ( fd2 , &o u v e r t s ) ;

}}

}75}

i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t fd1 , fd 2 ;80

i f ( a r g c != 3) {f p r i n t f ( s t d e r r , ” Usage : %s f 1 f 2 \n” , a r g v [ 0 ] ) ;return EXIT FAILURE ;

}85

fd 1 = open ( a r g v [ 1 ] , O RDONLY ) ;i f ( fd 1 < 0)

abandon ( ” O u v e r t u r e f i c h i e r 1 r e f u s e e ” ) ;

90fd 2 = open ( a r g v [ 2 ] , O RDONLY ) ;i f ( fd 2 < 0)

abandon ( ” O u v e r t u r e f i c h i e r 2 r e f u s e e ” ) ;

m i x e r ( fd1 , fd2 , 1 ) ;95

return EXIT SUCCESS ;}

9.2 Attente de donnees avec delai maximum

L’exemple suivant montre comment utiliser la limite de temps dans le cas (frequent) d’attente surun seul descripteur.

Une fonction utilitaire :

1/∗S e l e c t F i f o / AttenteDonnees . c

a t t e n t e de donnees p r o v e n a n t d ’ un d e s c r i p t e u r o u v e r t ,5avec d e l a i maximum

∗/

#inc lude <s y s / t ime . h>10#inc lude <s y s / t y p e s . h>

#inc lude <s y s / s t a t . h>#inc lude <u n i s t d . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

15#inc lude < f c n t l . h>

28

Page 29: Programmation Syst`eme et Réseau sous Unix

/∗f o n c t i o n a t t e n d r e d o n n e e s

20p a r a m e t r e s :− un d e s c r i p t e u r o u v e r t− une d u r e e d ’ a t t e n t e en m i l l i s e c o n d e s

r o l e : a t t e n d que des donn ees a r r i v e n t s u r l e d e s c r i p t e u r pendant25un c e r t a i n temps .

r e t o u r n e :1 s i des donn ees s o n t a r r i v e e s0 s i l e d e l a i e s t d e p a s s e

30−1 en c a s d ’ e r r e u r . V o i r v a r i a b l e e r r n o .∗/

i n t a t t e n d r e d o n n e e s ( i n t fd , i n t m i l l i s e c o n d e s )35{

f d s e t s e t ;s t r u c t t i m e v a l d e l a i ;

FD ZERO(& s e t ) ;40FD SET ( fd ,& s e t ) ;

d e l a i . t v s e c = m i l l i s e c o n d e s / 1 0 0 0 ;d e l a i . t v u s e c = ( m i l l i s e c o n d e s % 1000) ∗ 1 0 0 0 ;

return s e l e c t ( FD SETSIZE , &s e t , NULL , NULL , &d e l a i ) ;45}

Le programme principal :

1/∗S e l e c t F i f o / l e c t e u r . c

Exemple de l e c t u r e avec d e l a i ( t i m e o u t ) .5M. B i l l a u d , Septembre 2002

Ce programme a t t e n d des l i g n e s de t e x t e p r o v e n a n t d ’ une f i f o ,e t l e s a f f i c h e .En a t t e n d a n t de r e c e v o i r l e s l i g n e s , i l a f f i c h e une p e t i t e e t o i l e

10t o u r n a n t e ( par a f f i c h a g e s u c c e s s i f des sy m b o l e s − \ | e t / ) .

Exemple d ’ u t i l i s a t i o n :− c r e e r une f i f o : m k f i f o /tmp/ m a f i f o− dans une f e n e t r e , l a n c e r : l e c t e u r /tmp/ m a f i f o

15l e programme s e met en a t t e n t e− dans une a u t r e f e n e t r e , f a i r ec a t > /tmp/ m a f i f op u i s t a p e r q u e l q u e s l i g n e s de t e x t e .

20∗/

#inc lude <s y s / t ime . h>

29

Page 30: Programmation Syst`eme et Réseau sous Unix

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s t a t . h>

25#inc lude <u n i s t d . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>#inc lude < f c n t l . h>

30#def ine TAILLE TAMPON 100#def ine DELAI 500 /∗ m i l l i s e c o n d e s ∗/

extern i n t a t t e n d r e d o n n e e s ( i n t fd , i n t m i l l i s e c o n d e s ) ;35

i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t f d ;char symbole [ ] = ”−\\|−” ;

40i n t n = 0 ;i n t n u m e r o l i g n e = 1 ;

i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” Usage : %s f i f o \n” , a r g v [ 0 ] ) ;

45e x i t ( EXIT FAILURE ) ;}p r i n t f ( ”> O u v e r t u r e f i f o %s . . . \ n” , a r g v [ 1 ] ) ;f d = open ( a r g v [ 1 ] , O RDONLY ) ;i f ( f d == −1) {

50f p r i n t f ( s t d e r r , ” O u v e r t u r e r e f u s e e \n” ) ;e x i t ( EXIT FAILURE ) ;

} ;p r i n t f ( ”OK\n” ) ;

55f o r ( ; ; ) {i n t r = a t t e n d r e d o n n e e s ( fd , DELAI ) ;i f ( r == 0) {

/∗ d e l a i d epass e , on a f f i c h e un c a r a c t e r e s u i v ipar b a c k s p a c e ∗/

60p r i n t f ( ”%c\b” , symbole [ n++ % 4 ] ) ;f f l u s h ( s t d o u t ) ;

} e l s e {/∗ on a r e c u q u e l q u e chose ∗/char tampon [ TAILLE TAMPON ] ;

65i n t n b l u s ;n b l u s = r e a d ( fd , tampon , TAILLE TAMPON−1);i f ( n b l u s <= 0) break ;tampon [ n b l u s ]= ’ \0 ’ ;p r i n t f ( ”%4d %s ” , n u m e r o l i g n e ++, tampon ) ;

70}}c l o s e ( f d ) ;e x i t ( EXIT SUCCESS ) ;

}

30

Page 31: Programmation Syst`eme et Réseau sous Unix

10 Communication interprocessus par sockets locaux

Les sockets (prises) sont un moyen generique de faire communiquer des processus entre eux. C’est lemoyen standard utilise pour la communication sur le reseau Internet, mais on peut l’employer egalementpour la communication locale entre processus tournant sur une meme machine (commes les FIFOs etles pipes, et les files de messages IPC que nous verrons plus loin).

10.1 Creation d’un socket

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t s o c k e t ( i n t domain , i n t type , i n t p r o t o c o l ) ;

La fonction socket() cree une nouvelle prise et retourne un descripteur qui servira ensuite auxlectures et ecritures. Le parametre domain indique le � domaine de communication � utilise, qui estPF LOCAL ou (synonyme) PF UNIX pour les communications locales. 4

Le type indique le style de communication desire entre les deux participants. Les deux styles prin-cipaux sont

– SOCK DGRAM : communication par messages (blocs contenant des octets) appeles datagrammes– SOCK STREAM : la communication se fait par un flot (bidirectionnel) d’octets une fois que la

connection est etablie.Fiabilite : la fiabilite des communication par datagrammes est garantie pour le domaine local,

mais ce n’est pas le cas pour les domaines � reseau � que nous verrons plus loin : les datagrammespeuvent etre perdus, dupliques, arriver dans le desordre etc. et c’est au programmeur d’application d’entenir compte. Par contre la fiabilite des � streams � est assuree par les couches basses du systeme decommunication, evidemment au prix d’un surcout (numerotation des paquets, accuses de reception,temporisations, retranmissions, etc).

Enfin, le parametre protocol indique le protocole selectionne. La valeur 0 correspond au protocolepar defaut pour le domaine et le type indique.

10.2 Adresses

La fonction socket() cree un socket anonyme. Pour qu’un autre processus puisse le designer, ilfaut lui associer un nom par l’intermediaire d’une adresse contenue dans une structure sockaddr un :

#inc lude <s y s /un . h>

s t r u c t s o c k a d d r u n {s a f a m i l y t s u n f a m i l y ; /∗ AF UNIX ∗/char s u n p a t h [ UNIX PATH MAX ] ; /∗ pathname ∗/

} ;

Ces adresses sont des chemins d’acces dans l’arborescence des fichiers et repertoires.Exemple :

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>#inc lude <s y s /un . h>

s o c k l e n t l o n g u e u r a d r e s s e ;

4. Le domaine definit une famille de protocoles (protocol family) utilisables. Autres familles disponibles : PF INET

protocoles internet IPv4, PF INET6 protocoles internet IPv6, PF IPX protocoles Novel IPX, PF X25 protocoles X25 (ITU-TX.25 / ISO-8208), PF APPLETALKAppletalk, etc.

31

Page 32: Programmation Syst`eme et Réseau sous Unix

s t r u c t s o c k a d d r u n a d r e s s e ;

a d r e s s e . s u n f a m i l y = AF LOCAL ;s t r c p y ( a d r e s s e . sun path , ”/tmp/ xyz ” ) ;l o n g u e u r a d r e s s e = SUN LEN (&amp ; d r e s s e ) ;

L’association d’une adresse a un socket se fait par bind() (voir exemples plus loin).

10.3 Communication par datagrammes

Dans l’exemple developpe ici, un serveur affiche les datagrammes emis par les clients.

10.3.1 La reception de datagrammes

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t b i n d ( i n t s o c k f d , s t r u c t s o c k a d d r ∗my addr ,s o c k l e n t a d d r l e n ) ;

i n t r e c v f r o m ( i n t s , void ∗buf , s i z e t l e n , i n t f l a g s ,s t r u c t s o c k a d d r ∗ from , s o c k l e n t ∗ f r o m l e n ) ;

La fonction bind() permet de nommer le socket de reception. La fonction recvfrom() attendl’arrivee d’un datagramme qui est stocke dans les len premiers octets du tampon buff. Si from n’estpas NULL, l’adresse du socket emetteur 5 est placee dans la structure pointee par from, dont la longueurmaximale est contenue dans l’entier pointe par fromlen.

Si la lecture a reussi, la fonction retourne le nombre d’octets du message lu, et la longueur del’adresse est mise a jour.

Le parametre flags permet de preciser des options.

1/∗ LocalDatagrammes / s e r v e u r−dgram− l o c a l . c ∗/

/∗Usage : s e r v e u r−dgram− l o c a l chemin

5R e c o i t des datagrammes par un s o c k e t du domain l o c a l ,e t l e s a f f i c h e . Le pa ra me t re i n d i q u e l e nom du s o c k e t .S ’ a r r e t e quand l a donnee e s t ” s t o p ” .

∗/10

#inc lude <s t d i o . h>#inc lude <u n i s t d . h>#inc lude < s t d l i b . h>#inc lude <s y s / t y p e s . h>

15#inc lude <s y s / s o c k e t . h>#inc lude <s y s /un . h>

#def ine TAILLE MAX DONNEE 1024

20void abandon ( char message [ ] ){

p e r r o r ( message ) ;

5. qui peut servir a expedier une reponse

32

Page 33: Programmation Syst`eme et Réseau sous Unix

e x i t ( EXIT FAILURE ) ;}

25i n t main ( i n t argc , char ∗ a r g v [ ] ){

s o c k l e n t l o n g u e u r a d r e s s e ;s t r u c t s o c k a d d r u n a d r e s s e ;

30i n t f d ;

i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” usage : %s chemin\n” , a r g v [ 0 ] ) ;abandon ( ” mauvais nombre de p a r a m e t r e s ” ) ;

35}

a d r e s s e . s u n f a m i l y = AF LOCAL ;s t r c p y ( a d r e s s e . sun path , a r g v [ 1 ] ) ;l o n g u e u r a d r e s s e = SUN LEN (& a d r e s s e ) ;

40f d = s o c k e t (PF LOCAL ,SOCK DGRAM, 0 ) ;i f ( f d < 0)

abandon ( ” C r e a t i o n du s o c k e t s e r v e u r ” ) ;

45i f ( b i n d ( fd , ( s t r u c t s o c k a d d r ∗) &a d r e s s e , l o n g u e u r a d r e s s e ) <0)abandon ( ”Nommage du s o c k e t s e r v e u r ” ) ;

p r i n t f ( ”> S e r v e u r d emarr e s u r s o c k e t l o c a l \”%s \”\n” , a r g v [ 1 ] ) ;whi le ( 1 ) {

50i n t l g ;/∗ un c a r a c t e r e s u p p l e m e n t a i r e permet d ’ a j o u t e r l e

t e r m i n a t e u r de ch a ı n e , q u i n ’ e s t pas t r a n s m i s ∗/char tampon [ TAILLE MAX DONNEE +1] ;l g = r e c v f r o m ( fd , tampon , TAILLE MAX DONNEE , 0 , NULL , NULL ) ;

55i f ( l g <= 0)abandon ( ” R e c e p t i o n datagramme ” ) ;

tampon [ l g ] = ’ \0 ’ ; /∗ a j o u t t e r m i n a t e u r ∗/p r i n t f ( ” Recu : %s \n” , tampon ) ;i f ( st rcmp ( tampon , ” s t o p ” ) == 0) {

60p r i n t f ( ”> a r r e t demande\n” ) ;break ;

}}c l o s e ( f d ) ;

65u n l i n k ( a r g v [ 1 ] ) ;return EXIT SUCCESS ;

}

10.3.2 Emission de datagrammes

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t s e n d t o ( i n t s , const void ∗msg , s i z e t l e n , i n t f l a g s ,const s t r u c t s o c k a d d r ∗ to , s o c k l e n t t o l e n ) ;

33

Page 34: Programmation Syst`eme et Réseau sous Unix

sendto utilise le descripteur de socket s pour envoyer le message forme des len premiers octetsde msg a l’adresse de longueur tolen pointee par to.

Le meme descripteur peut etre utilise pour des envois a des adresses differentes.

1/∗ LocalDatagrammes / c l i e n t −dgram− l o c a l . c ∗/

/∗Usage : c l i e n t −dgram− l o c a l chemin messages

5E n v o i e des datagrammes a un s o c k e t du domain l o c a l ,e t l e s a f f i c h e . Le p r e m i e r pa ram e t re i n d i q u e l e nom du s o c k e t ,l e s a u t r e s des c h a ı n e s de c a r a c t e r e s .

10Exemple : c l i e n t −dgram− l o c a l un deux ” t r e n t e e t un” s t o p∗/

#inc lude <s t d i o . h>#inc lude <u n i s t d . h>

15#inc lude < s t d l i b . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>#inc lude <s y s /un . h>

20#def ine TAILLE MAX DONNEE 1024

void abandon ( char message [ ] ){

p e r r o r ( message ) ;25e x i t ( EXIT FAILURE ) ;

}

i n t main ( i n t argc , char ∗ a r g v [ ] ){

30s o c k l e n t l o n g u e u r a d r e s s e ;s t r u c t s o c k a d d r u n a d r e s s e ;i n t f d ;i n t k ;

35i f ( a r g c <= 2) {f p r i n t f ( s t d e r r , ” usage : %s chemin message\n” , a r g v [ 0 ] ) ;abandon ( ” mauvais nombre de p a r a m e t r e s ” ) ;

}

40a d r e s s e . s u n f a m i l y = AF LOCAL ;s t r c p y ( a d r e s s e . sun path , a r g v [ 1 ] ) ;l o n g u e u r a d r e s s e = SUN LEN (& a d r e s s e ) ;

f d = s o c k e t (PF LOCAL ,SOCK DGRAM, 0 ) ;45i f ( f d < 0)

abandon ( ” C r e a t i o n du s o c k e t c l i e n t ” ) ;

f o r ( k=2; k<a r g c ; k++) {i n t l g ;

50l g=s t r l e n ( a r g v [ k ] ) ;

34

Page 35: Programmation Syst`eme et Réseau sous Unix

i f ( l g > TAILLE MAX DONNEE)l g = TAILLE MAX DONNEE ;

/∗ l e message e s t envoy e s a n s l e t e r m i n a t e u r ’\0 ’ ∗/55i f ( s e n d t o ( fd , a r g v [ k ] , lg , 0 ,

( s t r u c t s o c k a d d r ∗) &a d r e s s e ,l o n g u e u r a d r e s s e ) < 0)

abandon ( ” E x p e d i t i o n du message ” ) ;

60p r i n t f ( ” . ” ) ;f f l u s h ( s t d o u t ) ;s l e e p ( 1 ) ;

}

65p r i n t f ( ”OK\n” ) ;c l o s e ( f d ) ;return EXIT SUCCESS ;

}

Exercice : modifier les programmes precedents pour que le serveur envoie une reponse qui seraaffichee par le client 6.10.3.3 Emission et reception en mode connecte

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t c o n n e c t ( i n t s o c k f d ,const s t r u c t s o c k a d d r ∗ s e r v a d d r ,s o c k l e n t a d d r l e n ) ;

i n t send ( i n t s , const void ∗msg , s i z e t l e n , i n t f l a g s ) ;i n t r e c v ( i n t s , void ∗buf , s i z e t l e n , i n t f l a g s ) ;

Un emetteur qui va envoyer une serie de messages au meme destinataire par le meme socket peutfaire prealablement un connect() pour indiquer une destination par defaut, et employer ensuite send()a la place de sendto().

Le recepteur qui ne s’interesse pas a l’adresse de l’envoyeur peut utiliser recv().Exercice : modifier les programmes precedents pour utiliser recv() et send().

10.4 Communication par flots

Dans ce type de communication, c’est une suite d’octets qui est transmises (et non pas une suitede messages comme dans la communication par datagrammes).

Les sockets locaux de ce type sont crees par

i n t f d = s o c k e t (PF LOCAL , SOCK STREAM , 0 ) ;

10.4.1 Architecture client-serveur

La plupart des applications communicantes sont concues selon une structure dissymetrique : l’ar-chitecture client-serveur, dans laquelle un processus serveur est contacte par plusieurs clients.

Le client cree un socket (socket()), qu’il met en relation (par connect()) avec celui du serveur.Les donnees sont echangees par read(), write() ... et le socket est ferme par close().

6. Penser a attribuer un nom au socket du client pour que le serveur puisse lui repondre, par exemple avec l’aide dela fonction tempnam().

35

Page 36: Programmation Syst`eme et Réseau sous Unix

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t c o n n e c t ( i n t s o c k f d ,const s t r u c t s o c k a d d r ∗ s e r v a d d r ,s o c k l e n t a d d r l e n ) ;

Du cote serveur : un socket est cree et une adresse lui est associee (socket() + bind()). Unlisten() previent le systeme que ce socket recevra des demandes de connexion, et precise le nombrede connexions que l’on peut mettre en file d’attente.

Le serveur attend les demandes de connexion par la fonction accept() qui renvoit un descripteur,lequel permet la communication avec le client.

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t b i n d ( i n t s o c k f d ,s t r u c t s o c k a d d r ∗my addr ,s o c k l e n t a d d r l e n ) ;

i n t l i s t e n ( i n t s , i n t b a c k l o g ) ;

i n t a c c e p t ( i n t s ,s t r u c t s o c k a d d r ∗addr ,s o c k l e n t ∗ a d d r l e n ) ;

Remarque : il est possible ne fermer qu’une “moitie” de socket : shutdown(1) met fin aux emissions(causant une “fin de fichier” chez le correspondant), shutdown(0) met fin aux receptions.

#inc lude <s y s / s o c k e t . h>

i n t shutdown ( i n t s , i n t how ) ;

Le client :

1/∗Loca lSt ream / c l i e n t −s t ream . c

Envo i / r e c e p t i o n de donnees par un s o c k e t l o c a l ( mode c o n n e c t e )5

Exemple de c l i e n t q u i− o u v r e un s o c k e t− e n v o i e s u r ce s o c k e t du t e x t e l u s u r l ’ e n t r e e s t a n d a r d− a t t e n d e t a f f i c h e une r e p o n s e

10∗/

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

15#inc lude <s y s /un . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude < s t r i n g . h>#inc lude < s t d l i b . h>

20#def ine TAILLE TAMPON 1000

36

Page 37: Programmation Syst`eme et Réseau sous Unix

void abandon ( char message [ ] ){

25p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

i n t main ( i n t argc , char ∗ a r g v [ ] )30{

char ∗ chemin ; /∗ chemin d ’ a c c e s du s o c k e t s e r v e u r ∗/s o c k l e n t l o n g u e u r a d r e s s e ;s t r u c t s o c k a d d r u n a d r e s s e ;i n t f d ;

35/∗ 1 . r e c e p t i o n des p a r a m e t r e s de l a l i g n e de commande ∗/i f ( a r g c != 2) {

p r i n t f ( ” Usage : %s chemin\n” , a r g v [ 0 ] ) ;abandon ( ” Mauvais nombre de p a r a m e t r e s ” ) ;

40}chemin = a r g v [ 1 ] ;

/∗ 2 . I n i t i a l i s a t i o n du s o c k e t ∗/

45/∗ 2 . 1 c r e a t i o n du s o c k e t ∗/f d = s o c k e t (PF LOCAL , SOCK STREAM, 0 ) ;i f ( f d < 0)

abandon ( ” C r e a t i o n du s o c k e t c l i e n t ” ) ;

50/∗ 2 . 2 R e m p l i s s a g e a d r e s s e s e r v e u r ∗/a d r e s s e . s u n f a m i l y = AF LOCAL ;s t r c p y ( a d r e s s e . sun path , chemin ) ;l o n g u e u r a d r e s s e = SUN LEN(& a d r e s s e ) ;

55/∗ 2 . 3 c o n n e x i o n au s e r v e u r ∗/i f ( c o n n e c t ( fd , ( s t r u c t s o c k a d d r ∗) &a d r e s s e , l o n g u e u r a d r e s s e )

< 0)abandon ( ” c o n n e c t ” ) ;

60p r i n t f ( ”CLIENT> Connex ion e t a b l i e \n” ) ;

/∗ 3 . L e c t u r e e t e n v o i des donn ees ∗/f o r ( ; ; ) {

char tampon [ TAILLE TAMPON ] ;65i n t n b l u s , n b e n v o y e s ;

n b l u s = r e a d ( 0 , tampon , TAILLE TAMPON ) ;i f ( n b l u s <= 0)

break ;70n b e n v o y e s = w r i t e ( fd , tampon , n b l u s ) ;

i f ( n b e n v o y e s != n b l u s )abandon ( ” e n v o i donn ees ” ) ;

}/∗ 4 . F in de l ’ e n v o i ∗/

75shutdown ( fd , 1 ) ;p r i n t f ( ”CLIENT> Fin e n v o i , a t t e n t e de l a r e p o n s e .\ n” ) ;

37

Page 38: Programmation Syst`eme et Réseau sous Unix

/∗ 5 . R e c e p t i o n e t a f f i c h a g e de l a r e p o n s e ∗/f o r ( ; ; ) {

80char tampon [ TAILLE TAMPON ] ;i n t n b l u s ;n b l u s = r e a d ( fd , tampon , TAILLE TAMPON − 1 ) ;i f ( n b l u s <= 0)

break ;85tampon [ n b l u s ] = ’ \0 ’ ; /∗ a j o u t d ’ un t e r m i n a t e u r de c h a ı n e ∗/

p r i n t f ( ”%s ” , tampon ) ;}/∗ e t f i n ∗/c l o s e ( f d ) ;

90p r i n t f ( ”CLIENT> Fin .\ n” ) ;return EXIT SUCCESS ;

}

Le serveur est programme ici de facon atypique, puisqu’il traite qu’il traıte une seule communicationa la fois. Si le client fait traıner les choses, les autres clients en attente resteront bloques longtemps.

1/∗Loca lSt ream / s e r v e u r−s t ream . c

Envo i / r e c e p t i o n de donnees par un s o c k e t l o c a l ( mode c o n n e c t e )5

Exemple de s e r v e u r q u i− a t t e n d une c o n n e x i o n− l i t du t e x t e− e n v o i e une r e p o n s e

10Remarques− ce s e r v e u r ne t r a i t e qu ’ une c o n n e x i o n a l a f o i s .− I l ne s ’ a r r e t e j a m a i s .∗/

15

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

20#inc lude <s y s /un . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>#inc lude <c t y p e . h>

25#def ine TAILLE TAMPON 1000#def ine MAX CONNEXIONS EN ATTENTE 4

void abandon ( char message [ ] )30{

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

38

Page 39: Programmation Syst`eme et Réseau sous Unix

35i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t f d s e r v e u r ;s t r u c t s o c k a d d r u n a d r e s s e ;s i z e t t a i l l e a d r e s s e ;

40char ∗ chemin ;char tampon [ TAILLE TAMPON ] ;i n t n b c a r ;i n t numero connex ion = 0 ;

45/∗ 1 . r e c e p t i o n des p a r a m e t r e s de l a l i g n e de commande ∗/

i f ( a r g c != 2) {p r i n t f ( ” usage : %s chemin\n” , a r g v [ 0 ] ) ;abandon ( ” Mauvais nombrede p a r a m e t r e s ” ) ;

50}chemin = a r g v [ 1 ] ;

/∗ 3 . I n i t i a l i s a t i o n du s o c k e t de r e c e p t i o n ∗//∗ 3 . 1 c r e a t i o n du s o c k e t ∗/

55f d s e r v e u r = s o c k e t (PF LOCAL , SOCK STREAM, 0 ) ;i f ( f d s e r v e u r < 0)

abandon ( ” C r e a t i o n du s o c k e t s e r v e u r ” ) ;

/∗ 3 . 2 R e m p l i s s a g e a d r e s s e s e r v e u r ∗/60a d r e s s e . s u n f a m i l y = AF LOCAL ;

s t r c p y ( a d r e s s e . sun path , chemin ) ;t a i l l e a d r e s s e = SUN LEN(& a d r e s s e ) ;

/∗ 3 . 3 A s s o c i a t i o n de l ’ a d r e s s e au s o c k e t ∗/65t a i l l e a d r e s s e = s i z e o f a d r e s s e ;

i f ( b i n d ( f d s e r v e u r , ( s t r u c t s o c k a d d r ∗) &a d r e s s e , t a i l l e a d r e s s e ) < 0)abandon ( ” b i n d ” ) ;

/∗ 3 . 4 Ce s o c k e t a t t e n d des c o n n e x i o n s m i s e s en f i l e d ’ a t t e n t e ∗/70l i s t e n ( f d s e r v e u r , MAX CONNEXIONS EN ATTENTE ) ;

p r i n t f ( ”SERVEUR> Le s e r v e u r e c o u t e l e s o c k e t %s \n” , chemin ) ;

/∗ 4 . b o u c l e du s e r v e u r ∗/75f o r ( ; ; ) {

i n t f d c l i e n t ;i n t compteur = 0 ;

/∗ 4 . 1 a t t e n t e d ’ une c o n n e x i o n ∗/80p r i n t f ( ”SERVEUR> A t t e n t e d ’ une c o n n e x i o n .\ n” ) ;

f d c l i e n t = a c c e p t ( f d s e r v e u r , NULL , NULL ) ;i f ( f d c l i e n t < 0)

abandon ( ” a c c e p t ” ) ;

85numero connex ion++;p r i n t f ( ”SERVEUR> Connex ion #%d e t a b l i e .\ n” , numero connex ion ) ;

/∗ 4 . 2 l e c t u r e e t a f f i c h a g e des donn ees e n v o y e e s par l e c l i e n t ∗/

39

Page 40: Programmation Syst`eme et Réseau sous Unix

f o r ( ; ; ) {90i n t n b l u s ;

n b l u s = r e a d ( f d c l i e n t , tampon , TAILLE TAMPON − 1 ) ;i f ( n b l u s <= 0)

break ;compteur += n b l u s ;

95tampon [ n b l u s ] = ’ \0 ’ ;p r i n t f ( ”%s ” , tampon ) ;

}

/∗ 4 . 4 p l u s de donnees , on e n v o i t une r e p o n s e ∗/100p r i n t f ( ”SERVEUR> e n v o i de l a r e p o n s e .\ n” ) ;

n b c a r = s p r i n t f ( tampon , ”∗∗∗ Fin de l a c o n n e x i o n #%d\n” ,numero connex ion ) ;

w r i t e ( f d c l i e n t , tampon , n b c a r ) ;n b c a r = s p r i n t f ( tampon , ”∗∗∗ Vous m’ avez envoy e %d c a r a c t e r e s \n” ,

105compteur ) ;w r i t e ( f d c l i e n t , tampon , n b c a r ) ;n b c a r = s p r i n t f ( tampon , ”∗∗∗ Merc i e t a b i e n t o t .\ n” ) ;w r i t e ( f d c l i e n t , tampon , n b c a r ) ;

110/∗ 4 . 4 f e r m e t u r e de l a c o n n e x i o n ∗/c l o s e ( f d c l i e n t ) ;p r i n t f ( ”SERVEUR> f i n de c o n n e x i o n .\ n” ) ;

}115

/∗ on ne p a s s e j a m a i s i c i ∗/return EXIT SUCCESS ;

}

Dans une programmation plus classique, le serveur lance un processus (par fork(), voir plus loin)des qu’une connexion est etablie, et delegue le traitement de la connexion a ce processus.

Une autre technique est envisageable pour traiter plusieurs connexions par un processus unique :le serveur maintient une liste de descripteurs ouverts, et fait une boucle autour d’un select(), enattente de donnees venant

– soit du descripteur “principal” ouvert par le serveur. Dans ce cas il effectue ensuite unaccept(...) qui permettra d’ajouter un nouveau client a la liste.

– soit d’un des descripteurs des clients, et il traite alors les donnees venant de ce client (il l’enlevede la liste en fin de communication).

Cette technique conduit a des performances nettement superieures aux serveurs multiprocessus oumultithreads (pas de temps perdu a lancer des processus), au prix d’une programmation qui oblige leprogrammeur a gerer lui-meme le “contexte de deroulement” de chaque processus.

1/∗Loca lSt ream / s e r v e u r−stream−monotache . c

Envo i / r e c e p t i o n de donnees par un s o c k e t l o c a l ( mode c o n n e c t e )5

Exemple de s e r v e u r monotache q u i g e r e p l u s i e u r s c o n n e x i o n s

− a t t e n d une c o n n e x i o n− l i t du t e x t e

10− e n v o i e une r e p o n s e

40

Page 41: Programmation Syst`eme et Réseau sous Unix

∗/

#inc lude <u n i s t d . h>15#inc lude <s y s / t y p e s . h>

#inc lude <s y s / s o c k e t . h>#inc lude <s y s /un . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>

20#inc lude < s t d l i b . h>#inc lude <c t y p e . h>#inc lude <a s s e r t . h>

25#def ine TAILLE TAMPON 1000#def ine MAX CONNEXIONS EN ATTENTE 4#def ine MAX CLIENTS 10

/∗ l e s donn ees p r o p r e s a chaque c l i e n t ∗/30

#def ine INACTIF −1s t r u c t {

i n t f d ;i n t numero connex ion ;

35i n t compteur ;} c l i e n t [ MAX CLIENTS ] ;

void abandon ( char message [ ] ){

40p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

i n t main ( i n t argc , char ∗ a r g v [ ] )45{

i n t f d s e r v e u r ;s t r u c t s o c k a d d r u n a d r e s s e ;s i z e t t a i l l e a d r e s s e ;char ∗ chemin ;

50i n t n b c o n n e x i o n s = 0 ;i n t i ;i n t nbfd ;

55/∗ 1 . r e c e p t i o n des p a r a m e t r e s de l a l i g n e de commande ∗/

i f ( a r g c != 2) {p r i n t f ( ” usage : %s chemin\n” , a r g v [ 0 ] ) ;abandon ( ” mauvais nombre de p a r a m e t r e s ” ) ;

60}chemin = a r g v [ 1 ] ;

/∗ 3 . I n i t i a l i s a t i o n du s o c k e t de r e c e p t i o n ∗//∗ 3 . 1 c r e a t i o n du s o c k e t ∗/

41

Page 42: Programmation Syst`eme et Réseau sous Unix

65f d s e r v e u r = s o c k e t (PF LOCAL , SOCK STREAM, 0 ) ;i f ( f d s e r v e u r < 0)

abandon ( ” C r e a t i o n du s o c k e t s e r v e u r ” ) ;

/∗ 3 . 2 R e m p l i s s a g e a d r e s s e s e r v e u r ∗/70a d r e s s e . s u n f a m i l y = AF LOCAL ;

s t r c p y ( a d r e s s e . sun path , chemin ) ;t a i l l e a d r e s s e = SUN LEN(& a d r e s s e ) ;

/∗ 3 . 3 A s s o c i a t i o n de l ’ a d r e s s e au s o c k e t ∗/75t a i l l e a d r e s s e = s i z e o f a d r e s s e ;

i f ( b i n d ( f d s e r v e u r , ( s t r u c t s o c k a d d r ∗) &a d r e s s e , t a i l l e a d r e s s e ) < 0)abandon ( ” b i n d ” ) ;

/∗ 3 . 4 Ce s o c k e t a t t e n d des c o n n e x i o n s m i s e s en f i l e d ’ a t t e n t e ∗/80l i s t e n ( f d s e r v e u r , MAX CONNEXIONS EN ATTENTE ) ;

p r i n t f ( ”SERVEUR> Le s e r v e u r e c o u t e l e s o c k e t %s \n” , chemin ) ;

/∗ 3 . 5 i n i t i a l i s a t i o n du t a b l e a u des c l i e n t s ∗/85f o r ( i = 0 ; i < MAX CLIENTS ; i ++) {

c l i e n t [ i ] . f d = INACTIF ;}

90/∗ 4 . b o u c l e du s e r v e u r ∗/

f o r ( ; ; ) {f d s e t l e c t u r e s ;

95/∗ 4 . 1 r e m p l i s s a g e des masques du s e l e c t ∗/FD ZERO(& l e c t u r e s ) ;FD SET ( f d s e r v e u r , &l e c t u r e s ) ;f o r ( i = 0 ; i < MAX CLIENTS ; i ++) {

i f ( c l i e n t [ i ] . f d != INACTIF )100FD SET ( c l i e n t [ i ] . fd , &l e c t u r e s ) ;

}

/∗ 4 . 2 a t t e n t e d ’ un ev enement ( ou p l u s i e u r s ) ∗/nbfd = s e l e c t ( FD SETSIZE , &l e c t u r e s , NULL , NULL , NULL ) ;

105a s s e r t ( nbfd >= 0 ) ;

/∗ 4 . 3 en c a s de n o u v e l l e c o n n e x i o n : ∗/i f ( FD ISSET ( f d s e r v e u r , &l e c t u r e s ) ) {

/∗ s i i l y a de l a p l a c e dans l a t a b l e des c l i e n t s ,110on y a j o u t e l a n o u v e l l e c o n n e x i o n ∗/

nbfd−−;f o r ( i = 0 ; i < MAX CLIENTS ; i ++) {

i f ( c l i e n t [ i ] . f d == INACTIF ) {i n t f d c l i e n t ;

115f d c l i e n t = a c c e p t ( f d s e r v e u r , NULL , NULL ) ;i f ( f d c l i e n t < 0)

abandon ( ” a c c e p t ” ) ;

42

Page 43: Programmation Syst`eme et Réseau sous Unix

c l i e n t [ i ] . f d = f d c l i e n t ;120c l i e n t [ i ] . numero connex ion = ++n b c o n n e x i o n s ;

c l i e n t [ i ] . compteur = 0 ;p r i n t f ( ”SERVEUR> a r r i v e e de c o n n e x i o n #%d ( f d %d )\n” ,

c l i e n t [ i ] . numero connex ion , f d c l i e n t ) ;break ;

125}i f ( i >= MAX CLIENTS) {

p r i n t f ( ”SERVEUR> t r o p de c o n n e x i o n s !\ n” ) ;}

}130} ;

/∗ 4 . 4 t r a i t e m e n t des c l i e n t s a c t i f s q u i ont r e c u des donn ees ∗/f o r ( i = 0 ; ( i < MAX CLIENTS) && ( nbfd > 0 ) ; i ++) {

i f ( ( c l i e n t [ i ] . f d != INACTIF ) &&135FD ISSET ( c l i e n t [ i ] . fd , &l e c t u r e s ) ) {

i n t n b l u s ;char tampon [ TAILLE TAMPON ] ;nbfd−−;n b l u s = r e a d ( c l i e n t [ i ] . fd , tampon , TAILLE TAMPON − 1 ) ;

140p r i n t f ( ”SERVEUR> donnees r e c u e s de #%d (%d o c t e t s )\n” ,c l i e n t [ i ] . numero connex ion , n b l u s ) ;

i f ( n b l u s > 0)c l i e n t [ i ] . compteur += n b l u s ;

e l s e {145i n t n b c a r ;

p r i n t f ( ”SERVEUR> e n v o i de l a r e p o n s e au c l i e n t #%d .\ n” ,c l i e n t [ i ] . numero connex ion ) ;

n b c a r =s p r i n t f ( tampon , ”∗∗∗ Fin de l a c o n n e x i o n #%d\n” ,

150c l i e n t [ i ] . numero connex ion ) ;w r i t e ( c l i e n t [ i ] . fd , tampon , n b c a r ) ;n b c a r =

s p r i n t f ( tampon ,”∗∗∗ Vous m’ avez envoy e %d c a r a c t e r e s \n” ,

155c l i e n t [ i ] . compteur ) ;w r i t e ( c l i e n t [ i ] . fd , tampon , n b c a r ) ;n b c a r = s p r i n t f ( tampon , ”∗∗∗ Merc i e t a b i e n t o t .\ n” ) ;w r i t e ( c l i e n t [ i ] . fd , tampon , n b c a r ) ;c l o s e ( c l i e n t [ i ] . f d ) ;

160/∗ e n l e v e m e n t de l a l i s t e des c l i e n t s ∗/c l i e n t [ i ] . f d = INACTIF ;

}}

}165a s s e r t ( nbfd == 0 ) ; /∗ t o u s l e s d e s c r i p t e u r s ont e t e t r a i t e s ∗/

}/∗ on ne p a s s e j a m a i s i c i ( b o u c l e s a n s f i n ) ∗/return EXIT SUCCESS ;

}

43

Page 44: Programmation Syst`eme et Réseau sous Unix

10.5 socketpair()

La fonction socketpair() construit une paire de sockets locaux, bi-directionnels, relies l’un al’autre.

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t s o c k e t p a i r ( i n t d , i n t type , i n t p r o t o c o l , i n t sv [ 2 ] ) ;

Dans l’etat actuel des implementations, le parametre d (domaine) doit etre egal a AF LOCAL, ettype a SOCK DGRAM ou SOCK STREAM, avec le protocole par defaut (valeur 0).

Cette fonction remplit le tableau sv[] avec les descripteurs de deux sockets du type indique. Cesdeux sockets sont relies entre eux et bidirectionnels : ce qu’on ecrit sur le descripteur sv[0] peut etrelu sur sv[1], et reciproquement.

On utilise socketpair() comme pipe(), pour la communication entre descendants d’un memeprocessus 7. socketpair() possede deux avantages sur pipe() : la possibilite de transmettre desdatagrammes, et la bidirectionnalite.

Exemple :

1/∗p a i r e−send . c

echange de donnees a t r a v e r s des s o c k e t s l o c a u x c r e e s par5s o c k e t p a i r ( )

∗/

#inc lude <u n i s t d . h>#inc lude <s t d i o . h>

10#inc lude < s t d l i b . h>#inc lude <s y s / s o c k e t . h>#inc lude <s y s / t y p e s . h>

s t r u c t paquet {15i n t t y p e ;

i n t v a l e u r ;} ;

/∗ l e s d i f f e r e n t s t y p e s de p a q u e t s ∗/20

#def ine DONNEE 0#def ine RESULTAT 1#def ine FIN 2

25void abandon ( char message [ ] ){

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}30

i n t a d d i t i o n n e u r ( i n t f d ){

/∗c a l c u l e l a somme des e n t i e r s q u i a r r i v e n t s u r l e d e s c r i p t e u r ,

7. au sens large, ce qui inclue la communication d’un processus avec un de ses fils

44

Page 45: Programmation Syst`eme et Réseau sous Unix

35r e n v o i e l e r e s u l t a t∗/

i n t somme = 0 ;s t r u c t paquet p ;i n t n ;

40f o r ( ; ; ) {

n = r e c v ( fd , &p , s i z e o f p , 0 ) ;i f ( n < 0)

abandon ( ” r e c v ” ) ;45p r i n t f ( ” a d d i t i o n n e u r : r e c e p t i o n d ’ un paquet c o n t e n a n t ” ) ;

i f ( p . t y p e == FIN ) {p r i n t f ( ” l a marque de f i n \n” ) ;break ;

}50p r i n t f ( ” l a donnee %d\n” , p . v a l e u r ) ;

somme += p . v a l e u r ;} ;/∗ e n v o i r e p o n s e ∗/p . t y p e = RESULTAT ;

55p . v a l e u r = somme ;p r i n t f ( ” a d d i t i o n n e u r : e n v o i du t o t a l %d\n” , somme ) ;n = send ( fd , &p , s i z e o f p , 0 ) ;i f ( n < 0)

abandon ( ” a d d i t i o n n e u r : send ” ) ;60return EXIT SUCCESS ;

}

i n t g e n e r a t e u r ( i n t f d ){

65/∗e n v o i e une s u i t e d ’ e n t i e r s , r e c u p e r e e t a f f i c h e l e r e s u l t a t .

∗/s t r u c t paquet p ;i n t i , n , r e s u l t a t ;

70f o r ( i = 1 ; i <= 5 ; i ++) {

p . t y p e = DONNEE;p . v a l e u r = i ;p r i n t f ( ” g e n e r a t e u r : e n v o i de l a donnee %d\n” , i ) ;

75n = send ( fd , &p , s i z e o f p , 0 ) ;i f ( n < 0)

abandon ( ” g e n e r a t e u r : send ” ) ;s l e e p ( 1 ) ;

} ;80p . t y p e = FIN ;

p r i n t f ( ” g e n e r a t e u r : e n v o i de l a marque de f i n \n” ) ;n = send ( fd , &p , s i z e o f p , 0 ) ;i f ( n < 0)

abandon ( ” g e n e r a t e u r : send ” ) ;85

p r i n t f ( ” g e n e r a t e u r : l e c t u r e du r e s u l t a t \n” ) ;n = r e c v ( fd , &p , s i z e o f p , 0 ) ;i f ( n < 0)

45

Page 46: Programmation Syst`eme et Réseau sous Unix

abandon ( ” g e n e r a t e u r : r e c v ” ) ;90r e s u l t a t = p . v a l e u r ;

p r i n t f ( ” g e n e r a t e u r : r e s u l t a t r e c u = %d\n” , r e s u l t a t ) ;return EXIT SUCCESS ;

}

95i n t main ( ){

i n t p a i r e s o c k e t s [ 2 ] ;

s o c k e t p a i r (AF LOCAL , SOCK DGRAM, 0 , p a i r e s o c k e t s ) ;100

i f ( f o r k ( ) == 0) {c l o s e ( p a i r e s o c k e t s [ 0 ] ) ;return a d d i t i o n n e u r ( p a i r e s o c k e t s [ 1 ] ) ;

} e l s e {105c l o s e ( p a i r e s o c k e t s [ 1 ] ) ;

return g e n e r a t e u r ( p a i r e s o c k e t s [ 0 ] ) ;}

}

11 Processus

11.1 fork(), wait()

#inc lude <u n i s t d . h>p i d t f o r k ( void ) ;p i d t w a i t ( i n t ∗ s t a t u s )

La fonction fork() cree un nouveau processus (fils) semblable au processus courant (pere). Lavaleur renvoyee n’est pas la meme pour le fils (0) et pour le pere (numero de processus du fils). -1indique un echec.

La fonction wait() attend qu’un des processus fils soit termine. Elle renvoie le numero du fils, etson status (voir exit()) en parametre passe par adresse.

Attention. Le processus fils herite des descripteurs ouverts de son pere. Il convient que chacundes processus ferme les descripteurs qui ne le concernent pas.

Exemple :

1/∗ D i v e r s / b i p r o c . c ∗/

/∗∗ I l l u s t r a t i o n de f o r k ( ) e t p i p e ( ) ;

5∗∗ Exemple a deux p r o c e s s u s r e l i e s par un tuyau− l ’ un e n v o i e a b c d e f . . . z 10 f o i s dans l e tuyau− l ’ a u t r e e c r i t ce q u i l u i a r r i v e du tuyau s u r l as o r t i e s t a n d a r d , en l e f o r m a t t a n t .

10∗/

#inc lude <u n i s t d . h>#inc lude < s t d l i b . h>#inc lude <s t d i o . h>

15#inc lude <s y s / t y p e s . h>

46

Page 47: Programmation Syst`eme et Réseau sous Unix

#inc lude <s y s / w a i t . h>

#def ine TAILLE LIGNE 30#def ine TAILLE ALPHABET 26

20#def ine NOMBRE REPETITIONS 10

void abandon ( char r a i s o n [ ] ){

p e r r o r ( r a i s o n ) ;25e x i t ( EXIT FAILURE ) ;

}

void e n v o y e r d o n n e e s ( i n t s o r t i e ){

30char a l p h a b e t [ TAILLE ALPHABET ] ;i n t k ;

f o r ( k=0; k<TAILLE ALPHABET ; k++) {a l p h a b e t [ k ] = ’ a ’+k ;

35}

f o r ( k=0; k < NOMBRE REPETITIONS ; k++)i f ( w r i t e ( s o r t i e , a l p h a b e t , TAILLE ALPHABET)

!= TAILLE ALPHABET) {40abandon ( ” w r i t e ” ) ;

}c l o s e ( s o r t i e ) ;

}

45i n t l i r e d o n n e e s ( i n t fd , char ∗tampon , s i z e t t a i l l e t a m p o n ){

/∗ l e c t u r e , en i n s i s t a n t pour r e m p l i r l e tampon ∗/i n t d e j a l u s =0;i n t n ;

50whi le ( d e j a l u s < t a i l l e t a m p o n ) {

n = r e a d ( fd , tampon+d e j a l u s , t a i l l e t a m p o n−d e j a l u s ) ;i f ( n < 0) return (−1);i f ( n == 0) break ; /∗ p l u s r i e n a l i r e ∗/

55d e j a l u s += n ;}return d e j a l u s ;

}

60void r e c e v o i r d o n n e e s ( i n t e n t r e e ){

char l i g n e [ TAILLE LIGNE +1] ;i n t nb , n u m e r o l i g n e =1;

65whi le ( ( nb = l i r e d o n n e e s ( e n t r e e , l i g n e , TAILLE LIGNE ) ) > 0) {l i g n e [ nb ] = ’ \0 ’ ;p r i n t f ( ”%3d %s \n” , n u m e r o l i g n e ++, l i g n e ) ;

} ;i f ( nb < 0) {

47

Page 48: Programmation Syst`eme et Réseau sous Unix

70abandon ( ” r e a d ” ) ;}c l o s e ( e n t r e e ) ;

}

75i n t main ( void ){

i n t f d [ 2 ] , s t a t u s ;p i d t f i l s ;

80i f ( p i p e ( f d ) != 0)abandon ( ” Echec c r e a t i o n p i p e ” ) ;

i f ( ( f i l s = f o r k ( ) ) < 0)abandon ( ” echec f o r k ” ) ;

85i f ( f i l s == 0) {

/∗ l e p r o c e s s u s f i l s ∗/c l o s e ( f d [ 0 ] ) ;c l o s e ( 1 ) ;

90e n v o y e r d o n n e e s ( f d [ 1 ] ) ;

} e l s e {/∗ l e p r o c e s s u s p e r e c o n t i n u e i c i ∗/c l o s e ( 0 ) ;

95c l o s e ( f d [ 1 ] ) ;

r e c e v o i r d o n n e e s ( f d [ 0 ] ) ;

w a i t (& s t a t u s ) ;100p r i n t f ( ” s t a t u s f i l s = %d\n” , s t a t u s ) ;

}return EXIT SUCCESS ;

}

Exercice : Observez ce qui se passe si, dans la fonction affiche(), on remplace l’appel a lire()

par un read() ? Et si on ne fait pas le wait() ?

11.2 waitpid()

La fonction waitpid() permet d’attendre l’arret d’un des processus fils designe par son pid (n’im-porte lequel si pid=-1), et de recuperer eventuellement son code de retour. Elle retourne le numero duprocessus fils.

L’option WNOHANG rend waitpid non bloquant (qui retourne alors -1 si le processus attendu n’estpas termine).

#inc lude <s y s / t y p e s . h>#inc lude <s y s / w a i t . h>

p i d t w a i t p i d ( p i d t p id , i n t ∗ s t a t u s , i n t o p t i o n s ) ;

Exemple :

i n t p i d f i l s ;i n t s t a t u s ;

i f ( ( p i d f i l s = f o r k ( ) ) != 0) {

48

Page 49: Programmation Syst`eme et Réseau sous Unix

c o d e p r o c e s s u s f i l s ( ) ;e x i t ( EXIT SUCCESS ) ;} ;

. . .i f ( w a i t p i d ( p i d f i l s , NULL ,WMNOHANG) == −1)

p r i n t f ( ” Le p r o c e s s u s f i l s n ’ e s t pas e n c o r e t e r m i n e \n” ) ;. . .

11.3 exec()

#inc lude <u n i s t d . h>i n t e x e c v ( const char ∗FILENAME , char ∗const ARGV [ ] )i n t e x e c l ( const char ∗FILENAME , const char ∗ARG0 , . . . )i n t e x e c v e ( const char ∗FILENAME , char ∗const ARGV [ ] , char ∗const ENV [ ] )i n t e x e c l e ( const char ∗FILENAME , const char ∗ARG0 , . . . char ∗const ENV [ ] )i n t execvp ( const char ∗FILENAME , char ∗const ARGV [ ] )i n t e x e c l p ( const char ∗FILENAME , const char ∗ARG0 , . . . )

Ces fonctions font toutes la meme chose : activer un executable a la place du processus courant.Elles different par la maniere d’indiquer les parametres.

– execv() : les parametres de la commande sont transmis sous forme d’un tableau de pointeurssur des chaınes de caracteres (le dernier etant NULL). Exemple :

1/∗ D i v e r s / e x e c v . c ∗/

#inc lude <u n i s t d . h>#inc lude <s t d i o . h>

5#inc lude < s t d l i b . h>

#def ine CHEMIN COMPILATEUR ”/ u s r / b i n / gcc ”#def ine NOM COMPILATEUR ” gcc ”#def ine TAILLE MAX PREFIXE 10

10#def ine TAILLE MAX NOMFICHIER 100

i n t main ( void ){

15char p r e f i x e [ TAILLE MAX PREFIXE ] ;char nom source [ TAILLE MAX NOMFICHIER ] ;

char ∗ p a r a m e t r e s [ ] = {NOM COMPILATEUR,

20NULL , /∗ exmplacement pour l e nom du f i c h i e r s o u r c e ∗/”−o” ,NULL , /∗ emplacement pour l e nom de l ’ e x e c u t a b l e ∗/NULL /∗ f i n des p a r a m e t r e s ∗/

} ;25

p r i n t f ( ” p r e f i x e du f i c h i e r a c o m p i l e r : ” ) ;s c a n f ( ”%s ” , p r e f i x e ) ; /∗ dangereux ∗/

s n p r i n t f ( nom source , TAILLE MAX NOMFICHIER ,30”%s . c ” , p r e f i x e ) ;

49

Page 50: Programmation Syst`eme et Réseau sous Unix

p a r a m e t r e s [ 1 ] = nom source ;p a r a m e t r e s [ 3 ] = p r e f i x e ;

35e x e c v (CHEMIN COMPILATEUR , p a r a m e t r e s ) ;

p e r r o r ( ” e x e c v ” ) ; /∗ normalement on ne p a s s e pas i c i ∗/return EXIT FAILURE ;

}

– execl() recoit un nombre variable de parametres. Le dernier est NULL). Exemple :

1/∗ D i v e r s / e x e c l . c ∗/

#inc lude <u n i s t d . h>#inc lude <s t d i o . h>

5#inc lude < s t d l i b . h>

#def ine CHEMIN COMPILATEUR ”/ u s r / b i n / gcc ”#def ine NOM COMPILATEUR ” gcc ”#def ine TAILLE MAX PREFIXE 10

10#def ine TAILLE MAX NOMFICHIER 100

i n t main ( void ){

15char p r e f i x e [ TAILLE MAX PREFIXE ] ;char n o m f i c h i e r [ TAILLE MAX NOMFICHIER ] ;

p r i n t f ( ” P r e f i x e du f i c h i e r a c o m p i l e r : ” ) ;s c a n f ( ”%s ” , p r e f i x e ) ; /∗ dangereux ∗/

20s n p r i n t f ( n o m f i c h i e r , TAILLE MAX NOMFICHIER ,

”%s . c ” , p r e f i x e ) ;

e x e c l (CHEMIN COMPILATEUR ,25NOM COMPILATEUR,

n o m f i c h i e r , ”−o” , p r e f i x e ,NULL ) ;

p e r r o r ( ” e x e c l ” ) ; /∗ on ne p a s s e j a m a i s i c i ∗/30return EXIT FAILURE ;

}

– execve() et execle() ont un parametre supplementaire pour preciser l’environnement.– execvp() et execlp() utilisent la variable d’environnement PATH pour localiser l’executable a

lancer. On pourrait donc ecrire simplement :

e x e c l p ( ” gcc ” , ” gcc ” , f i c h i e r , ”−o” , p r e f i x e , NULL ) ;

11.4 Numeros de processus : getpid(), getppid()

#inc lude <u n i s t d . h>p i d t g e t p i d ( void ) ;p i d t g e t p p i d ( void ) ;

50

Page 51: Programmation Syst`eme et Réseau sous Unix

getpid() permet a un processus de connaıtre son propre numero, et getppid() celui de son pere.

11.5 Programmation d’un demon

Les demons 8 sont des processus qui tournent normalement en arriere-plan pour assurer un service.Pour programmer correctement un demon, il ne suffit pas de faire un fork(), il faut aussi s’assurer quele processus restant ne bloque pas de ressources. Par exemple il doit liberer le terminal de controle duprocessus, revenir a la racine, faute de quoi il empechera le demontage eventuel du systeme de fichiersa partir duquel il a ete lance.

1/∗ D i v e r s /demon . c ∗/

#inc lude <u n i s t d . h>#inc lude < s t d l i b . h>

5#inc lude < f c n t l . h>

i n t d e v e n i r d e m o n ( void ){

i n t f d ;10

/∗ Le p r o c e s s u s s e d edouble , e t l e p e r e s e t e r m i n e ∗/i f ( f o r k ( ) != 0)

e x i t ( EXIT SUCCESS ) ;

15/∗ l e p r o c e s s u s f i l s d e v i e n t l e l e a d e r d ’ un nouveaugroupe de p r o c e s s u s ∗/

s e t s i d ( ) ;

/∗ l e p r o c e s s u s f i l s c r e e l e p r o c e s s u s demon , e t20s e t e r m i n e ∗/

i f ( f o r k ( ) != 0) e x i t ( EXIT SUCCESS ) ;

/∗ l e demon demenage v e r s l a r a c i n e ∗/c h d i r ( ”/” ) ;

25/∗ l ’ e n t r e e s t a n d a r d e s t r e d i r i g e e v e r s / dev / n u l l ∗/f d = open ( ”/ dev / n u l l ” , O RDWR) ;dup2 ( fd , 0 ) ;c l o s e ( f d ) ;

30/∗ e t l e s s o r t i e s v e r s / dev / c o n s o l e ∗/f d = open ( ”/ dev / c o n s o l e ” , O WRONLY) ;dup2 ( fd , 1 ) ;dup2 ( fd , 2 ) ;

35c l o s e ( f d ) ;return EXIT SUCCESS ;

}

Voir FAQ Unix : 1.7 How do I get my program to act like a daemon

8. Traduction de l’anglais daemon, acronyme de � Disk And Extension MONitor �, qui designait une des partiesresidentes d’un des premiers systemes d’exploitation

51

Page 52: Programmation Syst`eme et Réseau sous Unix

12 Signaux

12.1 signal()

#inc lude <s t d i o . h>void (∗ s i g n a l ( i n t signum , void (∗ h a n d l e r ) ( i n t ) ) ) ( i n t ) ;

La fonction signal() demande au systeme de lancer la fonction handler lorsque le signal signumest recu par le processus courant. La fonction signal() renvoie la fonction qui etait precedemmentassociee au meme signal.

Il y a une trentaine de signaux differents 9, parmi lesquels– SIGINT (program interrupt, emis par Ctrl-C),– SIGTST (terminal stop, emis par Ctrl-Z)– SIGTERM (demande de fin de processus)– SIGKILL (arret immediat de processus)– SIGFPE (erreur arithmetique),– SIGALRM (fin de delai, voir fonction alarm()), etc.La fonction handler() prend en parametre le numero du signal recu, et ne renvoie rien.Exemple :

1/∗ D i v e r s / s i g . c ∗/

#inc lude < s t d l i b . h>#inc lude < s i g n a l . h>

5#inc lude <e r r n o . h>#inc lude <u n i s t d . h>#inc lude <s t d i o . h>

#def ine DELAI 1 /∗ s e c o n d e s ∗/10

void t r a i t e m e n t ( i n t n u m e r o s i g n a l ){

p r i n t f ( ” S i g n a l %d => ” , n u m e r o s i g n a l ) ;switch ( n u m e r o s i g n a l ) {

15case SIGTSTP :p r i n t f ( ” Je m’ e n d o r s . . . . \ n” ) ;k i l l ( g e t p i d ( ) , SIGSTOP ) ; /∗ auto−endormissement ∗/p r i n t f ( ” Je me r e v e i l l e !\ n” ) ;s i g n a l ( SIGTSTP , t r a i t e m e n t ) ; /∗ r e p o s i t i o n n e m e n t ∗/

20break ;case SIGINT :case SIGTERM :

p r i n t f ( ” F in du programme .\ n” ) ;e x i t ( EXIT SUCCESS ) ;

25break ;}

}

i n t main ( void )30{

s i g n a l ( SIGTSTP , t r a i t e m e n t ) ; /∗ s i on r e c o i t c o n t r o l e−Z ∗/s i g n a l ( SIGINT , t r a i t e m e n t ) ; /∗ s i c o n t r o l e−C ∗/

9. La liste complete des signaux, leur signification et leur comportement sont decrits dans la page de manuel signal(chapitre 7 pour Linux)

52

Page 53: Programmation Syst`eme et Réseau sous Unix

s i g n a l (SIGTERM , t r a i t e m e n t ) ; /∗ s i k i l l p r o c e s s u s ∗/

35whi le ( 1 ) {s l e e p ( DELAI ) ;p r i n t f ( ” . ” ) ;f f l u s h ( s t d o u t ) ;

}40p r i n t f ( ” f i n \n” ) ;

e x i t ( EXIT SUCCESS ) ;}

12.2 kill()

#inc lude <u n i s t d . h>i n t k i l l ( p i d t p id , i n t s i g ) ;

La fonction kill() envoie un signal a un processus.

12.3 alarm()

#inc lude <u n i s t d . h>long a larm ( long d e l a i ) ;

La fonction alarm() demande au systeme d’envoyer un signal SIGALRM au processus dans un delaifixe (en secondes). Si une alarme etait deja positionnee, elle est remplacee. Un delai nul supprimel’alarme existante.

12.4 pause()

La fonction pause() bloque le processus courant jusqu’a ce qu’il recoive un signal.

#include<u n i s t d . h>i n t pause ( void ) ;

Exercice : Ecrire une fonction equivalente a sleep().

13 Les signaux Posix

Le comportement des signaux classiques d’UNIX est malheureusement different d’une version al’autre. On emploie donc de preference les mecanismes definis par la norme POSIX, qui offrent de plusla possibilite de masquer des signaux.

13.1 Manipulation des ensembles de signaux

Le type sigset t represente les ensembles de signaux.

#inc lude < s i g n a l . h>

i n t s i g e m p t y s e t ( s i g s e t t ∗ s e t ) ;i n t s i g f i l l s e t ( s i g s e t t ∗ s e t ) ;i n t s i g a d d s e t ( s i g s e t t ∗ s e t , i n t signum ) ;i n t s i g d e l s e t ( s i g s e t t ∗ s e t , i n t signum ) ;i n t s i g i s m e m b e r ( const s i g s e t t ∗ s e t , i n t signum ) ;

La fonction sigemptyset() cree un ensemble vide, sigaddset() ajoute un element, etc.

53

Page 54: Programmation Syst`eme et Réseau sous Unix

13.2 sigaction()

#inc lude < s i g n a l . h>

i n t s i g a c t i o n ( i n t signum ,const s t r u c t s i g a c t i o n ∗ act ,s t r u c t s i g a c t i o n ∗ o l d a c t ) ;

La fonction sigaction() change l’action qui sera executee lors de la reception d’un signal. Cetteaction est decrite par une structure struct sigaction

s t r u c t s i g a c t i o n {void (∗ s a h a n d l e r ) ( i n t ) ;void (∗ s a s i g a c t i o n ) ( int , s i g i n f o t ∗ , void ∗ ) ;s i g s e t t sa mask ;i n t s a f l a g s ;void (∗ s a r e s t o r e r ) ( void ) ; /∗ non u t i l i s e ∗/

}

– sa handler indique l’action associee au signal signum. Il peut valoir SIG DFL (action par defaut),SIG IGN (ignorer), ou un pointeur vers une fonction de traitement de lu signal.

– le masque sa mask indique l’ensemble de signaux qui seront bloques pendant l’execution de cesignal. Le signal lui-meme sera bloque, sauf si SA NODEFER ou SA NOMASK figurent parmi les flags.

Le champ sa flags contient une combinaison d’indicateurs, parmi lesquels– SA NOCLDSTOP pour le signal SIGCHLD, ne pas recevoir la notification d’arret des processus fils

(quand les processus fils recoivent SIGSTOP, SIGTSTP, SIGTTIN ou SIGTTOU).– SA ONESHOT ou SA RESETHAND remet l’action par defaut quand le handler a ete appele (c’est le

comportement par defaut du signal() classique).– SA SIGINFO indique qu’il faut utiliser la fonction sa sigaction() a trois parametres a la place

de sa handler().Exemple :

1/∗ D i v e r s / s i g−p o s i x . c ∗/

#inc lude < s t d l i b . h>#inc lude < s i g n a l . h>

5#inc lude <e r r n o . h>#inc lude <u n i s t d . h>#inc lude <s t d i o . h>

#def ine DELAI 1 /∗ s e c o n d e s ∗/10#def ine NB ITERATIONS 60

void t r a i t e r s i g n a l ( i n t n u m e r o s i g n a l ){

s t r u c t s i g a c t i o n r i e n , a n c i e n t r a i t e m e n t ;15

p r i n t f ( ” S i g n a l %d => ” , n u m e r o s i g n a l ) ;

switch ( n u m e r o s i g n a l ) {case SIGTSTP :

20p r i n t f ( ”J ’ a i r e c u un SIGTSTP .\ n” ) ;

/∗ on desarme l e s i g n a l SIGTSTP , avec s a u v e g a r d e dedu ” t r a i t a n t ” p r e c e d e n t ∗/

r i e n . s a h a n d l e r = SIG DFL ;

54

Page 55: Programmation Syst`eme et Réseau sous Unix

25r i e n . s a f l a g s = 0 ;s i g e m p t y s e t (& r i e n . sa mask ) ; /∗ r i e n a masquer ∗/s i g a c t i o n ( SIGTSTP , &r i e n , &a n c i e n t r a i t e m e n t ) ;

p r i n t f ( ” A l o r s j e m’ e n d o r s . . . . \ n” ) ;30k i l l ( g e t p i d ( ) , SIGSTOP ) ; /∗ auto−endormissement ∗/

p r i n t f ( ”On me r e v e i l l e ?\n” ) ;

/∗ r e m i s e en p l a c e a n c i e n t r a i t e m e n t ∗/s i g a c t i o n ( SIGTSTP , &a n c i e n t r a i t e m e n t , NULL ) ;

35p r i n t f ( ”C ’ e s t r e p a r t i !\ n” ) ;break ;

case SIGINT :case SIGTERM :

p r i n t f ( ”On m’ a demande d ’ a r r e t e r l e programme .\ n” ) ;40e x i t ( EXIT SUCCESS ) ;

break ;}

}

45i n t main ( void ){

s t r u c t s i g a c t i o n a ;i n t i ;

50a . s a h a n d l e r = t r a i t e r s i g n a l ; /∗ f o n c t i o n a l a n c e r ∗/s i g e m p t y s e t (&a . sa mask ) ; /∗ r i e n a masquer ∗/

s i g a c t i o n ( SIGTSTP , &a , NULL ) ; /∗ pause c o n t r o l e−Z ∗/s i g a c t i o n ( SIGINT , &a , NULL ) ; /∗ f i n c o n t r o l e−C ∗/

55s i g a c t i o n (SIGTERM , &a , NULL ) ; /∗ a r r e t ∗/

f o r ( i = 1 ; i < NB ITERATIONS ; i ++) {s l e e p ( DELAI ) ;

60p r i n t f ( ”%d” , i % 1 0 ) ;f f l u s h ( s t d o u t ) ;

}

p r i n t f ( ” F in \n” ) ;65return EXIT SUCCESS ;

}

14 Les processus legers (Posix 1003.1c)

Les processus classiques d’UNIX possedent des ressources separees (espace memoire, table desfichiers ouverts...). Lorsqu’un nouveau fil d’execution (processus fils) est cree par fork(), il se voitattribuer une copie des ressources du processus pere.

Il s’ensuit deux problemes :– probleme de performances, puisque la duplication est un mecanisme couteux– probleme de communication entre les processus, qui ont des variables separees.Il existe des moyens d’attenuer ces problemes : technique du copy-on-write dans le noyau pour

55

Page 56: Programmation Syst`eme et Réseau sous Unix

ne dupliquer les pages memoires que lorsque c’est strictement necessaire), utilisation de segmentsde memoire partagee (IPC) pour mettre des donnees en commun. Il est cependant apparu utile dedefinir un mecanisme permettant d’avoir plusieurs fils d’execution (threads) dans un meme espace deressources non duplique : c’est ce qu’on appelle les processus legers. Ces processus legers peuvent sevoir affecter des priorites.

On remarquera que la commutation entre deux threads d’un meme groupe est une operationeconomique, puisqu’il n’est pas utile de recharger entierement la table des pages de la MMU.

Ces processus legers ayant vocation a communiquer entre eux, la norme Posix 1003.1c definitegalement des mecanismes de synchronisation : exclusion mutuelle (mutex), semaphores, et conditions.

Remarque : les semaphores ne sont pas definis dans les bibliotheques de AIX 4.2 et SVR4 d’ATT/-Motorola. Ils existent dans Solaris et les bibliotheques pour Linux.

14.1 Threads

#inc lude <p t h r e a d . h>

i n t p t h r e a d c r e a t e ( p t h r e a d t ∗ th read ,p t h r e a d a t t r t ∗ a t t r ,void ∗(∗ s t a r t r o u t i n e ) ( void ∗ ) ,void ∗ ar g ) ;

void p t h r e a d e x i t ( void ∗ r e t v a l ) ;i n t p t h r e a d j o i n ( p t h r e a d t th , void ∗∗ t h r e a d r e t u r n ) ;

La fonction pthread create demande le lancement d’un nouveau processus leger, avec les attributsindiques par la structure pointee par attr (NULL = attributs par defaut). Ce processus executera lafonction start routine, en lui donnant le pointeur arg en parametre. L’identifiant du processus legerest range a l’endoit pointe par thread.

Ce processus leger se termine (avec un code de retour) lorsque la fonction qui lui est associee setermine par return retcode, ou lorsque le processus leger execute un pthread exit (retcode).

La fonction pthread join permet au processus pere d’attendre la fin d’un processus leger, et derecuperer eventuellement son code de retour.

Priorites : Le fonctionnement des processus legers peut etre mo-difie (priorites, algorithme d’ordonnancement, etc.) en manipulant les at-tributs qui lui sont associes. Voir les fonctions pthread attr init,pthread attr destroy, pthread attr set-detachstate, pthread attr getdetachstate,pthread attr setschedparam, pthread attr getschedparam, pthread attr setschedpolicy,pthread attr getschedpolicy, pthread attr setinheritsched,pthread attr getinheritsched, pthread attr setscope, pthread attr getscope.

14.2 Verrous d’exclusion mutuelle (mutex)

#inc lude <p t h r e a d . h>

i n t p t h r e a d m u t e x i n i t ( p t h r e a d m u t e x t ∗mutex ,const p t h r e a d m u t e x a t t r t ∗m u t e x a t t r ) ;

i n t p t h r e a d m u t e x d e s t r o y ( p t h r e a d m u t e x t ∗mutex ) ;

i n t p t h r e a d m u t e x l o c k ( p t h r e a d m u t e x t ∗mutex ) ) ;i n t p t h r e a d m u t e x u n l o c k ( p t h r e a d m u t e x t ∗mutex ) ;

i n t p t h r e a d m u t e x t r y l o c k ( p t h r e a d m u t e x t ∗mutex ) ;

Les verrous d’exclusion mutuelle (mutex) sont crees par pthread mutex init. Il en est de differentstypes (rapides, recursifs, etc.), selon les attributs pointes par le parametre mutexattr. La valeur

56

Page 57: Programmation Syst`eme et Réseau sous Unix

par defaut (mutexattr=NULL) fait generalement l’affaire. L’identificateur du verrou est place dans lavariable pointee par mutex.

pthread mutex destroy detruit le verrou. pthread mutex lock tente de le bloquer (etmet le thread en attente si le verrou est deja bloque), pthread mutex unlock le debloque.pthread mutex trylock tente de bloquer le verrou, et echoue si le verrou est deja bloque.

14.3 Exemple

Source :

1/∗ Threads / e g e r m u t e x . c ∗/

#inc lude <p t h r e a d . h>#inc lude <s t d i o . h>

5#inc lude <u n i s t d . h>

s t r u c t DonneesTache {char ∗ c h a i n e ; /∗ c h a i n e a e c r i r e ∗/i n t nombre ; /∗ nombre de r e p e t i t i o n s ∗/

10i n t d e l a i ; /∗ d e l a i e n t r e e c r i t u r e s ∗/} ;

i n t numero = 0 ;p t h r e a d m u t e x t v e r r o u ; /∗ p r o t e g e l ’ a c c e s a numero ∗/

15void ∗ e x e c u t e r t a c h e ( void ∗ data ){

i n t k ;s t r u c t Donnees ∗d = data ;

20f o r ( k=0; k< d−>nombre ; k++) {

p t h r e a d m u t e x l o c k (& v e r r o u ) ; /∗ DEBUT SECTION CRITIQUE ∗/numero++;p r i n t f ( ”[%d ] %s \n” , numero , d−>c h a i n e ) ;

25p t h r e a d m u t e x u n l o c k (& v e r r o u ) ; /∗ FIN SECTION CRITIQUE ∗/

s l e e p ( d−>d e l a i ) ;} ;return NULL ;

30}

i n t main ( void ){

p t h r e a d t t1 , t2 ;35s t r u c t DonneesTache d1 , d2 ;

d1 . nombre = 3 ;d1 . c h a i n e =” H e l l o ” ;d1 . d e l a i = 1 ;

40d2 . nombre = 2 ;d2 . c h a i n e = ” World ” ;d2 . d e l a i = 2 ;

45p t h r e a d m u t e x i n i t (& v e r r o u , NULL ) ;

57

Page 58: Programmation Syst`eme et Réseau sous Unix

p t h r e a d c r e a t e (&t1 , NULL , e x e c u t e r t a c h e , ( void ∗) &d1 ) ;p t h r e a d c r e a t e (&t2 , NULL , e x e c u t e r t a c h e , ( void ∗) &d2 ) ;

50p t h r e a d j o i n ( t1 , NULL ) ;p t h r e a d j o i n ( t2 , NULL ) ;

p t h r e a d m u t e x d e s t r o y (& v e r r o u ) ;

55p r i n t f ( ” %d l i g n e s .\ n” , numero ) ;e x i t ( 0 ) ;

}

Compilation :Sous Linux, avec la bibliotheque linuxthreads de Xavier Leroy (INRIA), ce programme doit etre

compile avec l’option -D REENTRANT et la bibliotheque libpthread :

gcc −g −Wall −p e d a n t i c −D REENTRANT l e g e r m u t e x . c −o l e g e r m u t e x − l p t h r e a d

Execution :¿

% l e g e r m u t e x[ 1 ] H e l l o[ 2 ] World[ 3 ] H e l l o[ 4 ] H e l l o[ 5 ] World5 l i g n e s .

%

14.4 Semaphores

Les semaphores, qui font partie de la norme POSIX, ne sont pas implementes dans toutes lesbibliotheques de threads.

#inc lude <semaphore . h>

i n t s e m i n i t ( sem t ∗sem , i n t pshared , unsigned i n t v a l u e ) ;i n t s e m d e s t r o y ( sem t ∗ sem ) ;

i n t sem wai t ( sem t ∗ sem ) ;i n t sem post ( sem t ∗ sem ) ;

i n t s e m t r y w a i t ( sem t ∗ sem ) ;i n t s e m g e t v a l u e ( sem t ∗ sem , i n t ∗ s v a l ) ;

Les semaphores sont crees par sem init, qui place l’identificateur du semaphore a l’endroit pointepar sem. La valeur initiale du semaphore est dans value. Si pshared est nul, le semaphore est local auprocessus lourd (le partage de semaphores entre plusieurs processus lourds n’est pas implemente dansla version courante de linuxthreads.).

sem wait et sem post sont les equivalents respectifs des primitives P et V de Dijkstra. La fonctionsem trywait echoue (au lieu de bloquer) si la valeur du semaphore est nulle. Enfin, sem getvalue

consulte la valeur courante du semaphore.Exercice : Utiliser un semaphore au lieu d’un mutex pour securiser l’exemple.

58

Page 59: Programmation Syst`eme et Réseau sous Unix

14.5 Conditions

Les conditions servent a mettre en attente des processus legers derriere un mutex. Une primitivepermet de debloquer d’un seul coup tous les threads bloques par une meme condition.

#inc lude <p t h r e a d . h>

i n t p t h r e a d c o n d i n i t ( p t h r e a d c o n d t ∗cond ,p t h r e a d c o n d a t t r t ∗ c o n d a t t r ) ;

i n t p t h r e a d c o n d d e s t r o y ( p t h r e a d c o n d t ∗ cond ) ;

i n t p t h r e a d c o n d w a i t ( p t h r e a d c o n d t ∗cond ,p t h r e a d m u t e x t ∗mutex ) ;

i n t p t h r e a d c o n d s i g n a l ( p t h r e a d c o n d t ∗ cond ) ;i n t p t h r e a d c o n d b r o a d c a s t ( p t h r e a d c o n d t ∗ cond ) ;

Les conditions sont creees par phtread cond init, et detruites par phtread cond destroy.Un processus se met en attente en effectuant un phtread cond wait (ce qui bloque au passage

un mutex). La primitive phtread cond broadcast debloque tous les processus qui attendent sur unecondition, phtread cond signal en debloque un seul.

15 Communication entre processus (IPC System V)

Les mecanismes de communication entre processus (InterProcess Communication, ou IPC ) d’UnixSystem V ont ete repris dans de nombreuses variantes d’Unix. Il y a 3 mecanismes :

– les segments de memoire partagee,– les semaphores,– les files de messages.

Ces trois types d’objets sont identifies par des cles.

15.1 ftok() constitution d’une cle

# inc lude <s y s / t y p e s . h># inc lude <s y s / i p c . h>

k e y t f t o k ( char ∗pathname , char p r o j e c t )

La fonction ftok() constitue une cle a partir d’un chemin d’acces et d’un caractere indiquant un� projet �. Plutot que de risquer une explication abstraite, etudions deux cas frequents :

– On dispose d’un logiciel commun dans /opt/jeux/OuiOui. Ce logiciel utilise deuxobjets partages. On pourra utiliser les cles ftok("/opt/jeux/OuiOui",’A’) etftok("/opt/jeux/OuiOui",’B’). Ainsi tous les processus de ce logiciel se refererontaux memes objets qui seront partages entre tous les utilisateurs.

– On distribue un exemple aux etudiants, qui le recopient chez eux et le font tourner. On souhaiteque les processus d’un meme etudiant communiquent entre eux, mais qu’ils n’interferent pas avecd’autres. On basera donc la cle sur une donnee personnelle, par exemple le repertoire d’accueil,avec les cles ftok(getenv("HOME"),’A’) et ftok(getenv("HOME"),’B’).

15.2 Memoires partagees

Ce mecanisme permet a plusieurs programmes de partager des segments memoire. Chaque segmentmemoire est identifie, au niveau du systeme, par une cle a laquelle correspond un identifiant. Lorsqu’unsegment est attache a un programme, les donnees qu’il contient sont accessibles en memoire parl’intermediaire d’un pointeur.

59

Page 60: Programmation Syst`eme et Réseau sous Unix

#inc lude <s y s / i p c . h>#inc lude <s y s /shm . h>

i n t shmget ( k e y t key , i n t s i z e , i n t s h m f l g ) ;char ∗ shmat ( i n t shmid , char ∗ shmaddr , i n t s h m f l g )i n t shmdt ( char ∗ shmaddr )i n t s h m c t l ( i n t shmid , i n t cmd , s t r u c t s h m i d d s ∗ buf ) ;

La fonction shmget() donne l’identifiant du segment ayant la cle key. Un nouveau segment(de taille size) est cree si key est IPC PRIVATE, ou bien si les indicateurs de shmflg contiennentIPC CREAT. Combinees, les options IPC EXCL | IPC CREAT indiquent que le segment ne doit pasexister prealablement. Les bits de poids faible de shmflg indiquent les droits d’acces.

shmat() attache le segment shmid en memoire, avec les droits specifies dans shmflag (SHM R,

SHM W, SHM RDONLY). shmaddr precise ou ce segment doit etre situe dans l’espace memoire (la valeurNULL demande un placement automatique). shmat() renvoie l’adresse ou le segment a ete place.

shmdt() “libere” le segment. shmctl() permet diverses operations, dont la destruction d’unememoire partagee (voir exemple).

Exemple (deux programmes) :Le producteur :

1/∗ IPC/ prod . c ∗/

/∗Ce programme l i t une s u i t e de nombres , e t e f f e c t u e l e

5cumul dans une v a r i a b l e en memoire p a r t a g e e .∗/

#inc lude <s y s / i p c . h>#inc lude <s y s /shm . h>

10#inc lude <s y s / t y p e s . h>#inc lude < s t d l i b . h>#inc lude <s t d i o . h>#inc lude <e r r n o . h>

15void abandon ( char message [ ] ){

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}20

s t r u c t donnees {i n t nb ;i n t t o t a l ;

} ;25

i n t main ( void ){

k e y t c l e ;i n t i d ;

30s t r u c t donnees ∗commun ;i n t r e p o n s e ;

c l e = f t o k ( g e t e n v ( ”HOME” ) , ’A ’ ) ;i f ( c l e == −1)

35abandon ( ” f t o k ” ) ;

60

Page 61: Programmation Syst`eme et Réseau sous Unix

i d = shmget ( c l e , s i z e o f ( s t r u c t donnees ) ,IPC CREAT | IPC EXCL | 0 6 6 6 ) ;

i f ( i d == −1) {40switch ( e r r n o ) {

case EEXIST :abandon ( ” Note : l e segment e x i s t e d e j a \n” ) ;

d e f a u l t :abandon ( ” shmget ” ) ;

45}}commun = ( s t r u c t donnees ∗) shmat ( id , NULL ,

SHM R | SHM W) ;i f (commun == NULL)

50abandon ( ” shmat ” ) ;

commun−>nb = 0 ;commun−>t o t a l = 0 ;

55whi le ( 1 ) {p r i n t f ( ”+ ” ) ;i f ( s c a n f ( ”%d” , &r e p o n s e ) != 1)

break ;commun−>nb++;

60commun−>t o t a l += r e p o n s e ;p r i n t f ( ” sous−t o t a l %d= %d\n” ,

commun−>nb , commun−>t o t a l ) ;}p r i n t f ( ”−−−\n” ) ;

65i f ( shmdt ( ( char ∗) commun) == −1)

abandon ( ” shmdt ” ) ;

/∗ s u p p r e s s i o n segment ∗/70i f ( s h m c t l ( id , IPC RMID , NULL) == −1)

abandon ( ” s h m c t l ( remove ) ” ) ;

return EXIT SUCCESS ;}

Le consommateur :

1/∗ IPC/ cons . c ∗/

/∗Ce programme a f f i c h e p e r i o d i q u e m e n t l e contenu de l a

5memoire p a r t a g e e . A r r e t par C o n t r o l e−C∗/

#inc lude <s y s / i p c . h>#inc lude <s y s /shm . h>

10#inc lude <s y s / t y p e s . h>#inc lude <u n i s t d . h>#inc lude < s t d l i b . h>

61

Page 62: Programmation Syst`eme et Réseau sous Unix

#inc lude <s t d i o . h>#inc lude <e r r n o . h>

15#inc lude < s i g n a l . h>

#def ine DELAI 2

20void abandon ( char message [ ] ){

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}25

s t r u c t donnees {i n t nb ;i n t t o t a l ;

} ;30

i n t c o n t i n u e r b o u c l e = 1 ;

void a r r e t e r b o u c l e ( i n t s i g n a l ){

35c o n t i n u e r b o u c l e = 0 ;}

i n t main ( void ){

40k e y t c l e ;i n t i d ;s t r u c t donnees ∗commun ;s t r u c t s i g a c t i o n a ;

45c l e = f t o k ( g e t e n v ( ”HOME” ) , ’A ’ ) ;i f ( c l e == −1)

abandon ( ” f t o k ” ) ;

i d = shmget ( c l e , s i z e o f ( s t r u c t donnees ) , 0 ) ;50i f ( i d == −1) {

switch ( e r r n o ) {case ENOENT:

abandon ( ” pas de segment\n” ) ;d e f a u l t :

55abandon ( ” shmget ” ) ;}

}

commun = ( s t r u c t donnees ∗) shmat ( id , NULL , SHM R ) ;60i f (commun == NULL)

abandon ( ” shmat ” ) ;

c o n t i n u e r b o u c l e = 1 ;

65a . s a h a n d l e r = a r r e t e r b o u c l e ;s i g e m p t y s e t (&a . sa mask ) ;

62

Page 63: Programmation Syst`eme et Réseau sous Unix

a . s a f l a g s = 0 ;s i g a c t i o n ( SIGINT , &a , NULL ) ;

70whi le ( c o n t i n u e r b o u c l e ) {s l e e p ( DELAI ) ;p r i n t f ( ” sous−t o t a l %d= %d\n” ,

commun−>nb , commun−>t o t a l ) ;}

75p r i n t f ( ”−−−\n” ) ;i f ( shmdt ( ( char ∗) commun) == −1)

abandon ( ” shmdt ” ) ;

80return EXIT SUCCESS ;}

Question : le second programme n’affiche pas forcement des informations coherentes. Pourquoi ?Qu’y faire ?

Probleme : ecrire deux programmes qui partagent deux variables i, j. Voici le pseudo-code :

p r o c e s s u s P1 p r o c e s s u s P2| i =0 j =0 | t a n t que i==j| r e p e t e r i n d e f i n i m e n t | f a i r e r i e n| i++ j++ | e c r i r e if i n f i n

Au bout de combien de temps le processus P2 s’arrete-t-il ? Faire plusieurs essais.Exercice : la commande ipcs affiche des informations sur les segments qui existent. Ecrire une

commande qui permet d’afficher le contenu d’un segment (on donne le shmid et la longueur enparametres).

15.3 Semaphores

#inc lude <s y s / t y p e s . h>#inc lude <s y s / i p c . h>#inc lude <s y s /sem . h>

i n t semget ( k e y t key , i n t nsems , i n t s e m f l g )i n t semop ( i n t semid , s t r u c t sembuf ∗ sops , unsigned nsops )i n t s e m c t l ( i n t semid , i n t semnum , i n t cmd , union semun arg )

Les operations System V travaillent en fait sur des tableaux de semaphores generalises (pouvantevoluer par une valeur entiere quelconque).

La fonction semget() demande a travailler sur le semaphore generalise qui est identifie par lacle key (meme notion que pour les cles des segments partages) et qui contient nsems semaphoresindividuels. Un nouveau semaphore est cree, avec les droits donnes par les 9 bits de poids faible desemflg, si key est IPC PRIVATE, ou si semflg contient IPC CREAT.

semop() agit sur le semaphore semid en appliquant simultanement a plusieurs semaphores indivi-duels les actions decrites dans les nsops premiers elements du tableau sops. Chaque sembuf est unestructure de la forme :

s t r u c t sembuf{

. . .short sem num ; /∗ semaphore number : 0 = f i r s t ∗/short sem op ; /∗ semaphore o p e r a t i o n ∗/

63

Page 64: Programmation Syst`eme et Réseau sous Unix

short s e m f l g ; /∗ o p e r a t i o n f l a g s ∗/. . .

}

sem flg est une combinaison d’indicateur qui peut contenir IPC NOWAIT et SEM UNDO (voir manuel).Ici nous supposons que sem flg est 0.

sem num indique le numero du semaphore individuel sur lequel porte l’operation. sem op est unentier destine (sauf si il est nul) a etre ajoute a la valeur courante semval du semaphore. L’operationse bloque si sem_op + semval < 0.

Cas particulier : si sem op est 0, l’operation est bloquee tant que semval est non nul.Les valeurs des semaphores ne sont mises a jour que lorsque aucun d’eux n’est bloque.semctl permet de realiser diverses operations sur les semaphores, selon la commande demandee.

En particulier, on peut fixer le n-ieme semaphore a la valeur val en faisant :

s e m c t l ( sem , n , SETVAL , v a l ) ;

Exemple : primitives sur les semaphores traditionnels.

1/∗ IPC/sem . c ∗/

/∗O p e r a t i o n s s u r des s emaphores

5∗/

#inc lude <s y s / t y p e s . h>#inc lude <s y s / i p c . h>#inc lude <s y s /sem . h>

10#inc lude <u n i s t d . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>#inc lude <c t y p e . h>

15typedef i n t SEMAPHORE;

void abandon ( char message [ ] ){

p e r r o r ( message ) ;20e x i t ( EXIT FAILURE ) ;

}

void d e t r u i r e s e m (SEMAPHORE sem ){

25i f ( s e m c t l ( sem , 0 , IPC RMID , 0) != 0)abandon ( ” d e t r u i r e s e m ” ) ;

}

void changer sem (SEMAPHORE sem , i n t v a l )30{

s t r u c t sembuf sb [ 1 ] ;sb [ 0 ] . sem num = 0 ;sb [ 0 ] . sem op = v a l ;sb [ 0 ] . s e m f l g = 0 ;

35i f ( semop ( sem , sb , 1) != 0)abandon ( ” changer sem ” ) ;

}

64

Page 65: Programmation Syst`eme et Réseau sous Unix

SEMAPHORE c r e e r s e m ( k e y t key )40{

SEMAPHORE sem ;i n t r ;

sem = semget ( key , 1 , IPC CREAT | 0 6 6 6 ) ;45i f ( sem < 0) {

p e r r o r ( ” c r e e r s e m ” ) ;e x i t ( EXIT FAILURE ) ;

}r = s e m c t l ( sem , 0 , SETVAL , 0 ) ; /∗ v a l e u r i n i t i a l e = 0 ∗/

50i f ( r < 0) {p e r r o r ( ” i n i t i a l i s a t i o n s emaphore ” ) ;e x i t ( EXIT FAILURE ) ;

}return sem ;

55}

void P(SEMAPHORE sem ){

changer sem ( sem , −1);60}

void V(SEMAPHORE sem ){

changer sem ( sem , 1 ) ;65}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

i n t main ( i n t argc , char ∗ a r g v [ ] )70{

SEMAPHORE sem ;k e y t key ;i n t e n c o r e = 1 ;

75i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” Usage : %s c l e \n” , a r g v [ 0 ] ) ;abandon ( ” Mauvais nombre de p a r a m e t r e s ” ) ;

}key = a t o i ( a r g v [ 1 ] ) ;

80sem = c r e e r s e m ( key ) ;whi le ( e n c o r e ) {

char r e p o n s e ;p r i n t f ( ”p , v , x , q ? ” ) ;i f ( s c a n f ( ”%c ” , &r e p o n s e ) != 1)

85break ;switch ( t o u p p e r ( r e p o n s e ) ) {case ’P ’ :

P( sem ) ;p r i n t f ( ”OK.\ n” ) ;

90break ;case ’V ’ :

V( sem ) ;

65

Page 66: Programmation Syst`eme et Réseau sous Unix

p r i n t f ( ”OK.\ n” ) ;break ;

95case ’X ’ :d e t r u i r e s e m ( sem ) ;p r i n t f ( ” Semaphore d e t r u i t \n” ) ;e n c o r e = 0 ;break ;

100case ’Q ’ :e n c o r e = 0 ;break ;

d e f a u l t :p r i n t f ( ” ?\n” ) ;

105}}p r i n t f ( ”Bye .\ n” ) ;return EXIT SUCCESS ;

}

Exercice : que se passe-t-il si on essaie d’interrompre semop() ?Exercice : utilisez les semaphores pour “securiser” l’exemple presente sur les memoires partagees.

15.4 Files de messages

Ce mecanisme permet l’echange de messages par des processus. Chaque message possede un corpsde longueur variable, et un type (entier strictement positif) qui peut servir a preciser la nature desinformations contenues dans le corps.

Au moment de la reception, on peut choisir de selectionner les messages d’un type donne.

#inc lude <s y s / t y p e s . h>#inc lude <s y s / i p c . h>#inc lude <s y s /msg . h>

i n t msgget ( k e y t key , i n t m s g f l g )i n t msgsnd ( i n t msqid , s t r u c t msgbuf ∗msgp , i n t msgsz , i n t m s g f l g )i n t msgrcv ( i n t msqid , s t r u c t msgbuf ∗msgp , i n t msgsz ,

long msgtyp , i n t m s g f l g )i n t m s g c t l ( i n t msqid , i n t cmd , s t r u c t m s q i d d s ∗ buf )

msgget() demande l’acces a (ou la creation de) la file de message avec la cle key. msgget()retourne la valeur de l’identificateur de file. msgsnd() envoie un message dans la file msqid. Le corpsde ce message contient msgsz octets, il est place, precede par le type dans le tampon pointe par msgp.Ce tampon de la forme :

s t r u c t msgbuf {long mtype ; /∗ message type , must be > 0 ∗/char mtext [ . . . ] /∗ message data ∗/

} ;

msgrcv() lit dans la file un message d’un type donne (si type < 0) ou indifferent (si type==0),et le place dans le tampon pointe par msgp. La taille du corps ne pourra exceder msgsz octets, sinonil sera tronque. msgrcv() renvoie la taille du corps du message.

Exemple. Deux programmes, l’un pour envoyer des messages (lignes de texte) sur une file avec untype donne, l’autre pour afficher les messages recus.

1/∗ IPC/ snd . c ∗/

/∗e n v o i des messages dans une f i l e ( IPC System V)

66

Page 67: Programmation Syst`eme et Réseau sous Unix

5∗/

#inc lude <e r r n o . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

10#inc lude <s t d i o . h>

#inc lude <s y s / t y p e s . h>#inc lude <s y s / i p c . h>#inc lude <s y s /msg . h>

15#def ine MAX TEXTE 1000

s t r u c t tampon {long mtype ;

20char mtext [MAX TEXTE ] ;} ;

void abandon ( char message [ ] ){

25p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

i n t main ( i n t argc , char ∗ a r g v [ ] )30{

i n t c l e , id , mtype ;i f ( a r g c != 3) {

f p r i n t f ( s t d e r r , ” Usage : %s c l e t y p e \n” , a r g v [ 0 ] ) ;abandon ( ” mauvais nombre de p a r a m e t r e s ” ) ;

35}c l e = a t o i ( a r g v [ 1 ] ) ;mtype = a t o i ( a r g v [ 2 ] ) ;i d = msgget ( c l e , 0 6 6 6 ) ;i f ( i d == −1)

40abandon ( ” msgget ” ) ;

whi le ( 1 ) {s t r u c t tampon msg ;i n t l , r ;

45p r i n t f ( ”> ” ) ;f g e t s ( msg . mtext , MAX TEXTE, s t d i n ) ;l = s t r l e n ( msg . mtext ) ;msg . mtype = mtype ;

50r = msgsnd ( id , ( s t r u c t msgbuf ∗) &msg , l + 1 , 0 ) ;i f ( r == −1)

abandon ( ” msgsnd ” ) ;}

}

1/∗ IPC/ r c v . c ∗/

67

Page 68: Programmation Syst`eme et Réseau sous Unix

/∗a f f i c h e l e s messages q u i p r o v i e n n e n t

5d ’ une f i l e ( IPC System V)∗/

#inc lude <e r r n o . h>#inc lude <s t d i o . h>

10#inc lude < s t d l i b . h>#inc lude <s t d i o . h>

#inc lude <s y s / t y p e s . h>#inc lude <s y s / i p c . h>

15#inc lude <s y s /msg . h>

#def ine MAX TEXTE 1000s t r u c t tampon {

long mtype ;20char mtext [MAX TEXTE ] ;

} ;

i n t c o n t i n u e r b o u c l e = 1 ;

25void abandon ( char message [ ] ){

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}30

i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t c l e , i d ;i f ( a r g c != 2) {

35f p r i n t f ( s t d e r r , ” Usage : %s c l e \n” , a r g v [ 0 ] ) ;abandon ( ” Mauvais nombnre de p a r a m e t r e s ” ) ;

}c l e = a t o i ( a r g v [ 1 ] ) ;i d = msgget ( c l e , IPC CREAT | 0 6 6 6 ) ;

40i f ( i d == −1)abandon ( ” msgget ” ) ;

whi le ( c o n t i n u e r b o u c l e ) {s t r u c t tampon msg ;

45i n t l = msgrcv ( id , ( s t r u c t msgbuf ∗) &msg , MAX TEXTE, 0L , 0 ) ;i f ( l == −1)

abandon ( ” msgrcv ” ) ;p r i n t f ( ” ( t y p e=%l d ) %s \n” , msg . mtype , msg . mtext ) ;

}50

return EXIT SUCCESS ;}

68

Page 69: Programmation Syst`eme et Réseau sous Unix

16 Communication par le reseau TCP-IP

Les concepts fondamentaux (sockets, adresses, communication par datagrammes et flots, client-serveur etc.) sont les memes que pour les sockets locaux (voir 10). Les particularites viennent desadresses : comment fabriquer une adresse a partir d’un nom de machine (resolution) et d’un numerode port, comment retrouver le nom d’une machine a partir d’une adresse (resolution inverse) etc.

16.1 Sockets, addresses

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t s o c k e t ( i n t domain , i n t type , i n t p r o t o c o l ) ;

Pour communiquer, les applications doivent creer des sockets (prises bidirectionnelles) par la fonc-tion socket() et les relier entre elles. On peut ensuite utiliser ces sockets comme des fichiers ordinaires(par read, write, ...) ou par des operations specifiques ( send, sendto, recv, recvfrom, ...).

Pour designer un socket sur une machine il faut une adresse de socket. Comme il existe differentstypes de sockets, les operations sur les adresses concerne un type d’adresse general abstrait (structsockaddr) qui recouvre tous les types concrets particuliers.

Pour TCP-IP (Inet), les adresses de sockets sont determinees par un numero IP, et un numero deport. Pour IPv4, on utilise des struct sockaddr in, qui possedent 3 champs importants :

– sin family, la famille d’adresses, valant AF INET

– sin addr, pour l’adresse IP.– sin port, pour le numero de portAttention, les octets de l’adresse IP et le numero de port sont stockes dans l’ordre reseau (big-

endian), qui n’est pas forcement celui de la machine hote sur laquelle s’execute le programme. Voirplus loin les fonctions de conversion hote/reseau.

Pour IPv6, on utilise des struct sockaddr in6, avec– sin6 family, valant AF INET6

– sin6 addr, l’adresse IP sur 6 octets– sin6 port, pour le numero de port.

16.2 Remplissage d’une adresse

Comme pour les sockets locaux, on cree les sockets par socket() et on � nomme la prise � parbind().

16.2.1 Preparation d’une adresse distante

Dans le cas le plus frequent, on dispose du nom de la machine destinataire (par exemple la chaınede caracteres "www.elysee.fr"), et du numero de port (un entier).

#i n c l u d e <netdb . h>s t r u c t h o s t e n t ∗ gethostbyname ( const char ∗name ) ;

gethostbyname() retourne un pointeur vers une structure hostent qui contient diverses informa-tions sur la machine en question, en particulier une adresse h addr 10 que l’on mettra dans sin addr.

Le champ sin port est un entier court en ordre reseau, pour y mettre un entier ordinaire il faut leconvertir par htons() 11.

Voir exemple client-echo.c.

10. Une machine peut avoir plusieurs adresses11. Host TO Network Short

69

Page 70: Programmation Syst`eme et Réseau sous Unix

16.2.2 Preparation d’une adresse locale

Pour une adresse sur la machine locale 12, on utilise– dans le cas le plus frequent, l’adresse INADDR ANY (0.0.0.0). Le socket est alors ouvert (avec

le meme numero de port) sur toutes les adresses IP de toutes les interfaces de la machine.– l’adresse INADDR LOOPBACK correspondant a l’adresse locale 127.0.0.1 (alias localhost). Le

socket n’est alors accessible que depuis la machine elle-meme.– une des adresses IP de la la machine.– l’adresse de diffusion generale (broadcast) INADDR BROADCAST (255.255.255.255) 13

Voir exemple serveur-echo.c.Pour IPV6– Famille d’adresses AF INET6, famille de protocoles PF INET6

– adresses predefinies IN6ADD LOOPBACK INIT (::1) IN6ADD ANY INIT

16.2.3 Examen d’une adresse

La fonction getsockname() permet de retrouver l’adresse associee a un socket.

#inc lude <s y s / s o c k e t . h>

i n t getsockname ( i n t s ,s t r u c t s o c k a d d r ∗name ,s o c k l e n t ∗ namelen )

Le numero de port est dans le champ sin port, pour le convertir en entier normal, utiliser ntohs()(Network TO Host short).

L’adresse IP peut etre convertie en chaıne de caracteres en notation decimale pointee (exemple"147.210.94.194") par inet ntoa() (network to ascii),

#inc lude <s y s / s o c k e t . h>#inc lude <n e t i n e t / i n . h>#inc lude <arpa / i n e t . h>

char ∗ i n e t n t o a ( s t r u c t i n a d d r i n ) ;

C’est ce qui est utilise dans serveur-echo.c pour determiner et afficher la provenance des requetes.On peut egalement tenter une resolution inverse, c’est-a-dire de retrouver le nom a partir de

l’adresse, en passant par gethostbyaddr, qui retourne un pointeur vers une structure hostent, dontle champ h name designe le nom officiel de la machine.

Cette resolution n’aboutit pas toujours, parce que tous les numeros IP ne correspondent pas a desmachines declarees.

#inc lude <netdb . h>extern i n t h e r r n o ;

s t r u c t h o s t e n t ∗ g e t h o s t b y a d d r ( const char ∗addr , i n t l e n , i n t t y p e ) ;

s t r u c t h o s t e n t {char ∗h name ; /∗ o f f i c i a l name o f h o s t ∗/char ∗∗ h a l i a s e s ; /∗ a l i a s l i s t ∗/i n t h a d d r t y p e ; /∗ h o s t a d d r e s s t y p e ∗/i n t h l e n g t h ; /∗ l e n g t h o f a d d r e s s ∗/char ∗∗ h a d d r l i s t ; /∗ l i s t o f a d d r e s s e s ∗/

}#def ine h a d d r h a d d r l i s t [ 0 ] /∗ f o r backward c o m p a t i b i l i t y ∗/

12. ne pas confondre avec la notion de socket du domaine local vue en 10 name=”sockets”¿13. L’utilisation de l’adresse de diffusion est soumise a restrictions, voir manuel

70

Page 71: Programmation Syst`eme et Réseau sous Unix

16.3 Fermeture d’un socket

Un socket peut etre ferme par close() ou par shutdown().

i n t shutdown ( i n t fd , i n t how ) ;

Un socket est bidirectionnel, le parametre how indique quelle(s) moitie(s) on ferme : 0 pour lasortie, 1 pour l’entree, 2 pour les deux (equivaut a close()).

16.4 Communication par datagrammes (UDP)

16.4.1 Creation d’un socket

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t s o c k e t ( i n t domain , i n t type , i n t p r o t o c o l ) ;

Cette fonction construit un socket et retourne un numero de descripteur. Pour une liaison pardatagrammes sur IPv4, utilisez la famille AF INET, le type SOCK DGRAM et le protocole par defaut 0.

Retourne -1 en cas d’echec.16.4.2 Connexion de sockets

La fonction connect met en relation un socket (de cette machine) avec un autre socket designe,qui sera le � correspondant par defaut � pour la suite des operations.

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t c o n n e c t ( i n t s o c k f d ,const s t r u c t s o c k a d d r ∗ s e r v a d d r ,s o c k l e n t a d d r l e n ) ;

16.4.3 Envoi de datagrammes

Sur un socket connecte (voir ci-dessus), on peut expedier des datagrammes (contenus dans untampon t de longueur n) par write(sockfd,t,n).

La fonction send()

i n t send ( i n t s , const void ∗msg , s i z e t l e n , i n t f l a g s ) ;

permet d’indiquer des flags, par exemple MSG DONTWAIT pour une ecriture non bloquante.Enfin, sendto() envoie un datagramme a une adresse specifiee, sur un socket connecte ou non.

i n t s e n d t o ( i n t s , const void ∗msg , s i z e t l e n , i n t f l a g s ,const s t r u c t s o c k a d d r ∗ to , s o c k l e n t t o l e n ) ;

16.4.4 Reception de datagrammes

Inversement, la reception peut se faire par un simple read(), par un recv() (avec des flags), oupar un recvfrom, qui permet de recuperer l’adresse from de l’emetteur.

i n t r e c v ( i n t s , void ∗buf , s i z e t l e n , i n t f l a g s ) ;i n t r e c v f r o m ( i n t s , void ∗buf , s i z e t l e n , i n t f l a g s ,

s t r u c t s o c k a d d r ∗ from , s o c k l e n t ∗ f r o m l e n ) ;

71

Page 72: Programmation Syst`eme et Réseau sous Unix

16.4.5 Exemple UDP : serveur d’echo

Principe :

– Le client envoie une chaıne de caracteres au serveur.– Le serveur l’affiche, la convertit en minuscules, et la reexpedie.– Le client affiche la reponse.

Usage :

– sur le serveur : serveur-echo numero-de-port– pour chaque client : client-echo nom-serveur numero-de-port � message a expedier �

Le client .

1/∗TCPIP/ c l i e n t −echo . c

Envo i de datagrammes5

Exemple de c l i e n t q u i− o u v r e un s o c k e t− e n v o i e des datagrammes s u r ce s o c k e t ( l i g n e s de t e x t e sde l ’ e n t r e e s t a n d a r d )

10− a t t e n d une r e p o n s e− a f f i c h e l a r e p o n s e∗/

#inc lude <u n i s t d . h>15#inc lude <s y s / t y p e s . h>

#inc lude <s y s / s o c k e t . h>#inc lude <n e t i n e t / i n . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>

20#inc lude <netdb . h>#inc lude < s t r i n g . h>#inc lude < s t d l i b . h>

#def ine TAILLE TAMPON 100025s t a t i c i n t f d ;

void abandon ( char message [ ] ){

30p r i n t f ( ”CLIENT> E r r e u r f a t a l e \n” ) ;p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}

35i n t main ( i n t argc , char ∗ a r g v [ ] ){

s t r u c t s o c k a d d r i n a d r e s s e s o c k e t s e r v e u r ;s t r u c t h o s t e n t ∗ hote ;i n t t a i l l e a d r e s s e s o c k e t s e r v e u r ;

40char ∗ n o m s e r v e u r ;i n t n u m e r o p o r t s e r v e u r ;char ∗ r e q u e t e , r e p o n s e [ TAILLE TAMPON ] ;

72

Page 73: Programmation Syst`eme et Réseau sous Unix

i n t l o n g u e u r r e q u e t e , l o n g u e u r r e p o n s e ;

45/∗ 1 . r e c e p t i o n des p a r a m e t r e s de l a l i g n e de commande ∗/i f ( a r g c != 4) {

p r i n t f ( ” Usage : %s hote p o r t message\n” , a r g v [ 0 ] ) ;abandon ( ” nombre de p a r a m e t r e s i n c o r r e c t ” ) ;

50}n o m s e r v e u r = a r g v [ 1 ] ;n u m e r o p o r t s e r v e u r = a t o i ( a r g v [ 2 ] ) ;r e q u e t e = a r g v [ 3 ] ;

55/∗ 2 . I n i t i a l i s a t i o n du s o c k e t ∗/

/∗ 2 . 1 c r e a t i o n du s o c k e t en mode datagramme ∗/f d = s o c k e t ( AF INET , SOCK DGRAM, 0 ) ;i f ( f d < 0)

60abandon ( ” C r e a t i o n s o c k e t ” ) ;

/∗ 2 . 2 r e c h e r c h e de l a machine s e r v e u r ∗/

hote = gethostbyname ( n o m s e r v e u r ) ;65i f ( hote == NULL)

abandon ( ” Recherche s e r v e u r ” ) ;

/∗ 2 . 3 R e m p l i s s a g e a d r e s s e s e r v e u r ∗/70a d r e s s e s o c k e t s e r v e u r . s i n f a m i l y = AF INET ;

a d r e s s e s o c k e t s e r v e u r . s i n p o r t = h t o n s ( n u m e r o p o r t s e r v e u r ) ;a d r e s s e s o c k e t s e r v e u r . s i n a d d r = ∗( s t r u c t i n a d d r ∗) hote−>h a d d r ;t a i l l e a d r e s s e s o c k e t s e r v e u r = s i z e o f a d r e s s e s o c k e t s e r v e u r ;

75/∗ 3 . Envo i de l a r e q u e t e ∗/p r i n t f ( ”REQUETE> %s \n” , r e q u e t e ) ;l o n g u e u r r e q u e t e = s t r l e n ( r e q u e t e ) + 1 ;i f ( s e n d t o ( fd , r e q u e t e , l o n g u e u r r e q u e t e , 0 , /∗ f l a g s ∗/

( s t r u c t s o c k a d d r ∗) &a d r e s s e s o c k e t s e r v e u r ,80t a i l l e a d r e s s e s o c k e t s e r v e u r )

< 0)abandon ( ” Envo i r e q u e t e ” ) ;

/∗ 4 . L e c t u r e de l a r e p o n s e ∗/85l o n g u e u r r e p o n s e = r e c v f r o m ( fd , reponse , TAILLE TAMPON , 0 , NULL , 0 ) ;

i f ( l o n g u e u r r e p o n s e < 0)abandon ( ” A t t e n t e r e p o n s e ” ) ;

p r i n t f ( ”REPONSE> %s \n” , r e p o n s e ) ;c l o s e ( f d ) ;

90p r i n t f ( ”CLIENT> Fin .\ n” ) ;return EXIT SUCCESS ;

}

Exercice : faire en sorte que le client reexpedie sa requete si il ne recoit pas la reponse dans undelai fixe. Fixer une limite au nombre de tentatives.

73

Page 74: Programmation Syst`eme et Réseau sous Unix

Le serveur :

1/∗TCP/ s e r v e u r−echo . c − R e c e p t i o n de datagrammes

Exemple de s e r v e u r q u i5− o u v r e un s o c k e t s u r un p o r t en mode non−c o n n e c t e

− a f f i c h e l e s messages ( c h a ı n e s de c a r a c t e r e s )qu ’ i l r e c o i t par ce s o c k e t .− e n v o i e une r e p o n s e∗/

10

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

15#inc lude <n e t i n e t / i n . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>#inc lude <arpa / i n e t . h>

20#inc lude <c t y p e . h>#inc lude < s t r i n g . h>

#def ine TAILLE TAMPON 1000s t a t i c i n t f d ;

25void abandon ( char message [ ] ){

p r i n t f ( ”SERVEUR> E r r e u r f a t a l e \n” ) ;p e r r o r ( message ) ;

30e x i t ( EXIT FAILURE ) ;}

void a r r e t e r s e r v e u r ( i n t s i g n a l ){

35c l o s e ( f d ) ;p r i n t f ( ”SERVEUR> A r r e t du s e r v e u r ( s i g n a l %d )\n” , s i g n a l ) ;e x i t ( EXIT SUCCESS ) ;

}

40i n t main ( i n t argc , char ∗ a r g v [ ] ){

s t r u c t s o c k a d d r i n a d r e s s e s e r v e u r ;s i z e t t a i l l e a d r e s s e s e r v e u r ;

45i n t n u m e r o p o r t s e r v e u r ;char ∗ s r c , ∗ d s t ;s t r u c t s i g a c t i o n a ;

/∗ 1 . r e c e p t i o n des p a r a m e t r e s de l a l i g n e de commande ∗/50

i f ( a r g c != 2) {p r i n t f ( ” usage : %s p o r t \n” , a r g v [ 0 ] ) ;

74

Page 75: Programmation Syst`eme et Réseau sous Unix

abandon ( ” mauvais nombre de p a r a m e t r e s ” ) ;}

55n u m e r o p o r t s e r v e u r = a t o i ( a r g v [ 1 ] ) ;

/∗ 2 . S i une i n t e r r u p t i o n s e p r o d u i t , a r r e t du s e r v e u r ∗//∗ s i g n a l ( SIGINT , a r r e t e r s e r v e u r ) ; ∗/

60a . s a h a n d l e r = a r r e t e r s e r v e u r ;s i g e m p t y s e t (&a . sa mask ) ;a . s a f l a g s = 0 ;s i g a c t i o n ( SIGINT , &a , NULL ) ;

65/∗ 3 . I n i t i a l i s a t i o n du s o c k e t de r e c e p t i o n ∗/

/∗ 3 . 1 C r e a t i o n du s o c k e t en mode non−c o n n e c t e( datagrammes ) ∗/

70f d = s o c k e t ( AF INET , SOCK DGRAM, 0 ) ;i f ( f d < 0)

abandon ( ” s o c k e t ” ) ;

75/∗ 3 . 2 R e m p l i s s a g e de l ’ a d r e s s e de r e c e p t i o n

( p r o t o c o l e I n t e r n e t TCP−IP , r e c e p t i o n a c c e p t e e s u r t o u t e sl e s a d r e s s e s IP du s e r v e u r , numero de p o r t i n d i q u e )

∗/80

a d r e s s e s e r v e u r . s i n f a m i l y = AF INET ;a d r e s s e s e r v e u r . s i n a d d r . s a d d r = INADDR ANY ;a d r e s s e s e r v e u r . s i n p o r t = h t o n s ( n u m e r o p o r t s e r v e u r ) ;

85/∗ 3 . 3 A s s o c i a t i o n du s o c k e t au p o r t de r e c e p t i o n ∗/

t a i l l e a d r e s s e s e r v e u r = s i z e o f a d r e s s e s e r v e u r ;i f ( b i n d ( fd ,

( s t r u c t s o c k a d d r ∗) &a d r e s s e s e r v e u r ,90t a i l l e a d r e s s e s e r v e u r ) < 0)

abandon ( ” b i n d ” ) ;

p r i n t f ( ”SERVEUR> Le s e r v e u r e c o u t e l e p o r t %d\n” ,n u m e r o p o r t s e r v e u r ) ;

95whi le ( 1 ) {

s t r u c t s o c k a d d r i n a d r e s s e c l i e n t ;i n t t a i l l e a d r e s s e c l i e n t ;char t a m p o n r e q u e t e [ TAILLE TAMPON ] ,

100tampon reponse [ TAILLE TAMPON ] ;i n t l g r e q u e t e , l g r e p o n s e ;

/∗ 4 . A t t e n t e d ’ un datagramme ( r e q u e t e ) ∗/

105t a i l l e a d r e s s e c l i e n t = s i z e o f ( a d r e s s e c l i e n t ) ;l g r e q u e t e = r e c v f r o m ( fd , tampon requete , TAILLE TAMPON ,

75

Page 76: Programmation Syst`eme et Réseau sous Unix

0 , /∗ f l a g s ∗/( s t r u c t s o c k a d d r ∗) &a d r e s s e c l i e n t ,( s o c k l e n t ∗) & t a i l l e a d r e s s e c l i e n t ) ;

110i f ( l g r e q u e t e < 0)abandon ( ” r e c f r o m ” ) ;

/∗ 5 . A f f i c h a g e message avec sa p r o v e n a n c e e t sa l o n g u e u r ∗/

115p r i n t f ( ”%s :%d [%d ]\ t : %s \n” ,i n e t n t o a ( a d r e s s e c l i e n t . s i n a d d r ) ,n t o h s ( a d r e s s e c l i e n t . s i n p o r t ) ,l g r e q u e t e , t a m p o n r e q u e t e ) ;

120/∗ 6 . F a b r i c a t i o n d ’ une r e p o n s e ∗/

s r c = t a m p o n r e q u e t e ;d s t = tampon reponse ;whi le ( (∗ d s t++ = t o u p p e r (∗ s r c ++)) != ’ \0 ’ ) ;

125l g r e p o n s e = s t r l e n ( tampon reponse ) + 1 ;

/∗ 7 . Envo i de l a r e p o n s e ∗/

i f ( s e n d t o ( fd ,130tampon reponse ,

l g r e p o n s e ,0 ,( s t r u c t s o c k a d d r ∗) &a d r e s s e c l i e n t ,t a i l l e a d r e s s e c l i e n t )

135< 0)abandon ( ” Envo i de l a r e p o n s e ” ) ;

}/∗ on ne p a s s e j a m a i s i c i ∗/return EXIT SUCCESS ;

140}

16.5 Communication par flots de donnees (TCP)

La creation d’un socket pour TCP se fait ainsi

i n t f d ;. .f d=s o c k e t ( AF INET , SOCK STREAM , 0 ) ;

16.5.1 Programmation des clients TCP

Le socket d’un client TCP doit etre relie (par connect()) a celui du serveur, et il est utilise ensuitepar des read() et des write(), ou des entrees-sorties de haut niveau fprintf(), fscanf(), etc. sion a defini des flots par fdopen().

16.5.2 Exemple : client web

1/∗ TCPIP/ c l i e n t −web . c ∗/

76

Page 77: Programmation Syst`eme et Réseau sous Unix

/∗I n t e r r o g a t i o n d ’ un s e r v e u r web

5Usage :c l i e n t −web s e r v e u r p o r t a d r e s s e−document

r e t o u r n e l e contenu du document d ’ a d r e s s e10h t t p : / / s e r v e u r : p o r t / a d r e s s e−document

Exemple :c l i e n t −web www. i n f o . p r i v e 80 / i n d e x . html

15Fonct ionnement :− o u v e r t u r e d ’ une c o n n e x i o n TCP v e r s s e r v e u r : p o r t− e n v o i de l a r e q u e t e GET a d r e s s e−document HTTP/ 1 . 0 [ c r ] [ l f ] [ c r ] [ l f ]− a f f i c h a g e de l a r e p o n s e

∗/20

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>#inc lude <n e t i n e t / i n . h>

25#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude <netdb . h>#inc lude < s t r i n g . h>#inc lude < s t d l i b . h>

30#def ine CRLF ”\ r \n”#def ine TAILLE TAMPON 1000

35void abandon ( char message [ ] ){

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

}40

/∗ −− c o n n e x i o n v e r s un s e r v e u r TCP −−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/i n t o u v r i r c o n n e x i o n t c p ( char n o m s e r v e u r [ ] , i n t p o r t s e r v e u r ){

s t r u c t s o c k a d d r i n a d d r s e r v e u r ;45s t r u c t h o s t e n t ∗ s e r v e u r ;

i n t f d ;

f d = s o c k e t ( AF INET , SOCK STREAM, 0 ) ; /∗ c r e a t i o n p r i s e ∗/i f ( f d < 0)

50abandon ( ” s o c k e t ” ) ;

s e r v e u r = gethostbyname ( n o m s e r v e u r ) ; /∗ r e c h e r c h e a d r e s s e s e r v e u r ∗/i f ( s e r v e u r == NULL)

abandon ( ” gethostbyname ” ) ;55

77

Page 78: Programmation Syst`eme et Réseau sous Unix

a d d r s e r v e u r . s i n f a m i l y = AF INET ;a d d r s e r v e u r . s i n p o r t = h t o n s ( p o r t s e r v e u r ) ;a d d r s e r v e u r . s i n a d d r = ∗( s t r u c t i n a d d r ∗) s e r v e u r−>h a d d r ;

60i f ( c o n n e c t ( fd , /∗ c o n n e x i o n au s e r v e u r ∗/

( s t r u c t s o c k a d d r ∗) &a d d r s e r v e u r ,s i z e o f a d d r s e r v e u r )

< 0)65abandon ( ” c o n n e c t ” ) ;

return ( f d ) ;}

70/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

void demander document ( i n t fd , char a d r e s s e d o c u m e n t [ ] ){

char r e q u e t e [ TAILLE TAMPON ] ;75i n t l o n g u e u r ;

/∗ c o n s t i t u t i o n de l a r e q u e t e , s u i v i e d ’ une l i g n e v i d e ∗/l o n g u e u r = s n p r i n t f ( r e q u e t e , TAILLE TAMPON ,

”GET %s HTTP/ 1 . 0 ” CRLF CRLF ,a d r e s s e d o c u m e n t ) ;

80w r i t e ( fd , r e q u e t e , l o n g u e u r ) ; /∗ e n v o i ∗/}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

85void a f f i c h e r r e p o n s e ( i n t f d ){

char tampon [ TAILLE TAMPON ] ;i n t l o n g u e u r ;whi le ( 1 ) {

90/∗ l e c t u r e par b l o c ∗/l o n g u e u r = r e a d ( fd , tampon , TAILLE TAMPON ) ;i f ( l o n g u e u r <= 0)

break ;w r i t e ( 1 , tampon , l o n g u e u r ) ; /∗ c o p i e s u r s o r t i e s t a n d a r d ∗/

95} ;}

/∗ −− main −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

100i n t main ( i n t argc , char ∗ a r g v [ ] ){

char ∗ nom serveur , ∗ a d r e s s e d o c u m e n t ;i n t p o r t s e r v e u r ;i n t f d ;

105i f ( a r g c != 4) {

p r i n t f ( ” Usage : %s s e r v e u r p o r t a d r e s s e−document\n” ,a r g v [ 0 ] ) ;

abandon ( ” nombre de p a r a m e t r e s i n c o r r e c t ” ) ;110}

78

Page 79: Programmation Syst`eme et Réseau sous Unix

n o m s e r v e u r = a r g v [ 1 ] ;p o r t s e r v e u r = a t o i ( a r g v [ 2 ] ) ;a d r e s s e d o c u m e n t = a r g v [ 3 ] ;

115f d = o u v r i r c o n n e x i o n t c p ( nom serveur , p o r t s e r v e u r ) ;

demander document ( fd , a d r e s s e d o c u m e n t ) ;a f f i c h e r r e p o n s e ( f d ) ;

120c l o s e ( f d ) ;

return EXIT SUCCESS ;}

Remarque : souvent il est plus commode de creer des flots de haut niveau au dessus du socket (voirfdopen()) que de manipuler des read et des write. Voir dans l’exemple suivant.

16.5.3 Realiser un serveur TCP

Un serveur TCP doit traiter des connexions venant de plusieurs clients.

Apres avoir cree et nomme le socket, le serveur specifie qu’il accepte les communications entrantespar listen(), et se met effectivement en attente d’une connexion de client par accept().

#inc lude <s y s / t y p e s . h>#inc lude <s y s / s o c k e t . h>

i n t l i s t e n ( i n t s , i n t b a c k l o g ) ;i n t a c c e p t ( i n t s , s t r u c t s o c k a d d r ∗addr ,

s o c k l e n t ∗ a d d r l e n ) ;

Le parametre backlog indique la taille maximale de la file des connexions en attente. Sous Linuxla limite est donnee par la constante SOMAXCONN (qui vaut 128), sur d’autres systemes elle est limiteea 5.

La fonction accept() renvoie un autre socket, qui servira a la communication avec le client.L’adresse du client peut etre obtenue par les parametres addr et addrlen.

En general les serveurs TCP doivent traiter plusieurs connexions simultanement. La solution habi-tuelle est de lancer, apres l’appel a accept() un processus fils (par fork())qui traite la communicationavec un seul client. Ceci induit une gestion des processus, donc des signaux lies a la terminaison desprocessus fils.

17 Exemples TCP : serveurs Web

Dans ce qui suit nous presentons un serveur Web rudimentaire, capable de fournir des pages Webconstruites a partir des fichiers d’un repertoire. Nous donnons deux implementations possibles, a l’aidede processus lourds et legers.

17.1 Serveur Web (avec processus)

17.1.1 Principe et psedo-code

Cette version suit l’approche traditionnelle. Un processus est cree chaque fois qu’un client contactele serveur.

Pseudo-code :

79

Page 80: Programmation Syst`eme et Réseau sous Unix

o u v r i r s o c k e t s e r v e u r ( s o c k e t / b i n d / l i s t e n )r e p e t e r i n d e f i n i m e n t| a t t e n d r e l ’ a r r i v e e d ’ un c l i e n t ( a c c e p t )| c r e e r un p r o c e s s u s ( f o r k ) e t l u i d e l e g u e r| l a communicat ion avec l e c l i e n tf i n−r e p e t e r

17.1.2 Code du serveur

1/∗ S e r v e u r−avec−p r o c e s s u s / s e r v e u r−web . c ∗/

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−S e r v e u r TCP

5s e r v e u r web , q u i r e n v o i e l e s f i c h i e r s ( t e x t e s )d ’ un r e p e r t o i r e s o u s forme de pages HTML

usage : s e r v e u r−web p o r t r e p e r t o i r e10exemple : s e r v e u r−web 8000 / u s r / doc / ex emples

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/

#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>

15#inc lude <s y s / e r r n o . h>#inc lude <s y s / s o c k e t . h>#inc lude <s y s / w a i t . h>#inc lude <s y s / s t a t . h>#inc lude <n e t i n e t / i n . h>

20#inc lude <arpa / i n e t . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

25#inc lude ” d e c l a r a t i o n s . h”

void a r r e t e r s e r v e u r ( i n t n u m e r o s i g n a l ) ;void a t t e n d r e s o u s s e r v e u r ( i n t n u m e r o s i g n a l ) ;

30i n t f d s e r v e u r ; /∗ v a r i a b l e g l o b a l e , pour p a r t a g e ravec t r a i t e m e n t s i g n a l f i n s e r v e u r ∗/

void d e m a r r e r s e r v e u r ( i n t numero port , char r e p e r t o i r e [ ] ){

35i n t n u m e r o c l i e n t = 0 ;i n t f d c l i e n t ;s t r u c t s i g a c t i o n a c t i o n i n t , a c t i o n c h l d ;

f d s e r v e u r = s e r v e u r t c p ( numero por t ) ;40

/∗ a r r e t du s e r v e u r s i s i g n a l SIGINT ∗/a c t i o n i n t . s a h a n d l e r = a r r e t e r s e r v e u r ;s i g e m p t y s e t (& a c t i o n i n t . sa mask ) ;a c t i o n i n t . s a f l a g s = 0 ;

80

Page 81: Programmation Syst`eme et Réseau sous Unix

45s i g a c t i o n ( SIGINT , &a c t i o n i n t , NULL ) ;

/∗ a t t e n t e f i l s s i SIGCHLD ∗/a c t i o n c h l d . s a h a n d l e r = a t t e n d r e s o u s s e r v e u r ;s i g e m p t y s e t (& a c t i o n c h l d . sa mask ) ;

50a c t i o n c h l d . s a f l a g s = SA NOCLDSTOP ;s i g a c t i o n (SIGCHLD , &a c t i o n c h l d , NULL ) ;

p r i n t f ( ”> S e r v e u r ” VERSION” ( p o r t=%d , r e p e r t o i r e de documents=\”%s \”)\n” ,

55numero port , r e p e r t o i r e ) ;

whi le ( 1 ) {s t r u c t s o c k a d d r i n a ;s i z e t l = s i z e o f a ;

60f d c l i e n t = a t t e n d r e c l i e n t ( f d s e r v e u r ) ;getsockname ( f d c l i e n t , ( s t r u c t s o c k a d d r ∗)&a , &l ) ;n u m e r o c l i e n t ++;p r i n t f ( ”> c l i e n t %d [% s ]\ n” , n u m e r o c l i e n t ,

65i n e t n t o a ( a . s i n a d d r ) ) ;

i f ( f o r k ( ) == 0) {/∗ l e p r o c e s s u s f i l s fe rme l e s o c k e t s e r v e u r e t

s ’ occupe du c l i e n t ∗/70c l o s e ( 0 ) ;

c l o s e ( 1 ) ;c l o s e ( 2 ) ;c l o s e ( f d s e r v e u r ) ;s e r v i r c l i e n t ( f d c l i e n t , r e p e r t o i r e ) ;

75c l o s e ( f d c l i e n t ) ;e x i t ( EXIT SUCCESS ) ;

}/∗ l e p r o c e s s u s p e r e n ’ a p l u s b e s o i n du s o c k e t c l i e n t .

I l l e fe rme e t r e p a r t dans l a b o u c l e ∗/80c l o s e ( f d c l i e n t ) ;

}}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−85T r a i t e m e n t des s i g n a u x

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

void a r r e t e r s e r v e u r ( i n t n u m e r o s i g n a l ){

90p r i n t f ( ”=> f i n du s e r v e u r \n” ) ;shutdown ( f d s e r v e u r , 2 ) ; /∗ u t i l e ? ∗/c l o s e ( f d s e r v e u r ) ;e x i t ( EXIT SUCCESS ) ;

}95

void a t t e n d r e s o u s s e r v e u r ( i n t n u m e r o s i g n a l ){

/∗ c e t t e f o n c t i o n e s t a p p e l e e chaque f o i s qu ’ un s i g n a l SIGCHLD

81

Page 82: Programmation Syst`eme et Réseau sous Unix

i n d i q u e l a f i n d ’ un p r o c e s s u s f i l s au moins . ∗/100whi le ( w a i t p i d (−1 , NULL , WNOHANG) > 0) {

/∗ a t t e n t e des f i l s a r r e t e s , t a n t qu ’ i l y en a ∗/}

}

105/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/void usage ( char prog [ ] ){

p r i n t f ( ” Usage : %s [ o p t i o n s \n\n” , prog ) ;p r i n t f ( ” Opt ions : ”

110”−h\ t c e m e s s a g e \n””−p p o r t \ t p o r t du s e r v e u r [%d ]\ n””−d d i r \ t r e p e r t o i r e des documents [% s ]\ n” ,PORT PAR DEFAUT , REPERTOIRE PAR DEFAUT ) ;

}115

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/i n t main ( i n t argc , char ∗ a r g v [ ] ){

i n t p o r t = PORT PAR DEFAUT ;120char ∗ r e p e r t o i r e = REPERTOIRE PAR DEFAUT ; /∗ l a r a c i n e

des documents ∗/char c ;

whi le ( ( c = g e t o p t ( argc , argv , ”hp : d : ” ) ) != −1)125switch ( c ) {

case ’ h ’ :usage ( a r g v [ 0 ] ) ;e x i t ( EXIT SUCCESS ) ;break ;

130case ’ p ’ :p o r t = a t o i ( o p t a r g ) ;break ;

case ’ d ’ :r e p e r t o i r e = o p t a r g ;

135break ;case ’ ? ’ :

f p r i n t f ( s t d e r r , ” Opt ion i n c o n n u e −%c . −h pour a i d e .\ n” ,o p t o p t ) ;

break ;140} ;

d e m a r r e r s e r v e u r ( port , r e p e r t o i r e ) ;e x i t ( EXIT SUCCESS ) ;

}

17.1.3 Discussion de la solution

Un avantage est la simplicite de la solution, et sa robustesse : une erreur d’execution dans unprocessus fils est normalement sans incidence sur le fonctionnement des autres parties du serveur.

En revanche, la creation d’un processus est une operation relativement couteuse, qui introduit untemps de latence au debut de chaque communication. D’ou l’idee de lancer les processus avant d’enavoir besoin (prechargement), et de reutiliser ceux qui ont termine leur tache.

82

Page 83: Programmation Syst`eme et Réseau sous Unix

17.2 Serveur Web (avec threads)

17.2.1 Principe et pseudo-code

Les processus legers permettent une autre approche : on cree prealablement un � pool � deprocessus que l’on bloque. Lorsqu’un client se presente, on confie la communication a un processusinoccupe.

o u v r i r s o c k e t s e r v e u r ( s o c k e t / b i n d / l i s t e n )c r e e r un p o o l de p r o c e s s u sr e p e t e r i n d e f i n i m e n t| a t t e n d r e l ’ a r r i v e e d ’ un c l i e n t ( a c c e p t )| t r o u v e r un p r o c e s s u s l i b r e , e t l u i| c o n f i e r l a communicat ion avec l e c l i e n tf i n−r e p e t e r

17.2.2 Code du serveur

1/∗ s e r v e u r−web . c ∗/

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−S e r v e u r TCP

5s e r v e u r web , q u i r e n v o i e l e s f i c h i e r s ( t e x t e s )d ’ un r e p e r t o i r e s o u s forme de pages HTML

usage : s e r v e u r−web [−p p o r t ] [−d r e p e r t o i r e ]10exemple : s e r v e u r−web −p 8000 −d / u s r / doc / exe mples

V e r s i o n b a s e e s u r l e s t h r e a d s . Au l i e u de c r e e run p r o c e s s u s par connex ion , on g e r e un p o o l de t a c h e s( sous−s e r v e u r s ) .

15− au demarrage du s e r v e u r l e s sous−s e r v e u r s s o n t c r e e s ,e t b l o q u e s par un v e r r o u− quand un c l i e n t s e connecte , l a c o n n e x i o n e s tc o n f i e e a un sous−s e r v e u r i n a c t i f , q u i e s t d e b l o q u epour l ’ o c c a s i o n .

20−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/

#inc lude <p t h r e a d . h>#inc lude <u n i s t d . h>#inc lude <s y s / t y p e s . h>

25#inc lude <s y s / e r r n o . h>#inc lude <s y s / s o c k e t . h>#inc lude <s y s / w a i t . h>#inc lude <s y s / s t a t . h>#inc lude <n e t i n e t / i n . h>

30#inc lude <arpa / i n e t . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

35#inc lude ” d e c l a r a t i o n s . h”

83

Page 84: Programmation Syst`eme et Réseau sous Unix

void a r r e t e r s e r v e u r ( i n t n u m e r o s i g n a l ) ;

#def ine NB SOUS SERVEURS 540

s t r u c t d o n n e e s s o u s s e r v e u r {p t h r e a d t i d ; /∗ i d e n t i f i c a t e u r de t h r e a d

∗/p t h r e a d m u t e x t v e r r o u ;i n t a c t i f ; /∗ 1 => sous−s e r v e u r occupe ∗/

45i n t f d ; /∗ s o c k e t du c l i e n t∗/

char ∗ r e p e r t o i r e ;} ;

s t r u c t d o n n e e s s o u s s e r v e u r p o o l [ NB SOUS SERVEURS ] ;50i n t f d s e r v e u r ; /∗ v a r i a b l e g l o b a l e , pour p a r t a g e r

avec t r a i t e m e n t s i g n a l f i n s e r v e u r ∗/

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−s o u s s e r v e u r

55−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/void ∗ e x e c u t e r s o u s s e r v e u r ( void ∗ data ){

s t r u c t d o n n e e s s o u s s e r v e u r ∗d = data ;whi le ( 1 ) {

60p t h r e a d m u t e x l o c k (&d−>v e r r o u ) ;s e r v i r c l i e n t ( d−>fd , d−>r e p e r t o i r e ) ;c l o s e ( d−>f d ) ;d−>a c t i f = 0 ;

}65return NULL ; /∗ j a m a i s e x e c u t e ∗/

}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/void c r e e r s o u s s e r v e u r s ( char r e p e r t o i r e [ ] )

70{i n t k ;

f o r ( k = 0 ; k < NB SOUS SERVEURS ; k++) {s t r u c t d o n n e e s s o u s s e r v e u r ∗d = p o o l + k ;

75d−>a c t i f = 0 ;d−>r e p e r t o i r e = r e p e r t o i r e ;p t h r e a d m u t e x i n i t (&d−>v e r r o u , NULL ) ;p t h r e a d m u t e x l o c k (&d−>v e r r o u ) ;p t h r e a d c r e a t e (&d−>id , NULL ,

80e x e c u t e r s o u s s e r v e u r , ( void ∗) d ) ;}

}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−85d e m a r r e r s e r v e u r : c r e e l e s o c k e t s e r v e u r

e t l a n c e des p r o c e s s u s pour chaque c l i e n t−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

84

Page 85: Programmation Syst`eme et Réseau sous Unix

i n t d e m a r r e r s e r v e u r ( i n t numero port , char r e p e r t o i r e [ ] )90{

i n t n u m e r o c l i e n t = 0 ;i n t f d c l i e n t ;s t r u c t s i g a c t i o n a c t i o n f i n ;

95p r i n t f ( ”> S e r v e u r ” VERSION ”+t h r e a d s ”” ( p o r t=%d , r e p e r t o i r e de documents=\”%s \”)\n” ,numero port , r e p e r t o i r e ) ;

/∗ s i g n a l SIGINT −> a r r e t du s e r v e u r ∗/100

a c t i o n f i n . s a h a n d l e r = a r r e t e r s e r v e u r ;s i g e m p t y s e t (& a c t i o n f i n . sa mask ) ;a c t i o n f i n . s a f l a g s = 0 ;s i g a c t i o n ( SIGINT , &a c t i o n f i n , NULL ) ;

105/∗ c r e a t i o n du s o c k e t s e r v e u r e t du p o o l de sous−s e r v e u r s ∗/f d s e r v e u r = s e r v e u r t c p ( numero por t ) ;c r e e r s o u s s e r v e u r s ( r e p e r t o i r e ) ;

110/∗ b o u c l e du s e r v e u r ∗/whi le ( 1 ) {

s t r u c t s o c k a d d r i n a ;s i z e t l = s i z e o f a ;i n t k ;

115f d c l i e n t = a t t e n d r e c l i e n t ( f d s e r v e u r ) ;getsockname ( f d c l i e n t , ( s t r u c t s o c k a d d r ∗) &a , &l ) ;n u m e r o c l i e n t ++;

120/∗ r e c h e r c h e d ’ un sous−s e r v e u r i n o c c u p e ∗/f o r ( k = 0 ; k < NB SOUS SERVEURS ; k++)

i f ( p o o l [ k ] . a c t i f == 0)break ;

i f ( k == NB SOUS SERVEURS) { /∗ pas de sous−s e r v e u r l i b r e ? ∗/125p r i n t f ( ”> c l i e n t %d [% s ] r e j e t e ( s u r c h a r g e )\n” ,

n u m e r o c l i e n t , i n e t n t o a ( a . s i n a d d r ) ) ;c l o s e ( f d c l i e n t ) ;

} e l s e {/∗ a f f e c t a t i o n du t r a v a i l e t d e b l o c a g e du sous−s e r v e u r ∗/

130p r i n t f ( ”> c l i e n t %d [% s ] t r a i t e par sous−s e r v e u r %d\n” ,n u m e r o c l i e n t , i n e t n t o a ( a . s i n a d d r ) , k ) ;

p o o l [ k ] . f d = f d c l i e n t ;p o o l [ k ] . a c t i f = 1 ;p t h r e a d m u t e x u n l o c k (& p o o l [ k ] . v e r r o u ) ;

135}}

}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−140T r a i t e m e n t des s i g n a u x

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

85

Page 86: Programmation Syst`eme et Réseau sous Unix

void a r r e t e r s e r v e u r ( i n t n u m e r o s i g n a l ){

145p r i n t f ( ”=> f i n du s e r v e u r \n” ) ;shutdown ( f d s e r v e u r , 2 ) ; /∗ u t i l e ? ∗/c l o s e ( f d s e r v e u r ) ;e x i t ( EXIT SUCCESS ) ;

}150

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/void usage ( char prog [ ] ){

155p r i n t f ( ” Usage : %s [ o p t i o n s \n\n” , prog ) ;p r i n t f ( ” Opt ions : ”

”−h\ t c e m e s s a g e \n””−p p o r t \ t p o r t du s e r v e u r [%d ]\ n””−d d i r \ t r e p e r t o i r e des documents [% s ]\ n” ,

160PORT PAR DEFAUT , REPERTOIRE PAR DEFAUT ) ;}

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/i n t main ( i n t argc , char ∗ a r g v [ ] )

165{i n t p o r t = PORT PAR DEFAUT ;char ∗ r e p e r t o i r e = REPERTOIRE PAR DEFAUT ; /∗ l a r a c i n e

des documents ∗/char c ;

170whi le ( ( c = g e t o p t ( argc , argv , ”hp : d : ” ) ) != −1)

switch ( c ) {case ’ h ’ :

usage ( a r g v [ 0 ] ) ;175e x i t ( EXIT SUCCESS ) ;

break ;case ’ p ’ :

p o r t = a t o i ( o p t a r g ) ;break ;

180case ’ d ’ :r e p e r t o i r e = o p t a r g ;break ;

case ’ ? ’ :f p r i n t f ( s t d e r r ,

185” Option i n c o n n u e −%c . −h pour a i d e .\ n” , o p t o p t ) ;break ;

}d e m a r r e r s e r v e u r ( port , r e p e r t o i r e ) ;e x i t ( EXIT SUCCESS ) ;

190}

17.2.3 Discussion de la solution

Cette solution presente les inconvenients symetriques de ses avantages. Les processus legers parta-geant une grande partie leur espace memoire, le crash d’un processus leger risque d’emporter le reste

86

Page 87: Programmation Syst`eme et Réseau sous Unix

du serveur.On peut utiliser le meme mecanisme de � pool de processus � avec des processus classiques. La

difficulte technique reside dans la transmission le descripteur resultant de l’accept() du serveur versun processus fils. Dans la premiere solution (fork() pour chaque connexion) le fils est lance apresl’accept(), et peut donc heriter du descripteur. Dans le cas d’un prechargement de processus fils, cen’est plus possible.

Pour ce faire, on peut utiliser le mecanisme (certes assez baroque) de transmission des informationsde service (Ancillary messages a travers une liaison par socket Unix entre deux processus : des optionsconvenables de sendmsg() permettent de faire passer un ensemble de descripteurs de fichiers d”unprocessus a un autre (qui tournent sur la meme machine, puisqu’ils communiquent par un socket Unix).Voir exemple a la fin de cette section.

17.3 Parties communes aux deux serveurs

17.3.1 Declarations et entetes de fonctions

1/∗ S e r v e u r Web − d e c l a r a t i o n s . h ∗/

#def ine CRLF ”\ r \n”#def ine VERSION ” MegaSoft 0 . 0 . 7 pour Unix ”

5#def ine PORT PAR DEFAUT 8000#def ine REPERTOIRE PAR DEFAUT ”/tmp”

#def ine FATAL( e r r ) { p e r r o r ( ( char ∗) e r r ) ; e x i t ( 1 ) ; }10

extern void s e r v i r c l i e n t ( i n t f d c l i e n t ,char r e p e r t o i r e [ ] ) ;

extern void envoyer document ( FILE ∗out ,15char nom document [ ] ,

char r e p e r t o i r e [ ] ) ;

extern void d o c u m e n t n o n t r o u v e ( FILE ∗out ,char nom document [ ] ) ;

20extern void r e q u e t e i n v a l i d e ( FILE ∗ out ) ;

extern i n t s e r v e u r t c p ( i n t numero por t ) ;

25extern i n t a t t e n d r e c l i e n t ( i n t f d s e r v e u r ) ;

17.3.2 Les fonctions orientees-reseau

– serveur tcp() : creation du socket du serveur TCP.– attendre client()

1/∗P r o j e t s e r v e u r Web − r e s e a u . cF o n c t i o n s r e s e a u

∗/5

#inc lude <s y s / t y p e s . h>#inc lude <s y s / e r r n o . h>

87

Page 88: Programmation Syst`eme et Réseau sous Unix

#inc lude <s y s / s o c k e t . h>#inc lude <s y s / w a i t . h>

10#inc lude <s y s / s t a t . h>#inc lude <n e t i n e t / i n . h>#inc lude < s i g n a l . h>#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

15#inc lude ” d e c l a r a t i o n s . h”

/∗ −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−F o n c t i o n s r e s e a u

20−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ∗/

i n t s e r v e u r t c p ( i n t numero por t ){

i n t f d ;25

/∗ demarre un s e r v i c e TCP s u r l e p o r t i n d i q u e ∗/

s t r u c t s o c k a d d r i n a d d r s e r v e u r ;s i z e t l g a d d r s e r v e u r = s i z e o f a d d r s e r v e u r ;

30/∗ c r e a t i o n de l a p r i s e ∗/f d = s o c k e t ( AF INET , SOCK STREAM, 0 ) ;i f ( f d < 0) FATAL( ” s o c k e t ” ) ;

35/∗ nommage de l a p r i s e ∗/a d d r s e r v e u r . s i n f a m i l y = AF INET ;a d d r s e r v e u r . s i n a d d r . s a d d r = INADDR ANY ;a d d r s e r v e u r . s i n p o r t = h t o n s ( numero por t ) ;i f ( b i n d ( fd , ( s t r u c t s o c k a d d r ∗)& a d d r s e r v e u r , l g a d d r s e r v e u r ) < 0)

40FATAL( ” b i n d ” ) ;

/∗ o u v e r t u r e du s e r v i c e ∗/l i s t e n ( fd , 4 ) ;return ( f d ) ;

45}

i n t a t t e n d r e c l i e n t ( i n t f d s e r v e u r ){

i n t f d c l i e n t ;50/∗ A c a u s e des s i g n a u x SIGCHLD , l a f o n c t i o n a c c e p t ( )

peut e t r e i n t e r r o m p u e quand un f i l s s e t e r m i n e .Dans ce cas , on r e l a n c e a c c e p t ( ) .

∗/whi le ( ( f d c l i e n t = a c c e p t ( f d s e r v e u r , NULL , NULL ) ) < 0) {

55i f ( e r r n o != EINTR )FATAL( ” F in anormale de a c c e p t ( ) . ” ) ;

}return ( f d c l i e n t ) ;

}

88

Page 89: Programmation Syst`eme et Réseau sous Unix

17.3.3 Les fonction de dialogue avec le client

– dialogue client() : lecture et traitement de la requete d’un client– envoyer document(),– document non trouve(),– requete invalide().

1/∗S e r v e u r−a v e c P r o c e s s u s / t r a i t e m e n t−c l i e n t . c

p r o j e t s e r v e u r WEB5Communication avec un c l i e n t

∗/

#inc lude <s t d i o . h>#inc lude < s t d l i b . h>

10#inc lude < s t r i n g . h>#inc lude <u n i s t d . h>

#inc lude ” d e c l a r a t i o n s . h”

15void s e r v i r c l i e n t ( i n t f d C l i e n t , char r e p e r t o i r e [ ] ){

FILE ∗ in , ∗ out ;char v e r b e [ 1 0 0 ] , nom document [ 1 0 0 ] ;

20i n t fd 2 ;

/∗ O u v e r t u r e de f i c h i e r s de haut n i v e a u ∗/i n = fdopen ( f d C l i e n t , ” r ” ) ;/∗ note : s i on a t t a c h e out au meme d e s c r i p t e u r que in ,

25l a f e r m e t u r e de l ’ un e n t r a i n e l a f e r m e t u r e de l ’ a u t r e ∗/fd 2 = dup ( f d C l i e n t ) ;out = fdopen ( fd2 , ”w” ) ;

/∗ l e c t u r e de l a r e q u e t e , du g e n r e30”GET q u e l q u e c h o s e . . . ” ∗/

f s c a n f ( in , ”%100 s %100 s ” , verbe , nom document ) ;f c l o s e ( i n ) ;

i f ( st rcmp ( verbe , ”GET” ) == 0)35envoyer document ( out , nom document , r e p e r t o i r e ) ;

e l s er e q u e t e i n v a l i d e ( out ) ;

f f l u s h ( out ) ; /∗ u t i l e ? ∗/f c l o s e ( out ) ;

40}

void envoyer document ( FILE ∗out ,char nom document [ ] ,char r e p e r t o i r e [ ] )

45{char n o m f i c h i e r [ 1 0 0 ] ;FILE ∗ f i c h i e r ;char l i g n e [ 1 0 0 ] ;

89

Page 90: Programmation Syst`eme et Réseau sous Unix

50s p r i n t f ( n o m f i c h i e r , ”%s%s ” , r e p e r t o i r e , nom document ) ;

i f ( s t r s t r ( n o m f i c h i e r , ” / . . / ” ) != NULL) {/∗ t e n t a t i v e d ’ a c c e s h o r s du r e p e r t o i r e ! ∗/d o c u m e n t n o n t r o u v e ( out , nom document ) ;

55return ;} ;f i c h i e r =f op en ( n o m f i c h i e r , ” r ” ) ;i f ( f i c h i e r == NULL) {

d o c u m e n t n o n t r o u v e ( out , nom document ) ;60return ;

} ;

f p r i n t f ( out ,”HTTP/ 1 . 1 200 OK” CRLF

65” S e r v e r : ” VERSION CRLF” Content−Type : t e x t / html ; c h a r s e t=i s o −8859−1” CRLFCRLF ) ;

f p r i n t f ( out ,70”<html><head><t i t l e >F i c h i e r %s</ t i t l e ></head>” CRLF

”<body b g c o l o r =\” w h i t e\”><h1>F i c h i e r %s</h1>” CRLF”<c e n t e r><t a b l e>””<t r><td b g c o l o r =\” y e l l o w \”>””< l i s t i n g >” CRLF ,

75nom document , n o m f i c h i e r ) ;

/∗ l e c o r p s du f i c h i e r ∗/whi le ( f g e t s ( l i g n e , 1 0 0 , f i c h i e r ) != NULL) {

char ∗p ;80f o r ( p=l i g n e ; ∗p != ’ \0 ’ ; p++) {

switch (∗p ) {case ’< ’ :

f p u t s ( ”& l t ; ” , out ) ;break ;

85case ’> ’ :f p u t s ( ”&gt ; ” , out ) ;break ;

case ’& ’ :f p u t s ( ”&amp ; ” , out ) ;

90break ;case ’ \n ’ :

f p u t s (CRLF , out ) ;break ;

d e f a u l t :95f p u t c (∗p , out ) ;

} ;} ;

} ;

100/∗ b a l i s e s de f i n ∗/f p u t s ( ”</ l i s t i n g ></t a b l e ></c e n t e r ></body></html>” CRLF , out ) ;

}

90

Page 91: Programmation Syst`eme et Réseau sous Unix

void d o c u m e n t n o n t r o u v e ( FILE ∗out , char nom document [ ] )105{

/∗ e n v o i de l a r e p o n s e : e n t e t e ∗/f p r i n t f ( out ,

”HTTP/ 1 . 1 404 Not Found” CRLF” S e r v e r : MegaSoft 0 . 0 . 7 (CP/M) ” CRLF

110” Content−Type : t e x t / html ; c h a r s e t=i s o −8859−1” CRLFCRLF ) ;

/∗ c o r p s de l a r e p o n s e ∗/f p r i n t f ( out ,

115”<HTML><HEAD>” CRLF”<TITLE>404 Not Found</TITLE>” CRLF”</HEAD><BODY BGCOLOR=\” y e l l o w \”>” CRLF”<H1>Pas t r o u v e !</H1>” CRLF” Le document <f o n t c o l o r =\” r e d\”><t t>%s</t t ></f on t> ”

120”demande<br>n ’ e s t pas d i s p o n i b l e .<P>” CRLF”<hr> Le webmaster ””</BODY></HTML>” CRLF ,nom document ) ;

f f l u s h ( out ) ;125}

void r e q u e t e i n v a l i d e ( FILE ∗ out ){

f p r i n t f ( out ,130”<HTML><HEAD>” CRLF

”<TITLE>400 Bad Request</TITLE>” CRLF”</HEAD><BODY BGCOLOR=\” y e l l o w \”>” CRLF”<H1>Bad Request</H1>””Vous avez envoy e une r e q u e t e que ”

135” ce s e r v e u r ne comprend pas . ” CRLF”<hr> Le webmaster ””</BODY></HTML>” CRLF ) ;

f f l u s h ( out ) ;}

17.3.4 Exercices, extensions...

Exercice : modifier traitement-client pour qu’il traite le cas des repertoires. Il devra alorsafficher le nom des objets de ce repertoire, leur type, leur taille et un lien.

Exercice : Utiliser le mecanisme de transmission de descripteur (voir exemple plus loin) pourrealiser un serveur a processus precharges.

17.3.5 Transmission d’un descripteur

L’exemple ci-dessous montre comment transmettre un descripteur d’un processus a un autre.

1/∗

exemple adapt e deh t t p : / /www. mai l−a r c h i v e . com/

5l i n u x−deve lopment−s y s @ s e n a t o r−b e d f e l l o w . mit . edu / msg01240 . html

91

Page 92: Programmation Syst`eme et Réseau sous Unix

( remplacement de a l l o c a par m a l l o c + m o d i f i c a t i o n s m i n e u r e s )∗/

/∗ p a s s f d . c −− sample program which p a s s e s a f i l e d e s c r i p t o r ∗/10

/∗ We behave l i k e a s i m p l e / b i n / cat , which o n l y h a n d l e s one argument∗ ( a f i l e name ) . We c r e a t e Unix domain s o c k e t s th rough∗ s o c k e t p a i r ( ) , and then f o r k ( ) . The c h i l d opens the f i l e whose∗ name i s p a s s e d on th e command l i n e , p a s s e s t he f i l e d e s c r i p t o r

15∗ and f i l e name back to t he parent , and then e x i t s . The p a r e n t∗ w a i t s f o r th e f i l e d e s c r i p t o r from t he c h i l d , then c o p i e s data∗ from t h a t f i l e d e s c r i p t o r to s t d o u t u n t i l no data i s l e f t . The∗ p a r e n t then e x i t s . ∗/

20#inc lude <m a l l o c . h>#inc lude < f c n t l . h>#inc lude <s t d i o . h>#inc lude < s t r i n g . h>#inc lude <s y s / s o c k e t . h>

25#inc lude <s y s / u i o . h>#inc lude <s y s /un . h>#inc lude <s y s / w a i t . h>#inc lude <u n i s t d . h>#inc lude < s t d l i b . h>

30void d i e ( char ∗message ){

p e r r o r ( message ) ;e x i t ( EXIT FAILURE ) ;

35}

/∗ C o p i e s data from f i l e d e s c r i p t o r ’ from ’ to f i l e d e s c r i p t o r ’ to ’∗ u n t i l n o t h i n g i s l e f t to be c o p i e d .

40E x i t s i f an e r r o r o c c u r s . ∗/void copyData ( i n t from , i n t to ){

char buf [ 1 0 2 4 ] ;i n t amount ;

45whi le ( ( amount = r e a d ( from , buf , s i z e o f ( buf ) ) ) > 0) {i f ( w r i t e ( to , buf , amount ) != amount ) {

d i e ( ” w r i t e ” ) ;}

}50i f ( amount < 0)

d i e ( ” r e a d ” ) ;}

/∗ The c h i l d p r o c e s s . Th i s s e n d s t he f i l e d e s c r i p t o r . ∗/55i n t c h i l d P r o c e s s ( char ∗ f i l e n a m e , i n t sock )

{i n t f d ;s t r u c t i o v e c v e c t o r ; /∗ some data to p a s s w/ th e f d ∗/s t r u c t msghdr msg ; /∗ th e complete message ∗/

92

Page 93: Programmation Syst`eme et Réseau sous Unix

60s t r u c t cmsghdr ∗cmsg ; /∗ th e c o n t r o l message ,which w i l l i n c l u d e th e f d ∗/

/∗ Open t he f i l e whose d e s c r i p t o r w i l l be p a s s e d . ∗/i f ( ( f d = open ( f i l e n a m e , O RDONLY) ) < 0) {

65p e r r o r ( ” open ” ) ;return EXIT FAILURE ;

}

70/∗ Send th e f i l e name down t he s o c k e t , i n c l u d i n g t he t r a i l i n g ’\0 ’ ∗/v e c t o r . i o v b a s e = f i l e n a m e ;v e c t o r . i o v l e n = s t r l e n ( f i l e n a m e ) + 1 ;

/∗ Put t o g e t h e r the f i r s t p a r t o f t he message .75I n c l u d e t he f i l e name i o v e c ∗/

msg . msg name = NULL ;msg . msg namelen = 0 ;msg . m s g i o v = &v e c t o r ;msg . m s g i o v l e n = 1 ;

80/∗ Now f o r the c o n t r o l message . We have to a l l o c a t e room f o r∗ th e f i l e d e s c r i p t o r . ∗/

cmsg = m a l l o c ( s i z e o f ( s t r u c t cmsghdr ) + s i z e o f ( f d ) ) ;85cmsg−>c m s g l e n = s i z e o f ( s t r u c t cmsghdr ) + s i z e o f ( f d ) ;

cmsg−>c m s g l e v e l = SOL SOCKET ;cmsg−>cmsg type = SCM RIGHTS ;

/∗ copy th e f i l e d e s c r i p t o r onto t he end o f90th e c o n t r o l message ∗/

memcpy (CMSG DATA( cmsg ) , &fd , s i z e o f ( f d ) ) ;

msg . m s g c o n t r o l = cmsg ;msg . m s g c o n t r o l l e n = cmsg−>c m s g l e n ;

95i f ( sendmsg ( sock , &msg , 0) != v e c t o r . i o v l e n )

d i e ( ” sendmsg ” ) ;

f r e e ( cmsg ) ;100return EXIT SUCCESS ;

}

/∗ The p a r e n t p r o c e s s . Th i s r e c e i v e s the f i l e d e s c r i p t o r . ∗/i n t p a r e n t P r o c e s s ( i n t sock )

105{char buf [ 8 0 ] ; /∗ s p a c e to r e a d f i l e name i n t o ∗/s t r u c t i o v e c v e c t o r ; /∗ f i l e name from the c h i l d ∗/s t r u c t msghdr msg ; /∗ f u l l message ∗/s t r u c t cmsghdr ∗cmsg ; /∗ c o n t r o l message w i t h t he f d ∗/

110i n t f d ;

/∗ s e t up the i o v e c f o r t he f i l e name ∗/v e c t o r . i o v b a s e = buf ;

93

Page 94: Programmation Syst`eme et Réseau sous Unix

v e c t o r . i o v l e n = 8 0 ;115

/∗ th e message we ’ r e e x p e c t i n g to r e c e i v e ∗/msg . msg name = NULL ;msg . msg namelen = 0 ;msg . m s g i o v = &v e c t o r ;

120msg . m s g i o v l e n = 1 ;

/∗ d y n a m i c a l l y a l l o c a t e so we can l e a v e room f o r t he f i l e∗ d e s c r i p t o r ∗/

cmsg = a l l o c a ( s i z e o f ( s t r u c t cmsghdr ) + s i z e o f ( f d ) ) ;125cmsg−>c m s g l e n = s i z e o f ( s t r u c t cmsghdr ) + s i z e o f ( f d ) ;

msg . m s g c o n t r o l = cmsg ;msg . m s g c o n t r o l l e n = cmsg−>c m s g l e n ;

i f ( ! recvmsg ( sock , &msg , 0 ) )130return EXIT FAILURE ;

p r i n t f ( ” got f i l e d e s c r i p t o r f o r ’% s ’\n” , ( char ∗) v e c t o r . i o v b a s e ) ;

/∗ grab t he f i l e d e s c r i p t o r from th e c o n t r o l s t r u c t u r e ∗/135memcpy(&fd , CMSG DATA( cmsg ) , s i z e o f ( f d ) ) ;

copyData ( fd , 1 ) ;

return EXIT SUCCESS ;140}

i n t main ( i n t argc , char ∗∗ a r g v ){

i n t s o c k s [ 2 ] ;145i n t s t a t u s ;

i f ( a r g c != 2) {f p r i n t f ( s t d e r r , ” o n l y a s i n g l e argument i s s u p p o r t e d \n” ) ;return 1 ;

150}

/∗ C r e a t e t he s o c k e t s . The f i r s t i s f o r t he p a r e n t and t he∗ second i s f o r t he c h i l d ( though we c o u l d r e v e r s e t h a t∗ i f we l i k e d . ∗/

155i f ( s o c k e t p a i r ( PF UNIX , SOCK STREAM, 0 , s o c k s ) )d i e ( ” s o c k e t p a i r ” ) ;

i f ( f o r k ( ) == 0 ) { /∗ c h i l d ∗/c l o s e ( s o c k s [ 0 ] ) ;

160return c h i l d P r o c e s s ( a r g v [ 1 ] , s o c k s [ 1 ] ) ;}

/∗ p a r e n t ∗/c l o s e ( s o c k s [ 1 ] ) ;

165p a r e n t P r o c e s s ( s o c k s [ 0 ] ) ;

w a i t (& s t a t u s ) ;

94

Page 95: Programmation Syst`eme et Réseau sous Unix

i f (WEXITSTATUS( s t a t u s ) )170f p r i n t f ( s t d e r r , ” c h i l d f a i l e d \n” ) ;

return EXIT SUCCESS ;}

18 Documentation

Les documents suivants ont ete tres utiles pour la redaction de ce texte et la programmation desexemples :

– Unix Frequently Asked Questions http://www.erlenstar.daemon.co.uk/unix/faq_toc.

html" (lien obsolete)– HP-UX Reference, volume 2 (section 2 and 3, C programming routines). HP-UX release 8.0,

Hewlett-Packard. (Janvier 1991).– Advanced Unix Programming, Marc J. Rochkind, Prentice-Hall Software Series (1985). ISBN

0-13-011800-1.– Linux online man pages (Distribution Slackware 3.1).– The GNU C Library Reference Manual, Sandra Loosemore, Richard M. Stallman, Roland Mc-

Grath, and Andrew Oram. Edition 0.06, 23-Dec-1994, pour version 1.09beta. Free SoftwareFoundation, ISBN 1-882114-51-1.

– What is multithreading ?, Martin McCarthy, Linux Journal 34, Fevrier 1997, pages 31 a 40.– Systemes d’exploitation distribues, Andrew Tanenbaum, InterEditions 1994, ISBN 2-7296-0706-4.– Page Web de Xavier Leroy sur les threads : http://pauillac.inria.fr/~xleroy/

linuxthreads

95