Comme je vous l'ai dit, pour communiquer il faut passer par des sockets, donc le serveur doit en avoir une.
Tout d'abord, on créé la fonction, et on créé les différentes variables :
1
2
3
4
5
6
7
8
9
|
int createTCPsocketServer(const char* port, int nbConnexion){
int sockfd; struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
|
Ensuite on initialise la variable hints :
1
2
3
4
|
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
|
On test si tout a bien fonctionné :
1
2
3
4
|
if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
|
Après, on boucle sur les résultat, et on regarde lequel on peut prendre :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
for(p = servinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server: socket");
continue;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("setsockopt");
exit(1);
}
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("server: bind");
continue;
}
break;
}
|
On test si on a bien trouvé quelque chose :
1
2
3
4
|
if(p == NULL){
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
|
On dégomme la structure servinfo et on dit que l'on va écouter :
1
2
3
4
5
|
freeaddrinfo(servinfo); if(listen(sockfd, nbConnexion) == -1){
perror("listen");
exit(1);
}
|
On dit comment dégommer les processus mort, on test la fin de l'initialisation et on renvoie la socket :
1
2
3
4
5
6
7
8
9
|
sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1){
perror("sigaction");
exit(1);
}
return sockfd;
}
|
Voilà ce que ça donne en entier :
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
|
int createTCPsocketServer(const char* port, int nbConnexion){
int sockfd; struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
for(p = servinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server: socket");
continue;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("setsockopt");
exit(1);
}
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if(p == NULL){
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
freeaddrinfo(servinfo); if(listen(sockfd, nbConnexion) == -1){
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1){
perror("sigaction");
exit(1);
}
return sockfd;
}
|
Voilà pour la création de la socket du server.
Mais cette fonction est plus grande que mon écran ! Il faut la découper.
C'est vrai cette fonction est longue, mais si vous la découpez vous allez perdre le fil.
Si vous avez UNE ou DEUX fonction trop longues dans votre programme (quand je dis trop longues je dis 50 ou 60 lignes, pas 200) ce n'est pas grave du moment que ce qui est dedans est clair.
|