Après avoir créé la socket, il va falloir indiquer le port sur lequel on écoutera les demande de connexion et éventuellement préciser l'adresse si on ne veut pas écouter toutes les adresses de la machine. Pour cela, on utilisera la fonction bind en lui passant 3 paramètres :
Il va donc falloir déclarer une variante de la structure sockaddr correspondant à AF_INET. Il s'agit du type struct sockaddr_in. On commencera par mettre à zéro le contenu de cette structure via la fonction bzero de string.h, puis on affectera, au premier champ nommé ici sin_family, la valeur AF_INET.
struct sockaddr_in adr_srv; bzero(&adr_srv, sizeof(adr_srv)); adr_srv.sin_family = AF_INET;
Il faut ensuite remplir, dans la structure, le champ sin_port avec le numéro de son port TCP sur laquelle le serveur écoute et éventuellement le champ sin_addr avec l'adresse IPv4. (On peut également laisser à zéro l'adresse IPv4 pour écouter sur toutes les interfaces.)
inet_aton("127.0.0.1", &adr_srv.sin_addr); adr_srv.sin_port = htons(80);
Ayant ainsi précisé l'adresse 127.0.0.1 et le port 80, il ne reste plus qu'à appeler la fonction bind pour que le serveur soit configuré pour se mettre en écoute des clients. On doit ensuite appelé la fonction listen qui fixe la file d'attente des clients arrivant simultanément.
bind(fd_srv, (struct sockaddr *) &adr_srv, sizeof(adr_srv)); listen(fd_srv, 5);
Il faut ensuite attendre, dans une boucle while, l'arrivée de chaque connexion d'un client et obtenir un socket de connexion vers ce client tandis que l'on conserve le socket du serveur pour recevoir les clients suivant.
Pour obtenir un socket permettant le dialogue avec le client, on utilisera la fonction accept qui demande 3 paramètres :
int fd_con; struct sockaddr_in adr_cli; socklen_t adr_cli_len; adr_cli_len = sizeof(adr_cli); fd_con = accept(fd_srv, (struct sockaddr *) &adr_cli, &adr_cli_len);
On pourra alors utiliser le nouveau socket pour communiquer avec le client. Et quand le dialogue est fini, l'un des protagonistes de la communication doit avertir son homologue de la fermeture du socket via la fonction : shutdown puis fermer le socket via la fonction : close de la bibliothèque unistd.h. C'est primordial de le faire côté serveur afin de libérer la place occupée, dans le kernel, par les sockets ouvertes pour chaque client.
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <netdb.h> #include <sys/socket.h> #include <string.h> // pour la fonction bzero #include <arpa/inet.h> // pour la fonction inet_addr void communication_serveur(int fd) { } int main() { int fd_srv, fd_con; struct sockaddr_in adr_srv, adr_cli; int err; socklen_t adr_cli_len; fd_srv = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd_srv<0) { printf("Erreur de creation de la socket !\n"); exit(1); } bzero(&adr_srv, sizeof(adr_srv)); adr_srv.sin_family = AF_INET; err = inet_aton("127.0.0.1", &adr_srv.sin_addr); if (err == 0) { printf("Adresse IPv4 invalide !\n"); exit(1); } adr_srv.sin_port = htons(8080); err = bind(fd_srv, (struct sockaddr *) &adr_srv, sizeof(adr_srv)); if (err != 0) { printf("Erreur d'accès au port serveur !\n"); exit(1); } err = listen(fd_srv, 5); if (err != 0) { printf("Erreur de création de la file d'attente !\n"); exit(1); } printf("Serveur lancé !\n"); while(1) { adr_cli_len = sizeof(adr_cli); fd_con = accept(fd_srv, (struct sockaddr *) &adr_cli, &adr_cli_len); if (fd_con < 0) { printf("Erreur sur l'acceptation de connexion entrante !\n"); exit(1); } printf("Connexion acceptée !\n"); communication_serveur(fd_con); shutdown(fd_con, SHUT_RDWR); close(fd_con); printf("Client déconnecté par le serveur !\n"); } return 0; }
Dans les langages comme PHP ou Python, il existe des bibliothèques faisant l'interface avec les fonctions systèmes.
Le code de l'exemple écrit en C devient en PHP :
function communication_serveur($socket) { } $sock_srv = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($sock_srv== false) die("Erreur de creation de la socket !\n"); $err = socket_bind($sock_srv, '127.0.0.1', 8080); if ($err == false) die("Erreur d'accès au port serveur !\n"); $err = socket_listen($sock_srv, 5); if ($err == false) die("Erreur de création de la file d'attente !\n"); echo "Serveur lancé !\n"; while (true) { $sock_con = socket_accept($sock_srv); if ($sock_con == false) die("Erreur sur l'acceptation de connexion entrante !\n"); echo "Connexion acceptée !\n"; communication_serveur($sock_con); socket_shutdown($sock_con); socket_close($sock_con); echo "Client déconnecté par le serveur !\n" }
Le code de l'exemple écrit en C devient en Python :
import socket def communication_serveur(sock) : ... try: sock_srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_srv.bind(('127.0.0.1', 8080)) sock_srv.listen(5) except socket.error: print("Erreur de lancement du serveur !") exit() print("Serveur lancé !") while True : try : (sock_con,adr_cli)=sock_srv.accept() print("Connexion acceptée !") communication_serveur(sock_con) sock_con.shutdown() sock_con.close() print("Client déconnecté par le serveur !") except socket.error : print("Erreur sur l'acceptation de connexion entrante !") exit()