serveur_fd = socket(AF_INET, SOCK_STREAM, 0)
- AF_INET : Famille d’adresses IPv4
- SOCK_STREAM : Type de socket (TCP, fiable, connexion orientée flux)
- 0 : Protocole par défaut (TCP pour SOCK_STREAM)
- Retour : Descripteur de fichier (entier) ou -1 si erreur
Serveur TCP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 8888
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
int sock_fd;
struct sockaddr_in adresse_serveur;
struct hostent *serveur;
char buffer[BUFFER_SIZE];
char message[BUFFER_SIZE];
int bytes_recus;
struct in_addr **addr_list; /* Pour une version plus explicite */
/* Vérification des arguments */
if (argc < 2) {
fprintf(stderr, "Usage: %s <adresse_serveur>\n", argv[0]);
exit(EXIT_FAILURE);
}
/* 1. Création du socket */
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("Erreur création socket");
exit(EXIT_FAILURE);
}
/* 2. Résolution du nom d'hôte */
serveur = gethostbyname(argv[1]);
if (serveur == NULL) {
fprintf(stderr, "Hôte inconnu : %s\n", argv[1]);
close(sock_fd);
exit(EXIT_FAILURE);
}
/* 3. Configuration de l'adresse */
memset(&adresse_serveur, 0, sizeof(adresse_serveur));
adresse_serveur.sin_family = AF_INET;
/* Méthode alternative plus explicite */
addr_list = (struct in_addr **)serveur->h_addr_list;
adresse_serveur.sin_addr = *addr_list[0];
adresse_serveur.sin_port = htons(PORT);
/* 4. Connexion au serveur */
if (connect(sock_fd, (struct sockaddr *)&adresse_serveur, sizeof(adresse_serveur)) < 0) {
perror("Erreur connect");
close(sock_fd);
exit(EXIT_FAILURE);
}
printf("Connecté au serveur %s:%d\n", argv[1], PORT);
printf("Adresse IP : %s\n", inet_ntoa(adresse_serveur.sin_addr));
/* 5. Échange de données */
while (1) {
printf("Message à envoyer (ou 'quit' pour quitter) : ");
fgets(message, BUFFER_SIZE, stdin);
/* Suppression du saut de ligne */
message[strcspn(message, "\n")] = '\0';
if (strcmp(message, "quit") == 0) {
break;
}
/* Envoi */
send(sock_fd, message, strlen(message), 0);
/* Réception de la réponse */
bytes_recus = recv(sock_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_recus <= 0) {
printf("Serveur déconnecté\n");
break;
}
buffer[bytes_recus] = '\0';
printf("Réponse du serveur : %s\n", buffer);
}
/* 6. Fermeture */
close(sock_fd);
return 0;
}
Makefile
CC = gcc
CFLAGS = -Wall -Wextra -ansi -pedantic
all: serveur
serveur: serveur_tcp.c
$(CC) $(CFLAGS) -o serveur serveur_tcp.c
clean:
rm -f serveur
.PHONY: all clean
Client TCP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 8888
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
int sock_fd;
struct sockaddr_in adresse_serveur;
struct hostent *serveur;
char buffer[BUFFER_SIZE];
char message[BUFFER_SIZE];
int bytes_recus;
struct in_addr **addr_list; /* Pour une version plus explicite */
/* Vérification des arguments */
if (argc < 2) {
fprintf(stderr, "Usage: %s <adresse_serveur>\n", argv[0]);
exit(EXIT_FAILURE);
}
/* 1. Création du socket */
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("Erreur création socket");
exit(EXIT_FAILURE);
}
/* 2. Résolution du nom d'hôte */
serveur = gethostbyname(argv[1]);
if (serveur == NULL) {
fprintf(stderr, "Hôte inconnu : %s\n", argv[1]);
close(sock_fd);
exit(EXIT_FAILURE);
}
/* 3. Configuration de l'adresse */
memset(&adresse_serveur, 0, sizeof(adresse_serveur));
adresse_serveur.sin_family = AF_INET;
/* Méthode alternative plus explicite */
addr_list = (struct in_addr **)serveur->h_addr_list;
adresse_serveur.sin_addr = *addr_list[0];
adresse_serveur.sin_port = htons(PORT);
/* 4. Connexion au serveur */
if (connect(sock_fd, (struct sockaddr *)&adresse_serveur, sizeof(adresse_serveur)) < 0) {
perror("Erreur connect");
close(sock_fd);
exit(EXIT_FAILURE);
}
printf("Connecté au serveur %s:%d\n", argv[1], PORT);
printf("Adresse IP : %s\n", inet_ntoa(adresse_serveur.sin_addr));
/* 5. Échange de données */
while (1) {
printf("Message à envoyer (ou 'quit' pour quitter) : ");
fgets(message, BUFFER_SIZE, stdin);
/* Suppression du saut de ligne */
message[strcspn(message, "\n")] = '\0';
if (strcmp(message, "quit") == 0) {
break;
}
/* Envoi */
send(sock_fd, message, strlen(message), 0);
/* Réception de la réponse */
bytes_recus = recv(sock_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_recus <= 0) {
printf("Serveur déconnecté\n");
break;
}
buffer[bytes_recus] = '\0';
printf("Réponse du serveur : %s\n", buffer);
}
/* 6. Fermeture */
close(sock_fd);
return 0;
}
Makefile
CC = gcc
CFLAGS = -Wall -Wextra -ansi -pedantic
all: client
client: client_tcp.c
$(CC) $(CFLAGS) -o client client_tcp.c
clean:
rm -f client
.PHONY: all clean
Muti_serveur (fork)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define PORT 8888
#define BUFFER_SIZE 1024
#define MAX_CLIENTS 10
/* Gestionnaire de signaux pour éviter les processus zombies */
void gestionnaire_sigchld(int signo) {
/* waitpid avec WNOHANG pour ne pas bloquer */
while (waitpid(-1, NULL, WNOHANG) > 0);
}
/* Fonction pour traiter chaque client */
void traiter_client(int client_fd, struct sockaddr_in adresse_client) {
char buffer[BUFFER_SIZE];
int bytes_lus;
int i;
char client_ip[INET_ADDRSTRLEN];
/* Convertir l'adresse IP en chaîne */
inet_ntop(AF_INET, &adresse_client.sin_addr, client_ip, INET_ADDRSTRLEN);
printf("[Processus %d] Client connecté : %s:%d\n",
getpid(),
client_ip,
ntohs(adresse_client.sin_port));
/* Communication avec le client */
while ((bytes_lus = recv(client_fd, buffer, BUFFER_SIZE - 1, 0)) > 0) {
buffer[bytes_lus] = '\0';
printf("[Processus %d] Reçu : %s", getpid(), buffer);
/* Conversion en majuscules */
for (i = 0; i < bytes_lus; i++) {
if (buffer[i] >= 'a' && buffer[i] <= 'z') {
buffer[i] = buffer[i] - 'a' + 'A';
}
}
/* Envoi de la réponse */
send(client_fd, buffer, bytes_lus, 0);
}
if (bytes_lus == 0) {
printf("[Processus %d] Client déconnecté\n", getpid());
} else {
perror("[Processus %d] Erreur recv");
}
close(client_fd);
printf("[Processus %d] Connexion fermée, processus termine\n", getpid());
exit(0); /* Le processus fils se termine */
}
int main(void) {
int serveur_fd, client_fd;
struct sockaddr_in adresse_serveur, adresse_client;
socklen_t taille_client = sizeof(adresse_client);
struct sigaction sa;
int opt = 1;
/* 1. Configuration du gestionnaire de signaux pour éviter les zombies */
sa.sa_handler = gestionnaire_sigchld;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* Réinitialiser les appels système interrompus */
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("Erreur sigaction");
exit(EXIT_FAILURE);
}
/* 2. Création du socket */
serveur_fd = socket(AF_INET, SOCK_STREAM, 0);
if (serveur_fd < 0) {
perror("Erreur création socket");
exit(EXIT_FAILURE);
}
/* 3. Option pour réutiliser l'adresse (évite "Address already in use") */
if (setsockopt(serveur_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("Erreur setsockopt");
close(serveur_fd);
exit(EXIT_FAILURE);
}
/* 4. Configuration de l'adresse du serveur */
memset(&adresse_serveur, 0, sizeof(adresse_serveur));
adresse_serveur.sin_family = AF_INET;
adresse_serveur.sin_addr.s_addr = INADDR_ANY;
adresse_serveur.sin_port = htons(PORT);
/* 5. Attachement du socket */
if (bind(serveur_fd, (struct sockaddr *)&adresse_serveur, sizeof(adresse_serveur)) < 0) {
perror("Erreur bind");
close(serveur_fd);
exit(EXIT_FAILURE);
}
/* 6. Mise en écoute */
if (listen(serveur_fd, MAX_CLIENTS) < 0) {
perror("Erreur listen");
close(serveur_fd);
exit(EXIT_FAILURE);
}
printf("Serveur multi-clients démarré sur le port %d\n", PORT);
printf("PID du serveur principal : %d\n", getpid());
printf("En attente de connexions...\n\n");
/* 7. Boucle principale d'acceptation */
while (1) {
/* Accepter une nouvelle connexion */
client_fd = accept(serveur_fd, (struct sockaddr *)&adresse_client, &taille_client);
if (client_fd < 0) {
perror("Erreur accept");
continue;
}
/* Création d'un processus fils pour gérer le client */
pid_t pid = fork();
if (pid < 0) {
perror("Erreur fork");
close(client_fd);
continue;
}
if (pid == 0) {
/* Processus fils */
close(serveur_fd); /* Le fils n'a pas besoin du socket d'écoute */
traiter_client(client_fd, adresse_client);
/* Ne jamais arriver ici */
} else {
/* Processus père */
close(client_fd); /* Le père n'a pas besoin du socket client */
printf("[Père %d] Nouveau client connecté, processus fils créé : %d\n",
getpid(), pid);
}
}
/* 8. Fermeture (jamais atteint dans cet exemple) */
close(serveur_fd);
return 0;
}
Serveur http
/* serveur_http_minimal.c - Version simplifiée pour tester */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 4096
int main(void) {
int serveur_fd, client_fd;
struct sockaddr_in adresse_serveur, adresse_client;
socklen_t taille_client = sizeof(adresse_client);
char buffer[BUFFER_SIZE];
int bytes_lus;
char *reponse_ok = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 135\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
"<head><title>Test Serveur</title></head>\n"
"<body>\n"
"<h1>Bienvenue sur mon serveur HTTP!</h1>\n"
"<p>Ceci est une reponse HTML.</p>\n"
"</body>\n"
"</html>\n";
char *reponse_404 = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 105\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
"<body>\n"
"<h1>404 - Page non trouvee</h1>\n"
"</body>\n"
"</html>\n";
/* Création socket */
serveur_fd = socket(AF_INET, SOCK_STREAM, 0);
if (serveur_fd < 0) {
perror("Erreur création socket");
exit(EXIT_FAILURE);
}
/* Configuration */
memset(&adresse_serveur, 0, sizeof(adresse_serveur));
adresse_serveur.sin_family = AF_INET;
adresse_serveur.sin_addr.s_addr = INADDR_ANY;
adresse_serveur.sin_port = htons(PORT);
/* Bind */
if (bind(serveur_fd, (struct sockaddr *)&adresse_serveur, sizeof(adresse_serveur)) < 0) {
perror("Erreur bind");
close(serveur_fd);
exit(EXIT_FAILURE);
}
/* Listen */
if (listen(serveur_fd, 5) < 0) {
perror("Erreur listen");
close(serveur_fd);
exit(EXIT_FAILURE);
}
printf("Serveur HTTP en écoute sur le port %d\n", PORT);
while (1) {
client_fd = accept(serveur_fd, (struct sockaddr *)&adresse_client, &taille_client);
if (client_fd < 0) {
perror("Erreur accept");
continue;
}
printf("Client connecté : %s:%d\n",
inet_ntoa(adresse_client.sin_addr),
ntohs(adresse_client.sin_port));
/* Lire la requête (optionnel, on ignore son contenu) */
bytes_lus = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_lus > 0) {
buffer[bytes_lus] = '\0';
printf("Requête reçue:\n%s\n", buffer);
/* Réponse simple */
if (strstr(buffer, "GET / ") || strstr(buffer, "GET /index.html")) {
send(client_fd, reponse_ok, strlen(reponse_ok), 0);
printf("Réponse 200 OK envoyée\n");
} else {
send(client_fd, reponse_404, strlen(reponse_404), 0);
printf("Réponse 404 envoyée\n");
}
}
close(client_fd);
printf("Connexion fermée\n\n");
}
close(serveur_fd);
return 0;
}
Serveur http multi-client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>
#define PORT 8080
#define BUFFER_SIZE 4096
#define MAX_CLIENTS 100
int clients_actifs = 0;
int compteur_clients = 0;
void gestionnaire_sigchld(int signo) {
while (waitpid(-1, NULL, WNOHANG) > 0) {
clients_actifs--;
}
}
/* Envoyer une réponse HTTP */
void envoyer_reponse_http(int client_fd, const char *body) {
char reponse[BUFFER_SIZE];
sprintf(reponse,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n"
"Content-Length: %ld\r\n"
"Connection: close\r\n"
"Server: ANSI-C/1.0\r\n"
"\r\n"
"%s",
strlen(body), body);
send(client_fd, reponse, strlen(reponse), 0);
}
/* Page d'accueil */
void envoyer_accueil(int client_fd, int numero_client) {
char body[BUFFER_SIZE];
time_t now;
char date_str[64];
time(&now);
strftime(date_str, sizeof(date_str), "%d/%m/%Y %H:%M:%S", localtime(&now));
sprintf(body,
"<html>\n"
"<head>\n"
"<title>Serveur ANSI C</title>\n"
"</head>\n"
"<body>\n"
"<h1>Serveur ANSI C</h1>\n"
"<hr>\n"
"<h2>Client numero : #%d</h2>\n"
"<p>Clients actifs : %d</p>\n"
"<p>Total clients servis : %d</p>\n"
"<p>Date/Heure : %s</p>\n"
"<p>Port : %d | PID : %d</p>\n"
"<hr>\n"
"<p><a href='/stats'>Voir les statistiques</a></p>\n"
"<p><a href='/quit'>Quitter</a></p>\n"
"</body>\n"
"</html>\n",
numero_client, clients_actifs, compteur_clients, date_str, PORT, getpid());
envoyer_reponse_http(client_fd, body);
}
/* Page statistiques */
void envoyer_stats(int client_fd, int numero_client) {
char body[BUFFER_SIZE];
sprintf(body,
"<html>\n"
"<head>\n"
"<title>Statistiques</title>\n"
"</head>\n"
"<body>\n"
"<h1>Statistiques</h1>\n"
"<hr>\n"
"<h2>Votre numero : #%d</h2>\n"
"<p>Clients actuellement connectes : %d</p>\n"
"<p>Total clients servis depuis demarrage : %d</p>\n"
"<p>Capacite maximale : %d clients</p>\n"
"<hr>\n"
"<p><a href='/'>Retour accueil</a></p>\n"
"</body>\n"
"</html>\n",
numero_client, clients_actifs, compteur_clients, MAX_CLIENTS);
envoyer_reponse_http(client_fd, body);
}
/* Page 404 */
void envoyer_404(int client_fd) {
char body[BUFFER_SIZE];
sprintf(body,
"<html>\n"
"<head>\n"
"<title>404</title>\n"
"</head>\n"
"<body>\n"
"<h1>404 - Page non trouvee</h1>\n"
"<hr>\n"
"<p>La page demandee n'existe pas.</p>\n"
"<p><a href='/'>Retour accueil</a></p>\n"
"</body>\n"
"</html>\n");
envoyer_reponse_http(client_fd, body);
}
/* Page au revoir */
void envoyer_au_revoir(int client_fd) {
char body[BUFFER_SIZE];
sprintf(body,
"<html>\n"
"<head>\n"
"<title>Au revoir</title>\n"
"</head>\n"
"<body>\n"
"<h1>Au revoir !</h1>\n"
"<hr>\n"
"<p>Merci d'avoir visite notre serveur ANSI C.</p>\n"
"<p><a href='/'>Nouvelle connexion</a></p>\n"
"</body>\n"
"</html>\n");
envoyer_reponse_http(client_fd, body);
}
/* Extraire le chemin de la requête HTTP */
void extraire_chemin(const char *requete, char *chemin) {
char method[16];
char path[256];
char version[16];
sscanf(requete, "%s %s %s", method, path, version);
strcpy(chemin, path);
}
void traiter_client(int client_fd, struct sockaddr_in adresse_client, int numero_client) {
char buffer[BUFFER_SIZE];
int bytes_lus;
char chemin[256];
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &adresse_client.sin_addr, client_ip, INET_ADDRSTRLEN);
printf("[Client #%d] Connecte depuis %s:%d\n",
numero_client, client_ip, ntohs(adresse_client.sin_port));
/* Lire la requête */
bytes_lus = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_lus <= 0) {
close(client_fd);
exit(0);
}
buffer[bytes_lus] = '\0';
extraire_chemin(buffer, chemin);
printf("[Client #%d] Chemin: %s\n", numero_client, chemin);
/* Router selon le chemin */
if (strcmp(chemin, "/") == 0 || strcmp(chemin, "/index.html") == 0) {
envoyer_accueil(client_fd, numero_client);
}
else if (strcmp(chemin, "/stats") == 0) {
envoyer_stats(client_fd, numero_client);
}
else if (strcmp(chemin, "/quit") == 0) {
envoyer_au_revoir(client_fd);
}
else {
envoyer_404(client_fd);
}
printf("[Client #%d] Deconnexion\n", numero_client);
close(client_fd);
exit(0);
}
int main(void) {
int serveur_fd, client_fd;
struct sockaddr_in adresse_serveur, adresse_client;
socklen_t taille_client = sizeof(adresse_client);
int opt = 1;
int numero_nouveau_client;
/* Gestion des signaux */
signal(SIGCHLD, gestionnaire_sigchld);
/* Création socket */
serveur_fd = socket(AF_INET, SOCK_STREAM, 0);
if (serveur_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
/* Option reuse address */
setsockopt(serveur_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/* Configuration adresse */
memset(&adresse_serveur, 0, sizeof(adresse_serveur));
adresse_serveur.sin_family = AF_INET;
adresse_serveur.sin_addr.s_addr = INADDR_ANY;
adresse_serveur.sin_port = htons(PORT);
/* Bind */
if (bind(serveur_fd, (struct sockaddr *)&adresse_serveur, sizeof(adresse_serveur)) < 0) {
perror("bind");
close(serveur_fd);
exit(EXIT_FAILURE);
}
/* Listen */
if (listen(serveur_fd, MAX_CLIENTS) < 0) {
perror("listen");
close(serveur_fd);
exit(EXIT_FAILURE);
}
printf("\n========================================\n");
printf("SERVEUR HTTP ANSI C\n");
printf("========================================\n");
printf("Port: %d\n", PORT);
printf("URL: http://localhost:%d/\n", PORT);
printf("PID: %d\n", getpid());
printf("========================================\n\n");
/* Boucle principale */
while (1) {
client_fd = accept(serveur_fd, (struct sockaddr *)&adresse_client, &taille_client);
if (client_fd < 0) {
perror("accept");
continue;
}
clients_actifs++;
compteur_clients++;
numero_nouveau_client = compteur_clients;
printf("[SERVEUR] +++ Client #%d connecte (Actifs: %d) +++\n",
numero_nouveau_client, clients_actifs);
{
pid_t pid = fork();
if (pid == 0) {
/* Processus fils */
close(serveur_fd);
traiter_client(client_fd, adresse_client, numero_nouveau_client);
exit(0);
} else if (pid > 0) {
/* Processus père */
close(client_fd);
} else {
perror("fork");
clients_actifs--;
close(client_fd);
}
}
}
close(serveur_fd);
return 0;
}