Using fork concurrent processing of multiple client requests and Peer-to-peer communication
First, in the previous mentioned in the Echo client/server program, the server can only handle a client's request, how to service multiple clients at the same time? Before you talk about advanced IO such as select/poll/epoll, a more old-fashioned approach is to use fork. Network servers often use fork to service multiple clients at the same time, the parent process is dedicated to listening ports, each accept a new client connection fork A child process dedicated to this client. However, when the subprocess exits, it produces a zombie process, and the parent process should pay attention to handling the SIGCHLD signal and calling wait to clean up the zombie process, the simplest way is to ignore the SIGCHLD signal directly.
/************************************************************************* > File name:echoser.c > Author: Simba > Mail:dameng34@163.com > Created time:fri Mar 2013 06:15:27 PM CST *************************** /#include <stdio.h> #include <sys/types.h> #include < sys/socket.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <arpa/inet.h
> #include <netinet/in.h> #include <string.h> #include <signal.h> #define ERR_EXIT (m) \ Do {\ Perror (m); \ exit (exit_failure);
\} while (0) void do_service (int);
int main (void) {signal (SIGCHLD, sig_ign); int LISTENFD; Passive sockets (file descriptor), that is, can only be accept, listening socket if (LISTENFD = socket (pf_inet, Sock_stream, ipproto_tcp)) < 0)//Listen
FD = socket (af_inet, sock_stream, 0) err_exit ("Socket error");
struct sockaddr_in servaddr; MemseT (&servaddr, 0, sizeof (SERVADDR));
servaddr.sin_family = af_inet;
Servaddr.sin_port = htons (5188);
SERVADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any); /* servaddr.sin_addr.s_addr = inet_addr ("127.0.0.1"); * * * Inet_aton ("127.0.0.1", &servaddr.sin_addr);
*/int on = 1;
if (setsockopt (LISTENFD, Sol_socket, so_reuseaddr, &on, sizeof (ON)) < 0) err_exit ("setsockopt error");
if (Bind (LISTENFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR)) < 0) Err_exit ("Bind error");
if (Listen (LISTENFD, Somaxconn) < 0)//listen should be after the socket and bind, but before accept ("Err_exit error"); struct sockaddr_in peeraddr; Outgoing parameter socklen_t peerlen = sizeof (PEERADDR); Incoming outgoing parameter must have an initial value of int conn;
Socket has been connected (become active socket, that can be active connect) pid_t PID; while (1) {if ((conn = Accept (LISTENFD, (struct sockaddr *) &peeraddr, &peerlen)) < 0)//3 Handshake Complete Order Column Err_exit ("Accept error");
printf ("Recv Connect ip=%s port=%d\n", Inet_ntoa (PEERADDR.SIN_ADDR), Ntohs (Peeraddr.sin_port));
PID = fork ();
if (PID = = 1) err_exit ("fork Error");
if (PID = = 0) {//child process close (LISTENFD);
Do_service (conn);
Exit (exit_success); else close (conn);
Parent process} return 0;
} void Do_service (int conn) {char recvbuf[1024];
while (1) {memset (recvbuf, 0, sizeof (RECVBUF));
int ret = READ (conn, recvbuf, sizeof (RECVBUF));
if (ret = 0)//client closes {printf ("Client close\n");
Break
else if (ret = = 1) err_exit ("read error");
Fputs (Recvbuf, stdout);
Write (conn, recvbuf, ret); }
}
The above program takes advantage of the fact that the parent-child process shares an open file descriptor, because the child process closes it without using the listener descriptor, and the connection descriptor is not valuable to the parent process. When a client closes, read returns 0, quits the loop, and the subprocess exits, but if the SIGCHLD signal is not set to be ignored, the child process becomes a zombie process because the parent process has not yet exited.