از این تابع به وسیله 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; }