/* ** tcp_server_multi.c -- a multi-threaded tcp server */ #include #include #include #include #include #include #include #include #include #include #include #define MYPORT 3490 // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold // since we are forking, we need to take care of child processes void sigchld_handler(int s) { while(waitpid(-1, NULL, WNOHANG) > 0); } int main(void) { int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct sockaddr_in my_addr; // my address information struct sockaddr_in their_addr; // connector's address information socklen_t sin_size; struct sigaction sa; int yes=1; // create a tcp socket to listen on if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } // specify that the address is to be reused: useful if the server is stopped // and immediately restarted before the port has been reclaimed by the kernel if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); // bind the socket to MYPORT if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1) { perror("bind"); exit(1); } // listen on the socket for connections if (listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } while(1) { // main accept() loop sin_size = sizeof their_addr; // accept connection from client if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { perror("accept"); continue; } printf("tcp_server_multi: got connection from %s\n",inet_ntoa(their_addr.sin_addr)); // everything in the following block happens simultaneously in the // child process, while the parent continues from the line after // the fork block if (!fork()) { // this is the child process close(sockfd); // child doesn't need the listener if (send(new_fd, "Hello, world!\n", 14, 0) == -1) perror("send"); close(new_fd); exit(0); } // child ends here // parent continues here close(new_fd); // parent doesn't need this } return 0; }