Introduction
This article writes a concurrent server (concurrent server) program that fork out a child process for each client request.
Attention
1. Signal Processing problems
For the same signal, according to the order of the signal is processed sequentially. The problem that may arise is that when the SIG1 signal is being processed, there are 2 or more SIG1 signals, which will only process 1 SIG1 signals after the original SIG1 signal is processed. Therefore, for the same signal, there will be a signal substitution problem. After a son has retired, the program in the process of processing handler (), if at this time and back two sons, then there must be a son of resources not recovered, called the zombie process.
For different signals, priority is given to the latter, and the latter is processed back to the last one. For example, when SIG1 is being processed, the SIG2 is processed, SIG2 is handled first, and the SIG2 is processed, and then the SIG1 is processed back to the end.
2. Solution
In a registered signal processing function, a loop is used and a waitpid is used in the loop to reclaim the child process resources. As soon as the signal processing function is entered, the signal processing function can reclaim all the resources of the son that has been forked out. Note: The waitpid is to be set to non-blocking mode, otherwise when the loop is entered, it will block in the signal handler function if no child process exits.
3. Wait and Waitpid
Wait must be blocking mode. So in the signal processing function, with while1{wait (NULL)} There is a problem, if you enter the signal processing function, as long as the son does not retreat, it will always be blocked here.
The waitpid can be either blocking mode or non-blocking mode.
4. Select and Accept
Both will return-1 when the signal is received.
For signals that the system does not process by default, the program does not receive it, and neither of them will return-1. In other words, SIGCHLD is a signal that the system does not process by default, and if it does not register a signal handler function, select and accept will not return-1 when the child process exits.
5. This code uses the Linux network programming 9--to TCP and UDP in the simple Package 2.0 dynamic library.
Code
Server.c
/************************************************************************* > File name:server.c > Author: Krischou > Mail:[email protected] > Created time:fri Sep 03:31:12 PM CST ******************************** ****************************************/#include"my_socket.h"#include<sys/wait.h>#include<signal.h>#include<errno.h>#defineMy_ip "192.168.1.100"#defineMy_port 8888#defineSIZE 192#defineMsg_size (SIZE-4)extern interrno; typedefstructtag_mag{intMsg_len;//record the true size of the Msg_buf CharMsg_buf[msg_size];//the Msg_buf occupies a space of 188byte}msg, *PMSG;voidMy_handle (intnum) { /*waitpid Parameters: *-1 means to reclaim every son * null indicates that the return value of exit of the child process is not concerned * wnohang:wait no hang non-blocking mode *waitpid return value: *-1 means No son created * 0 means no son exits * greater than 0 indicates a son quits **/ while(Waitpid (-1, NULL, Wnohang) >0) ;}intMainintargcChar*argv[]) { intFd_listen, fd_client; Signal (SIGCHLD, my_handle); My_socket (&Fd_listen, My_tcp, My_ip, My_port); My_listen (Fd_listen,Ten); while(Fd_client =Accept (Fd_listen, NULL, NULL)) { /*as long as it is not a signal ignored by the program, accept will receive and return 1*/ if(Fd_client = =-1) { if(errno = =eintr) { Continue ; }Else { Break;//after the break withdrew, the father retired. The son will be taken over by Init. } }Else { if(fork () = =0)//fork son used to communicate with client{MSG recv_msg; intRECVN; while(1) {memset (&recv_msg,0,sizeof(MSG)); /*In my_socket.c, the length of the MY_RECV received and the length of the My_send sent must be the exact value * MY_RECV fill in the length of less than equal to the actual to receive, is possible, greater than the words will never return to the loop
*/My_recv (&RECVN, Fd_client, &recv_msg,4); if(RECVN = =0)//when the opposite client exits (closes the socket), the return value of the system call Recv is 0 { Break ; }Else{my_recv (null,fd_client,&recv_msg.msg_buf, Recv_msg.msg_len); My_send (NULL, Fd_client,&recv_msg,4+Recv_msg.msg_len); }} close (Fd_client); Exit (0); } close (fd_client); } } return 0 ;}
Client.c
#include"my_socket.h"#defineMy_ip "192.168.1.100"#defineMy_port 6666#defineSer_ip "192.168.1.100"#defineSer_port 8888#defineSIZE 192#defineMsg_size (SIZE-4)typedefstructTag_mag{ intMsg_len; CharMsg_buf[msg_size];//188}msg, *PMSG;intMainintargcChar*argv[]) { intSFD; My_socket (&sfd, my_tcp, My_ip, My_port); My_connect (SFD, ser_ip, ser_port); MSG my_msg; while(Memset (&my_msg,0,sizeof(MSG)), Fgets (My_msg.msg_buf, msg_size, stdin)! =NULL) {My_msg.msg_len=strlen (MY_MSG.MSG_BUF); My_send (NULL, SFD,&my_msg,4+My_msg.msg_len); memset (&my_msg,0,sizeof(MSG)); MY_RECV (NULL, SFD,&my_msg,4); MY_RECV (NULL, SFD,&my_msg.msg_buf, My_msg.msg_len); printf ("recv from server:%s \ n", MY_MSG.MSG_BUF); } close (SFD);}
Note: This code is bound to a port because of client.c, so only one client can be connected, and the reader may enter the port number from the command line or let the system allocate itself.
The drawback of this paradigm is that the server will fork the son for processing each time it receives a client connection request, and fork has time overhead. A better approach is to fork the good son in advance, and the next blog post will talk about the process pool.
Linux client/server programming paradigm--concurrent Server (process)