تابع ()fork

از این تابع به وسیله multi-process کردن سرور، یک سرور concurrent می سازیم

#include <sys/types.h>
#include <unistd.h>
 
pid_t fork(void);

اسکلت کلی استفاده از تابع ()fork در سرور

pid_t pid;
int listen_sock, client_sock;
listen_sock = socket(...);
bind(listen_sock, ...);
listen(listen_sock, ...);
 
// ignoring the SIGCHLD signal
// prevent zombie/defunct child processes
signal(SIGCHLD, SIG_IGN);
 
while(1) {
 
    client_sock = accept(listen_sock, ...);  // blocking call
 
    pid = fork();
    if (pid == 0 ) { // this is the child process
 
      close(listen_sock); // child doesn't need the listener
 
      // process the request, doing something using client_sock 
 
      close(client_sock);
      exit(0);  // child terminates
    }
    close(client_sock); // parent doesn't need this
}

مثال یک سرور multi-process

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
 
#define PORT "54990"
#define BACKLOG 120
 
int main()
{
    int status, listen_sock, client_sock, sockopt;
    struct addrinfo hints, *res, *rp;
    struct sockaddr_storage client_addr;
    socklen_t addrlen;
    char ipstr[INET_ADDRSTRLEN];
    pid_t pid;
    char *msg = "Message from server: Hello World\n";
    size_t msglen;
 
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
 
    status = getaddrinfo(NULL, PORT, &hints, &res);
    if (status != 0) {
        fprintf(stderr, "getaddrinfo() error: %s\n", 
                gai_strerror(status));
        exit(EXIT_FAILURE);
    }
 
    for (rp = res; rp != NULL; rp = rp->ai_next) {
        listen_sock = socket(rp->ai_family, rp->ai_socktype, 
                                rp->ai_protocol);
        if (listen_sock == -1) {
            perror("socket() error ");
            continue; 
        }
 
        sockopt = 1;
        status = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, 
                            (void*)&sockopt, sizeof(sockopt));
        if (status == -1) {
            perror("setsockopt() error ");
            exit(EXIT_FAILURE);
        }
 
        status = bind(listen_sock, rp->ai_addr, rp->ai_addrlen);
        if (status == -1) {
            perror("bind() error ");
            close(listen_sock);
            continue;
        }
 
        break;
    }
    freeaddrinfo(res);
 
    if (rp == NULL) {
        fprintf(stderr, "Could not bind()\n");
        exit(EXIT_FAILURE);
    }
 
    status = listen(listen_sock, BACKLOG);
    if (status == -1) {
        perror("listen() error ");
        exit(EXIT_FAILURE);
    }
 
    printf("Wating for connections...\n");
 
    signal(SIGCHLD, SIG_IGN);
 
    addrlen = sizeof(client_addr);
    while(1) {
        client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, 
                                &addrlen);
        if (client_sock == -1) {
            perror("accept() error ");
            continue;
        }
 
        inet_ntop(client_addr.ss_family,
                &(((struct sockaddr_in *)&client_addr)->sin_addr), 
                ipstr, INET_ADDRSTRLEN);
        printf("Got connection from: %s\n", ipstr);
 
        pid = fork();
        if (pid == 0) { 
            close(listen_sock); 
            msglen = strlen(msg);
            status = send(client_sock, msg, msglen, 0);
            if (status == -1) {
                perror("send() error ");
                close(client_sock);
                exit(EXIT_FAILURE);
            }
            close(client_sock);
            exit(EXIT_SUCCESS);
        } else if (pid == -1) {
            perror("fork() error ");
            close(client_sock);
            continue;
        }
        printf("Forked process PID: %d\n", pid); 
        close(client_sock); 
    }
 
    close(listen_sock);
    return 0;
}