I have written a server which sets up and listens on a socket. It has business to attend to once per second, and then uses select() to serve connection requests during the interval.
Now, if I accept() the connection and then fork(), all is well (but I must remember to close my new socket in both the child and the parent). It made sense to me to fork() and
then accept() - only the child needs deal with the new socket. This "works", in that the client collects the infomation required. However, it comes at the cost of massive system resources! Invariably, the server will give multiple
"accept: Resource temporarily unavailable"
errors, and it starts to hog the system.
I do not understand why this is so. Can anyone shed some light?
Here is the code:
Code:
// Serve multiple requests during the idle second
//
while (w_time.tv_sec != 0 || w_time.tv_usec != 0) {
if (select(orig_sock + 1, &read_fd, (fd_set *)NULL,
(fd_set *)NULL, &w_time) < 0) {
perror("read socket select");
clean_up(orig_sock, NAME, shmid, 1);
exit(3);
}
if (FD_ISSET(orig_sock, &read_fd)) {
clnt_len = sizeof(clnt_addr);
if ((new_sock = accept(orig_sock, (struct sockaddr *) &clnt_addr,
&clnt_len)) < 0) {
perror("accept error");
clean_up(orig_sock, NAME, shmid, 1);
exit(3);
}
if (fork() == 0) {
read(new_sock, sock_request, 1024);
if (strcmp(sock_request, "START") == 0)
start_session(new_sock, registered, stack);
else if (strcmp(sock_request, "GET") == 0)
time_remaining(new_sock, registered);
else if (strcmp(sock_request, "STOP") == 0)
terminate_session(new_sock, registered, stack);
else
write(new_sock, "EBADREQ", sizeof("EBADREQ"));
close (new_sock);
exit(0);
}
close (new_sock);
}
}
This works; move the accept() into the fork() block and things get messy.
The socket was set up like this:
Code:
// Set up listening socket
//
if ((orig_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("generate error");
clean_up(orig_sock, NAME, shmid, 0);
exit(3);
}
if (ioctl(orig_sock, FIONBIO, &flag) < 0) {
perror("SERVER ioctl");
clean_up(orig_sock, NAME, shmid, 1);
exit(3);
}
serv_addr.sun_family = AF_UNIX;
strcpy (serv_addr.sun_path, NAME);
unlink(NAME); // In case it's hanging around..
mask = umask(0000); // Squid must talk to this socket.
if (bind(orig_sock, (struct sockaddr *) &serv_addr,
sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path)) < 0) {
perror("bind error");
clean_up(orig_sock, NAME, shmid, 1);
exit(3);
}
umask(mask);
listen(orig_sock, 2); // There are 2 redirectors