Question n°2 : multi-client / multi-processus

Explication

Par rapport à la question n°1, il n'y a pas beaucoup de changement à faire. On conserve les procédures do_client() et send_to() ainsi que la fonction receive_from(). On change juste le code source de la boucle d'acquisition des connexions :

void sigchld_handler(int signo) {
    signal(SIGCHLD, sigchld_handler);
    while (waitpid(-1, NULL, WNOHANG) > 0);
}

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("0.0.0.0", &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);
    }
    signal(SIGCHLD, sigchld_handler);
    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("Connexion acceptée !\n");
            if (fork()==0) {
                close(fd_srv);
                do_client(fd_con);
                close(fd_con);
                printf("Connexion fermée !\n");
                exit(0);
            }
            close(fd_con);
        }
    }
    return 0;
}
    

Le code source complet

#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
 
#include <unistd.h>       // pour la fonction fork
#include <signal.h>       // pour la fonction signal
#include <sys/wait.h>     // pour la fonction waitpid
 
void sigchld_handler(int signo) {
    signal(SIGCHLD, sigchld_handler);
    while (waitpid(-1, NULL, WNOHANG) > 0);
}
 
char* receive_from(int fd) {
    static char buf[2048]="";
    static int pos=0;
    int len;
    char *ret;

    while (1) {
        for(len=0; len<pos ; len++) if(buf[len]=='\n') break;
        if(buf[len]=='\n') break;
        len=sizeof(buf)-pos-1;
        if (len==0) {
            shutdown(fd, SHUT_RDWR);
            return NULL;
        }
        len=read(fd,buf+pos,len);
        if (len==0) return NULL;
        pos+=len;
    }
    buf[len]=0x00;
    ret=(char*) malloc(len+1);
    memcpy(ret,buf,len+1);
    memcpy(buf,buf+len+1,sizeof(buf)-len-1);
    pos-=len+1;
    return(ret);
}

void send_to(int fd, char* buf) {
    int i;
    for (i=0;i<strlen(buf);i++) {
        write(fd,buf+i,1);
        usleep(200000);
    }
    write(fd,"\n",1);
}

void do_client(int fd) {
    char *buf;
    while (1) {
        buf=receive_from(fd);
        if (buf == NULL) break;
        send_to(fd,buf);
        free(buf);
    }
}
 
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("0.0.0.0", &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);
    }
    signal(SIGCHLD, sigchld_handler);
    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("Connexion acceptée !\n");
            if (fork()==0) {
                close(fd_srv);
                do_client(fd_con);
                close(fd_con);
                printf("Connexion fermée !\n");
                exit(0);
            }
            close(fd_con);
        }
    }
    return 0;
}