Académique Documents
Professionnel Documents
Culture Documents
Dpartement IRIS
http://www.diderot.org
TP n5
Version - Date
Version 1.2 - Sept 2008
Nom du fichier
TP-5-Reseaux-Client-serveur.docx
TP n5
A. Sommaire
A. SOMMAIRE.................................................................................................................................................................................. 2
B. OBJECTIFS ................................................................................................................................................................................... 3
C. ETUDE DU CLIENT.......................................................................................................................................................................... 3
C.1. Cration du socket ........................................................................................................................................................... 3
C.2. Programme principal ....................................................................................................................................................... 4
a. Vue densemble ............................................................................................................................................................................................ 4
b. Paramtres.................................................................................................................................................................................................... 4
c. Boucle de fond .............................................................................................................................................................................................. 4
d. Slection de descripteurs ............................................................................................................................................................................ 4
e. Algorigramme ............................................................................................................................................................................................... 5
f. Taille des buffers ........................................................................................................................................................................................... 6
D. ETUDE DU SERVEUR....................................................................................................................................................................... 6
D.1. Structure du programme ................................................................................................................................................. 6
D.2. Cration du socket server ................................................................................................................................................ 7
a. Paramtre SO_REUSEADDR ................................................................................................................................................................... 7
b. Ecoute de port .............................................................................................................................................................................................. 7
2 / 15
TP n5
B. Objectifs
Cest de comprendre le fonctionnement des sockets TCP en langage C. Pour y arriver, il sagira dtudier
et de mettre en uvre un programme ralisant une application client/serveur.
Le listing du programme tudier est en annexe. Il sagit du programme dexemple dtaill dans le cours
Cours et Travaux pratiques en C A. Lebret .
Le programme est en 2 parties : La partie client (client.c) et la partie serveur (serveur.c).
C. Etude du client
C.1. Cration du socket
Quelle partie du programme est-elle charge dinitialiser le socket client ?
Lignes : ____________
Quel est le rle de la fonction inet_addr ? Expliquez la signification et le rle des paramtres et de la
valeur de retour de cette fonction :
3 / 15
TP n5
A quoi sert prcisment la fonction memcpy utilise la ligne 46 et quel rle remplit-elle dans le
programme (Voir le dtail de la structure hostent ).
Client.c
b. Paramtres
Quels sont les paramtres passs au programme et comment sont-ils utiliss ?
c. Boucle de fond
Expliquez la particularit de la boucle for et lincidence sur la dure du programme.
d. Slection de descripteurs
Donnez la dfinition dun descripteur de fichiers (file handle) et prcisez avec quels descripteurs le
programme va-t-il travailler ?
4 / 15
TP n5
e. Algorigramme
Compltez lalgorigramme suivant reprsentant le fonctionnement du programme principal
non
3 arguments ?
oui
Initialiser Socket
Ecoute socket
Ecoute clavier
Sel.
Descripteurs
ok ?
oui
oui
non
FIN
Rception
Socket ?
Lecture caractres
depuis socket
non
oui
Lecture
clavier ?
Lecture
caractres
non
5 / 15
TP n5
b. Modification du client
Vous allez modifier le client afin dajouter une commande permettant de quitter. Cette commande
permettra au client de fermer la connexion et stopper le programme ds que le client tape la chane
/quit .
Pour cela, il faut effectuer une comparaison de chanes entre le texte saisi par lutilisateur et la chaine
/quit qui sert quitter.
Modifiez le client afin quil prenne en charge la commande /quit . Testez et validez le fonctionnement.
Les fonctions stcmp ou strncmp peuvent tre utilises pour comparer des chanes.
D. Etude du serveur
D.1. Structure du programme
Observez le code source serveur.c et indiquez le nom et le rle de chaque fonction (main, serveur et
socket_serveur) en compltant le tableau suivant :
Fonction
Paramtres
Rle
6 / 15
TP n5
Reprez, dans le code source, la cration du socket serveur. Quelle est la diffrence avec la cration dun
socket client ?
a. Paramtre SO_REUSEADDR
Lors de la cration du socket serveur, un paramtre SO_REUSEADDR est utilis.
A quoi sert ce paramtre et dans quel(s) cas sera-t-il le plus utile ?
b. Ecoute de port
Quelles sont les 2 oprations effectuer pour que le socket serveur nouvellement cr puisse couter et
accepter les connexions venant des clients ?
7 / 15
TP n5
b. Fonction main
Voici lalgorigramme de la fonction main
Compltez cet algorigramme en vous aidant du listing du programme serveur
8 / 15
TP n5
9 / 15
TP n5
d. Modification du serveur
Vous allez modifier le serveur afin dajouter une commande permettant de quitter. Cette commande
permettra au serveur de fermer la connexion avec un client et de stopper le programme.
Pour cela, il faut effectuer une comparaison de chanes entre le texte saisi par lutilisateur et la chaine
/quit qui sert quitter.
Modifiez le serveur afin quil prenne en charge la commande /quit . Testez et validez le fonctionnement.
Les fonctions stcmp ou strncmp peuvent tre utilises pour comparer des chanes.
10 / 15
TP n5
/*
* Client en C
*
* A.LEBRET
*/
#include <sys/types.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
/*---------------------------------------------- */
int socket_client( char *serveur , unsigned short port ) {
int client_socket ;
struct hostent *hostent ;
struct sockaddr_in serveur_sockaddr_in ;
client_socket = socket( PF_INET , SOCK_STREAM , 0 ) ;
if ( client_socket == -1 ) {
perror( "socket" ) ;
exit( EXIT_FAILURE ) ;
}
if ( inet_addr( serveur ) == INADDR_NONE ) /* nom */ {
hostent = gethostbyname( serveur ) ;
if ( hostent == NULL ) {
perror( "gethostbyname" ) ;
exit( EXIT_FAILURE ) ;
}
}
else /* adresse IP */ {
unsigned long addr = inet_addr( serveur ) ;
hostent = gethostbyaddr((char *)&addr, sizeof(addr),
AF_INET ) ;
if ( hostent == NULL ) {
perror( "gethostbyaddr" ) ;
exit( EXIT_FAILURE ) ;
}
}
memset(&serveur_sockaddr_in, 0,
sizeof(serveur_sockaddr_in));
serveur_sockaddr_in.sin_family = AF_INET ;
serveur_sockaddr_in.sin_port = htons(port) ;
memcpy( &serveur_sockaddr_in.sin_addr.s_addr ,
hostent->h_addr_list[0] ,
hostent->h_length) ;
printf( ">>> Connexion vers le port %d de %s [%s]\n" ,
port , hostent->h_name ,
inet_ntoa( serveur_sockaddr_in.sin_addr ) ) ;
if ( connect(client_socket,
(struct sockaddr *)&serveur_sockaddr_in,
sizeof(serveur_sockaddr_in)) == -1 ) {
perror( "connect" ) ;
11 / 15
TP n5
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
exit( EXIT_FAILURE ) ;
}
return client_socket ;
}
/*---------------------------------------------- */
int main(int argc , char **argv) {
char *serveur ;
unsigned short port ;
int client_socket ;
if ( argc != 3 ) {
fprintf(stderr, "usage: %s serveur port\n",
argv[0]);
exit( EXIT_FAILURE ) ;
}
serveur = argv[1] ;
port = atoi( argv[2] ) ;
client_socket = socket_client( serveur , port ) ;
for ( ; ; ) {
fd_set rset ;
FD_ZERO( &rset ) ;
FD_SET( client_socket , &rset ) ;
FD_SET( STDIN_FILENO , &rset ) ;
if (select(client_socket+1, &rset, NULL, NULL, NULL)
== -1 ) {
perror( "select" ) ;
exit( EXIT_FAILURE ) ;
}
if (FD_ISSET(client_socket, &rset)) {
int octets ;
unsigned char tampon[BUFSIZ] ;
octets = read(client_socket, tampon, sizeof(tampon));
if ( octets == 0 ) {
close( client_socket ) ;
exit( EXIT_SUCCESS ) ;
}
write( STDOUT_FILENO , tampon , octets ) ;
}
if ( FD_ISSET( STDIN_FILENO , &rset ) ) {
int octets ;
unsigned char tampon[BUFSIZ] ;
octets = read(STDIN_FILENO, tampon, sizeof(tampon));
if ( octets == 0 ) {
close( client_socket ) ;
exit( EXIT_SUCCESS ) ;
}
write( client_socket , tampon , octets ) ;
}
}
exit( EXIT_SUCCESS ) ;
}
12 / 15
TP n5
/*
* Serveur en C
*
* A.LEBRET
*/
#include <sys/types.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
/* --------------------------------------------- */
int socket_serveur( unsigned short port ) {
int serveur_socket , option = 1 ;
struct sockaddr_in serveur_sockaddr_in ;
serveur_socket = socket( PF_INET , SOCK_STREAM , 0 ) ;
if ( serveur_socket == -1 ) {
perror( "socket" ) ;
exit( EXIT_FAILURE ) ;
}
if ( setsockopt(serveur_socket, SOL_SOCKET, SO_REUSEADDR,
&option, sizeof(option)) == -1 ) {
perror( "setsockopt" ) ;
exit( EXIT_FAILURE ) ;
}
memset(&serveur_sockaddr_in, 0,
sizeof (serveur_sockaddr_in));
serveur_sockaddr_in.sin_family = AF_INET ;
serveur_sockaddr_in.sin_port = htons( port ) ;
serveur_sockaddr_in.sin_addr.s_addr = INADDR_ANY ;
if ( bind( serveur_socket ,
(struct sockaddr *) &serveur_sockaddr_in,
sizeof(serveur_sockaddr_in) ) == -1 ) {
perror( "bind" ) ;
exit( EXIT_FAILURE ) ;
}
if ( listen( serveur_socket , SOMAXCONN ) == -1 ) {
perror( "listen" ) ;
exit( EXIT_FAILURE ) ;
}
return serveur_socket ;
}
/* ----------------------------------------------------- */
void serveur( int client_socket ) {
for ( ; ; ) {
fd_set rset ;
FD_ZERO( &rset ) ;
FD_SET( client_socket , &rset ) ;
FD_SET( STDIN_FILENO , &rset ) ;
if ( select(client_socket+1, &rset,
NULL, NULL, NULL ) == -1 ) {
perror( "select" ) ;
exit( EXIT_FAILURE ) ;
13 / 15
TP n5
58
}
59
if ( FD_ISSET( client_socket , &rset ) ) {
60
int octets ;
61
unsigned char tampon[BUFSIZ] ;
62
octets = read(client_socket, tampon, sizeof(tampon));
63
if ( octets == 0 ) {
64
close( client_socket ) ;
65
printf( ">>> Dconnexion\n" ) ;
66
exit( EXIT_SUCCESS ) ;
67
}
68
write( STDOUT_FILENO , tampon , octets ) ;
69
}
70
if ( FD_ISSET( STDIN_FILENO , &rset ) ) {
71
int octets ;
72
unsigned char tampon[BUFSIZ] ;
73
octets = read(STDIN_FILENO, tampon, sizeof(tampon));
74
if ( octets == 0 ) {
75
close( client_socket ) ;
76
exit( EXIT_SUCCESS ) ;
77
}
78
write( client_socket , tampon , octets ) ;
79
}
80
}
81 }
82 /* ------------------------------------------------ */
83 int main( int argc , char **argv ) {
84
unsigned short port ;
85
int serveur_socket ;
86
if ( argc != 2 ) {
87
fprintf( stderr , "usage: %s port\n" , argv[0] ) ;
88
exit( EXIT_FAILURE ) ;
89
}
90
port = atoi( argv[1] ) ;
91
serveur_socket = socket_serveur( port ) ;
92
for ( ; ; ) {
93
fd_set rset ;
94
FD_ZERO( &rset ) ;
95
FD_SET( serveur_socket , &rset ) ;
96
FD_SET( STDIN_FILENO , &rset ) ;
97
if (select(serveur_socket+1, &rset,
98
NULL, NULL, NULL) == -1 ) {
99
perror( "select" ) ;
100
exit( EXIT_FAILURE ) ;
101
}
102
if ( FD_ISSET( serveur_socket , &rset ) ) {
103
int client_socket ;
104
struct sockaddr_in client_sockaddr_in ;
105
socklen_t taille=sizeof (client_sockaddr_in);
106
struct hostent *hostent ;
107
client_socket = accept( serveur_socket ,
108
(struct sockaddr *) &client_sockaddr_in ,
109
&taille ) ;
110
if ( client_socket == -1 ) {
111
perror( "accept" ) ;
112
exit( EXIT_FAILURE ) ;
113
}
114
switch ( fork( ) ) {
115
case -1 : /* erreur */
116
perror( "fork" ) ;
117
exit( EXIT_FAILURE ) ;
118
case 0 : /* processus fils */
119
close( serveur_socket ) ;
14 / 15
TP n5
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 }
140
141
hostent = gethostbyaddr(
(char *)&client_sockaddr_in.sin_addr.s_addr,
sizeof(client_sockaddr_in.sin_addr.s_addr),
AF_INET) ;
if ( hostent == NULL ) {
perror( "gethostbyaddr" ) ;
exit( EXIT_FAILURE ) ;
}
printf(">>> Connexion depuis %s [%s]\n",
hostent->h_name,
inet_ntoa( client_sockaddr_in.sin_addr ) ) ;
serveur( client_socket ) ;
exit( EXIT_SUCCESS ) ;
default : /* processus pre */
close( client_socket ) ;
}
}
}
exit( EXIT_SUCCESS ) ;
15 / 15