TCP/IP Programming----process and multi-process server under Linux

Source: Internet
Author: User
Tags semaphore

In the previous study, our service can only serve one client at a time, even if the accept () function is included in the loop, it can only serve multiple clients sequentially, and there is no concurrency service capability, which is obviously unreasonable. Through multi-process use, we can easily implement multi-process on the server side, so that we can provide services to multiple clients at the same time.

First we need to understand the concept of program, process, process ID, zombie process, thread.

Program: Broadly speaking is to achieve a certain purpose two of the way, in programming is specifically to achieve a function of the code to write the entity, is static.

process: a dynamic execution of a program is a process that consumes a certain amount of memory space and is running a program.

Process ID: in the operating system, the PCB (Process Control block) is the unique identity of the process, where the process ID is used to differentiate between the process control blocks, which are unique in the system, and each process has a unique process ID to differentiate.

Thread: The process of a smaller resource collection, which does not hold system resources, but by requesting resources to run the process, is the smallest unit of the system scheduling. A process can contain multiple threads.

Zombie Process: This is destroyed after the process has been executed, but it is sometimes retained for some reason, although it has freed up most of the system resources, but still retains a small portion of the system resources, which we call "zombie process" for this process.

the cause of the zombie process: in Linux, in order for the child process to end after the end of the information and state can be queried by the parent process, so set up a mechanism: that is, when the process is finished running, a portion of the resources are reserved for the state and information at the end of the save (such as the process ID, return value, and so on) until the parent process obtains the information, the child process completely frees up the resources that it occupies. Due to the existence of this mechanism, when the task performed in the parent process is heavier than the child process (that is, the child process ends up before the parent process), the child process must wait for the parent process to proactively obtain the information, which causes the zombie process to be generated.

attached:The zombie process is generated because the child process ends before the parent process, and it is necessary to wait until the parent process queries for its end information, so it is natural to consider if the parent process ends up with the child process and the sound will occur? When a child process has not yet performed a complete task, if the parent process has finished running, the child process is managed to the process ID 1 of the system (the process used to assist the operating system), that is, the parent process of the child process becomes Process ID 1, the system will automatically collect information, To ensure that no zombie process is produced.

After understanding the basic concepts, we can try to practice multi-process. There are many ways to create processes, and we only understand the functions that create a multi-process server.

pid_t fork (void): Copy the current process into a new process

Return process ID on success, 1 on Failure

    • The return ID of 0 in the child process

    • The process ID of the parent process that returns the ID of the child process

In detail: by calling the fork () function, we can replicate the current process (calling the fork () function's process) into a new subprocess, both of which have the same and separate memory space (that is, the memory of the parent process is completely copied into another memory). We can differentiate between parent and child processes based on the return value of the function.

#include <stdio.h>#include <unistd.h>intMainintARGC, Char*ARGV[]){//Create child process pid_t PID =Fork();//Two processes will execute different code depending on the PID, the value of the PID in the parent process is the process ID of the child process, and the PID value in the subprocess is0    if(PID = =0){printf("I am child process pid %d\ n", PID); }Else{printf("I am parent Process Child Pid %d \ n", PID);Sleep( -); }return 0;}

A solution to the zombie process:

1. Use the wait () or waitpid () function:

pid_t Wait (int *statloc): Gets the return value of the child process

    • Statloc (memory address): When the function is called, if there is a child process that has already ended, the return value of the child process is stored in the inner space referred to by that address. If there are no child processes that have ended, then the main process is blocked until the child process has finished.

Returns the terminated child process ID on success, returns 1 on failure

#include <stdio.h>#include <unistd.h>#include <sys/wait.h>intMainintARGC, Char*ARGV[]){//Used to save stateintStatus//forkA sub-process pid_t PID =Fork();if(PID = =0){return 3; }Else{printf("Child PID:%d \ n", PID);//In the parent process, in theForkA sub-process PID =Fork();if(PID = =0){Exit(7); }Else{printf("Child PID:%d \ n", PID);//Gets the return value of the child processwait(&status);/** * Because other information is included in the cell that the status points to, it is determined and separated by the following macro definition * wifexited (status)------The child process returns to True when normal termination * Wexitstatus (status)------The return value of the child process **/Determine if the child process ends normallyif(wifexited (status)) {printf("Child send one: %d \ n", Wexitstatus (status)); }wait(&status);if(wifexited (status)) {printf("Child send one: %d \ n", Wexitstatus (status)); }Sleep( -); }    }return 0;}

pid_t waitpid (pid_t pid, int *statloc, int options) Gets the return value of the child process:

    • PID (Process ID): The process ID to end
    • Statloc (address pointer): Information such as the return value of the child process is stored in the memory address pointed to by the parameter
    • Option (configuration information): the constant declared in the delivery header file Sys/wait.h
#include <stdio.h>#include <unistd.h>#include <sys/wait.h>intMainintARGC,Char* argv[]) {//For saving state    intStatus//fork a child processpid_t pid = fork ();if(PID = =0) {Sleep ( the);return  -; }Else{ while(!waitpid (Pid,&status,wnohang)) {Sleep (3);puts("Sleap 3 Seconds"); }if(wifexited (status)) {printf("Child send%d \ n", Wexitstatus (status)); }    }return 0;}
2. Through the semaphore mechanism:

void (signal (int signum,void (func)))) (int)) The function to invoke when registering semaphores is generated:

    • Signo (semaphore constant): The type of semaphore to register

Common Signal Volume:

Signal Volume corresponding Events
Sigalrm Time to register with the alarm () function
SIGINT Input CTRL + C
SIGCHLD Child process End
    • (* func) (int) (function address pointer): The address of the function that points to the semaphore being processed

Returns the previously registered function pointer. The system wakes the thread that is sleeping when the semaphore occurs (even if the sleep time is not reached)

#include <stdio.h> #include <unistd.h> #include <sys/wait.h>/** Timeout processing function **/voidTime_out (intSIG) {if(sig = = SIGALRM) {Puts (" Time Out"); Alarm2); }}/** keyboard input processing function **/voidKey_control (intSIG) {if(sig = = SIGINT) {Puts ("Ctrl + C pressed"); }}intMainintARGC,Char* argv[]) {inti =0;//Register timeout processing signal to systemSignal (sigalrm,time_out);//Register keyboard input to the system CTRL + C to process the signalSignal (Sigint,key_control);//Set ClockAlarm2); for(;i<3; i++) {puts ("Wait ...."); Sleep -); }return 0;}

int sigaction (int signo, const struct sigaction *act, struct signation *oldaction) processing the semaphore emitted by the system

    • Signo (semaphore constant): Incoming semaphore to be monitored

    • Act (struct pointer): The address of the struct that is passed in to process semaphores

    • Oldaction (struct pointer): The number of previously registered processing semaphores can be obtained through the secondary parameter

The struct address on success returns 0, 1 on Failure

Sigaction structure of the body of the detailed:

struct sigaction{    void (* sa_handler) (int);//保存信号处理函数的地址    sigset_t sa_mask;  //一个调用信号捕捉函数之前要加到进程信号屏蔽字中的信号集    int sa_flags;//信号处理选项}该结构体后边的两个字段时用于指定信号相关的选项和特性,在此只需要全部填为0即可

Use the Sigaction () function:

#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h>/** Timeout processing function **/voidTime_out (intSIG) {if(sig = = SIGALRM) {Puts (" Time Out"); } Alarm (2);}intMainintARGC,Char*argv[]) {inti =0;//Declare a sigaction variablestruct Sigaction Act;/** initializes the value in the ACT variable **/Act.sa_handler = time_out;//Initialize the address of the signal processing functionAct.sa_flags =0;//Initialize signal processing flagSigemptyset (&act.sa_mask);//used to initialize and empty the act.sa_mask signal setSigaction (Sigalrm,&act,0);//Call the Sigaction functionAlarm2);//Set Clock     for(;i<3; i++) {puts ("Wait ... .."); Sleep -); }return 0;}
With these knowledge about process, zombie process processing, we can make a multi-process server, so that we can serve multiple clients at the same time.

Multi-Process Server:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <signal.h>#include <string.h>#include <sys/socket.h>#include <arpa/inet.h>#include <stdbool.h>#define Buff_sizevoidError_handling (Char*message);voidRead_child_proc (intSIG);intMainintARGC,Char*argv[]) {//server and client sockets    intServer_socket;intClient_socket;//server and client address    structSockaddr_in server_addr;structSockaddr_in client_addr;//To save the process IDpid_t pid;//Semaphore structure body variable    structSigaction Act;//To save the length of the socket addressSocklen_t addr_size;//To save string length    intStr_len;//To record the result of setting the semaphore    intState//character buffering    CharBuff[buff_size];//For the end of the control program    BOOLIs_running =true;//Check whether the number of arguments passed is legal    if(argc!=2){printf("Usage:%s <port> \ n", argv[0]);Exit(1); }//Initialize semaphore mechanismAct.sa_handler = Read_child_proc; Act.sa_flags =0;    Sigemptyset (&act.sa_mask); State = Sigaction (Sigchld,&act,0);//Initialize socketServer_socket = socket (Pf_inet,sock_stream,0);memset(&AMP;SERVER_ADDR,0,sizeof(SERVER_ADDR));    server_addr.sin_family = af_inet;    SERVER_ADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any); Server_addr.sin_port = htons (Atoi (argv[1]));//Bind address      if(Bind (Server_socket, (structSOCKADDR *) &server_addr,sizeof(SERVER_ADDR)) == -1) {error_handling ("bind () Error"); }//Set monitoring    if(Listen (Server_socket,5) == -1) {error_handling ("Listen () Error"); }//through the cycle to provide continuous service     while(is_running) {addr_size =sizeof(CLIENT_ADDR); Client_socket = Accept (Server_socket, (structSOCKADDR *) &client_addr,&addr_size);//For inspection        if(Client_socket = =-1){Continue; }Else{printf("New Client connected...............\n"); }//Create a new processPID = fork ();//Check whether the creation was successful        if(PID = =-1) {Close (client_socket);Continue; }//Sub-process run section where the server and client interactions are performed        if(PID = =0) {Close (server_socket);//continuously sends the read data to the client until the read is complete             while((Str_len = Read (client_socket,buff,buff_size))! =0) {write (Client_socket,buff,str_len); }//Close client connection after sending finishedClose (Client_socket);puts("The client disconnected ...");//Child process complete task, return            return 0; }Else{Close (client_socket); }    }//Shut down the server completely, but because the while loop in front is a dead loop, it is not normally executedClose (Server_socket);return 0;}/** Sub-process handler function **/voidRead_child_proc (intSIG) {pid_t pid;intStatusCall the Waitpid () function in the semaphore processing function to read the end information of the child process, destroy the child process completely, and the parent process can further process the processing result of the child process according to the information in the statusPID = Waitpid (-1, &status,wnohang);printf("Remove proc ID:%d \ n", PID);}/** error handling function **/voidError_handling (Char* message) {fputs(Message,stderr); FPUTC (' \ n ', stderr);Exit(1);}

Since then, we have completed the establishment of a multi-process server program that we can use to serve multiple clients at the same time.

TCP/IP Programming----process and multi-process server under Linux

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.