#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);
}