17. Annexes▲
17-1. Programme serv2prot.c▲
Cacher/Afficher le codeSélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
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.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
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.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
/* $Id: serv2prot.c 134 2009-02-27 16:38:44Z fla $
*
* Exemple de serveur d'écho , parallèle et multiprotocole (TCP, UDP).
*
* Compiler avec -DBAVARD pour des commentaires sur les états du serveur.
* Le serveur se stoppe avec un SIGHUP.
*
* Compiler avec -DBSD sur les OS BSD.
*
*/
#include <stdio.h> /* De toute façon ! */
#include <errno.h> /* Idem */
#include <stdlib.h> /* Pour "atoi". */
#include <unistd.h> /* Pour "getopt". */
#include <strings.h> /* Pour "bcopy". */
#include <signal.h> /* Pour "signal". */
#include <time.h> /* Pour "select". */
#include <sysexits.h> /* Codes de retour */
#include <sys/wait.h> /* Pour "wait". */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* Pour "inet_ntoa" */
#include <netdb.h> /* Pour "getservbyname" */
extern char *optarg ;
extern int optind , opterr ;
int OuvrirSocketUDP(char *, int) ;
int OuvrirSocketTCP(char *, int, int) ;
int PortParLeNom(char *, char *) ;
void TraiterTCP(int) ;
void TraiterUDP(int) ;
void PasDeZombi(int) ;
void FinCanonique(int) ;
#define max(a,b) (a > b ? a : b)
#define USAGE "Usage:%s -p <numéro de port > [-n|-w]\n\t-n : serveur parallèle\n\t-w : serveur itératif (défaut)\n"
#define VRAI (1)
#define FAUX (0)
#define MAXQ 5
#ifdef BSD
#define CAST fdset *
#define CAST2 struct rusage *
#else
#define CAST int *
#define CAST2 int *
#endif
#ifdef BAVARD
#define PRINTF (void)printf
#else
#define PRINTF if (0) (void)printf
#endif
int sudp, stcp ; /* Descrip. de socket. */
pid_t tcp_pid, udp_pid ; /* ceux des fils. */
int iteratif ; /* VRAI:serv. itératif. */
fd_set lect, alire ; /* Pour le 'select '. */
struct sockaddr_in sclient ; /* Pour le getpeername */
int
main(int argc, char *argv[])
{
int c ; /* Brouillon */
int nport ; /* N°port du serveur. */
int ndes ; /* Retour de 'select '. */
int sock ; /* Pour le 'accept '. */
int intcp
pid_t pid ; /* Pour le "fork". */
socklen_t slen ;
nport = -1 ; /* Non configuré. */
iteratif = VRAI ; /* Itératif par défaut. */
opterr = 0 ; /* cf "man 3 getopt" */
while ( ( c=getopt(argc ,argv, "p:nw")) != EOF ) {
switch(c) {
case 'p' : /* Numéro du port. */
nport = atoi(optarg) ;
break ;
case 'w' : /* 'wait' = Itératif. */
iteratif = VRAI ;
break ;
case 'n' : /* 'nowait' = Parallèle.*/
iteratif = FAUX ;
break ;
default : /* Erreur !! */
(void)fprintf(stderr, USAGE, argv[0]) ;
exit ( EX_USAGE ) ;
}
}
if (nport < 0) {
(void)fprintf(stderr, USAGE, argv[0]) ;
exit ( EX_USAGE ) ;
}
if (iteratif==VRAI)
PRINTF ( "***Début du server itératif\n" ) ;
else
PRINTF ( "***Début du server parallèle\n" ) ;
sudp = OuvrirSocketUDP("", nport) ;
stcp = OuvrirSocketTCP("", nport, MAXQ) ;
c = max(sudp, stcp) + 1 ; /* Rang bit + `a gauche. */
FD_ZERO(&lect) ; /* cf "<sys/types.h>" */
FD_SET(sudp, &lect) ;
FD_SET(stcp, &lect) ;
(void)signal(SIGCHLD, PasDeZombi) ; /* Mort d'un proc. fils */
(void)signal(SIGHUP, FinCanonique) ; /* Fin "propre". */
while (VRAI) { /* Tourne toujours ! */
alire = lect ;
PRINTF ( "***Lecture bloquante du 'select '\n" ) ;
if ((ndes = select(c , (CAST)&alire, (CAST)0, (CAST)0,\
(struct timeval *)0))<0) {
if (errno == EINTR) /* A cause d'une inter. */
continue ;
perror("select") ;
exit(EX_OSERR) ;
}
while (ndes) { /* ndes >= 0 */
if (FD_ISSET(stcp, &alire)) {
PRINTF("***Sélection de l'entrée TCP\n") ;
if ((sock=accept(stcp, (struct sockaddr *) 0, (socklen_t *)0))<0) {
perror("accept") ;
exit(EX_OSERR) ;
}
intcp = VRAI ;
}
else if (FD_ISSET(sudp, &alire)) {
PRINTF("***Sélection de l'entrée UDP\n") ;
sock = sudp ;
intcp = FAUX ;
}
if (getpeername(sock, (struct sockaddr *)&sclient, &slen) < 0)
perror("Getpeername") ;
else
PRINTF("***Nouveau client : %s:%d\n" ,\
inet_ntoa(sclient.sin_addr), ntohs(sclient.sin_port)) ;
retry :
pid=fork() ;
switch(pid) {
case -1 : /* Erreur. */
if (errno==EINTR) goto retry ;
perror ( "fork" ) ;
exit ( EX_OSERR ) ;
case 0 : /* Fils. */
if (intcp==VRAI) {
(void)close(sudp) ;
(void)close(stcp) ;
TraiterTCP(sock) ;
}
else {
(void)close(stcp) ;
TraiterUDP(sock) ;
}
exit(EX_OK) ;
default : /* Père. */
if (iteratif==VRAI)
FD_CLR (intcp==VRAI?stcp:sudp, &lect) ;
if (intcp==VRAI) {
(void)close(sock) ;
FD_CLR(stcp, &alire) ;
tcp_pid = pid ;
}
else {
udp_pid = pid ;
FD_CLR(sudp, &alire) ;
}
}
ndes-- ;
}
}
}
/*
* PasDeZombi : Gestion des processus fils qui se terminent.
*/
void
PasDeZombi(int nsig)
{
pid_t pid ;
int status ;
PRINTF("***On a reçu un SIGCHLD\n") ;
/*
* WNOHANG : évite que wait3 soit bloquant , m^eme si des fils sont
* encore en activité (retour 0).
*/
while ((pid=wait3(&status, WNOHANG, (CAST2)0)) > 0)
if (iteratif==VRAI)
if (pid==tcp_pid) {
FD_SET(stcp, &lect) ;
PRINTF("***L'entrée TCP est réactivée\n") ;
break ;
}
else if (pid==udp_pid) {
FD_SET(sudp, &lect) ;
PRINTF("***L'entrée UDP est réactivée\n") ;
break ;
}
#ifndef BSD
(void)signal ( SIGCHLD , PasDeZombi ) ; /* Selon OS */
#endif
}
/*
* FinCanonique : On passe par l`a en cas de fin normale.
*/
void
FinCanonique(int nsig)
{
PRINTF("***Signal SIGHUP reçu - Fin du serveur !\n") ;
exit(EX_OK) ;
}
/*
* Serveur d'écho , TCP.
*/
void
TraiterTCP(int des)
{
int n ;
char buf[1024] ;
PRINTF("***On entre dans TraiterTCP , chaîne lue :\n") ;
while ((n=read(des, buf, sizeof buf)) > 0 ) {/* == 0 -> EOF */
buf[n] = '\0' ;
PRINTF("***On renvoie (TCP) %s", buf) ;
if (write(des, buf, n) < 0)
perror ( "write - TCP" ) ;
}
PRINTF("\n" ) ;
PRINTF("*** Déconnexion de %s:%d\n", inet_ntoa(sclient.sin_addr),\
ntohs(sclient.sin_port));
}
/*
* Serveur d'echo , UDP.
*/
void
TraiterUDP(int des)
{
char buf[BUFSIZ] ;
int n ;
socklen_t ladr ;
struct sockaddr adr ;
PRINTF("***On entre dans TraiterUDP , chaîne lue :\n") ;
ladr = sizeof adr ;
if ((n=recvfrom(des, buf, sizeof buf, 0, (struct sockaddr *)&adr, &ladr)) < 0)
return ;
buf[n] = '\0' ;
PRINTF( "***On renvoie (UDP) :%s\n", buf) ;
(void)sendto(des, buf, n, 0, (struct sockaddr *)&adr, ladr) ;
}
/*
* OuvrirSocketUDP : Ouvre une socket UDP et renvoie le descripteur
*/
int
OuvrirSocketUDP(char *nserv, int nport)
{
struct sockaddr_in sadr ;
int sd ;
int np = htons(nport) ;
if (np < 0)
if ((np=PortParLeNom(nserv, "udp")) < 0)
return -1 ;
if ((sd=socket(PF_INET, SOCK_DGRAM , 0)) < 0) {
perror("socket - SOCK_DGRAM" ) ;
exit(EX_OSERR) ;
}
bzero((char *)&sadr, sizeof sadr) ;
sadr.sin_family = PF_INET ;
sadr.sin_port = np ;
if (bind(sd, (struct sockaddr *)&sadr, sizeof sadr) < 0) {
perror("bind - SOCK_DGRAM") ;
exit(EX_OSERR) ;
}
return sd ;
}
/*
* OuvrirSocketTCP : Ouvre une socket TCP et renvoie le descripteur
*/
int
OuvrirSocketTCP(char *nserv, int nport, int queue)
{
struct sockaddr_in sadr ;
int sd ;
int np = htons(nport) ;
if (np < 0)
if ((np=PortParLeNom(nserv, "tcp")) < 0)
return -1 ;
if ((sd=socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket - SOCK_STREAM") ;
exit(EX_OSERR) ;
}
bzero((char *)&sadr, sizeof sadr) ;
sadr.sin_family = PF_INET ;
sadr.sin_port = np ;
if (bind(sd, (struct sockaddr *)&sadr, sizeof sadr) < 0) {
perror("bind - SOCK_STREAM") ;
exit(EX_OSERR) ;
}
if (listen(sd, queue) < 0) {
perror("listen - SOCK_STREAM") ;
exit(EX_OSERR) ;
}
return sd ;
}
int
PortParLeNom(char *nserv, char *nprot)
{
struct servent *serv ;
if (getservbyname(nserv, nprot) == NULL )
return -1 ;
return serv->s_port ; /* Respecte le NBO. */
}
17-2. Remerciements Developpez▲
Vous pouvez retrouver l'article original ici : Cours d'introduction à TCP/IP. François Laissus a aimablement autorisé l'équipe « Réseaux » de Developpez.com à reprendre son article.
Nos remerciements à zoom61, ClaudeLELOUP, f-leb et _Max_ pour leur relecture orthographique.
N'hésitez pas à commenter ce document ! Commentez ![]()

