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