5.1.3 La fonction qui créée la socket du serveur

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;  // listen on sock_fd, new connexion on new_fd
	struct addrinfo hints, *servinfo, *p;
	struct sockaddr_storage their_addr; // connector's address information
	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); // all done with this structure
	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; // reap all dead processes
	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;  // listen on sock_fd, new connexion on new_fd
	struct addrinfo hints, *servinfo, *p;
	struct sockaddr_storage their_addr; // connector's address information
	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; // use my IP

	if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0){
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
		exit(1);
	}
	// loop through all the results and bind to the first we can
	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); // all done with this structure
	if(listen(sockfd, nbConnexion) == -1){
		perror("listen");
		exit(1);
	}
	sa.sa_handler = sigchld_handler; // reap all dead processes
	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.