#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <signal.h> #define DEF_PROC_NUM 13 #define PROC_NUM_LIMIT 666 #define TCP_PORT 12345 int server(int s) { int dsock; struct sockaddr_in client; unsigned int addrlen = sizeof(struct sockaddr_in); char *hello = "Hello, world! I'm prefork server.\n"; char *bye = "Goodbye, world!\n"; int r; signal(SIGPIPE, SIG_IGN); for (;;) { /* * NOTE: "thundering herd" is not a problem for accept(), see for ex. * https://stackoverflow.com/questions/2213779/does-the-thundering-herd-problem-exist-on-linux-anymore * https://lwn.net/Articles/663474/ */ dsock = accept(s, (struct sockaddr *)&client, &addrlen); if ( -1 == dsock) { perror("accept()\n"); continue; } printf("got client\n"); /* serve client */ r = write(dsock, hello, strlen(hello)); if ( (-1 == r) || (!r)) { printf("write 1 ...\n"); close(dsock); continue; }; r = sleep(10); /* kinda working ... */ if (r) { printf("interrupted sleep()\n"); } r = write(dsock, bye, strlen(bye)); if ( (-1 == r) || (!r)) { printf("write 2 ...\n"); close(dsock); continue; }; close(dsock); }; } struct sockaddr_in serv_addr; int procnum = DEF_PROC_NUM; int lsock; int main(int argc, char *argv[]) { int r, p, pid; int yes = 1; if (argc > 2) { printf("usage: %s [number of server processes]\n", argv[0]); exit(1); }; if (argc == 1) { printf("number of server process is not specified, defaults to %d\n", procnum); } else { r = sscanf(argv[1], "%d", &procnum); if ( r != 1) { printf("number of server process is bad, defaults to %d\n", procnum); }; if (procnum > PROC_NUM_LIMIT) { procnum = PROC_NUM_LIMIT; printf("number of server process is too large, using max (%d)\n", procnum); } } /* create listening socket */ lsock = socket(AF_INET, SOCK_STREAM, 0); if ( -1 == lsock ) { perror("socket()"); exit(1); }; r = setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); if ( r == -1 ) { perror("setsockopt()"); exit(1); }; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(TCP_PORT); r = bind(lsock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if ( -1 == r ) { perror("bind()"); exit(1); }; r = listen(lsock, PROC_NUM_LIMIT); if ( -1 == r ) { perror("listen()"); exit(1); }; /* prefork */ for (p = 0; p < procnum; p++) { pid = fork(); switch (pid) { case -1: ;;; perror("fork()"); ;;; break; /* child process */ case 0: ;;; server(lsock); ;;; break; /* parent */ default: ;;; printf("child process (pid = %d) created\n", pid); ;;; }; }; /* let orphaned children be parentised by init */ exit(0); }