Linux Socketマルチプロセスサーバ

6269 ワード

server.c
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <signal.h>

#define MAXLINE 1024

// 1:
static void sig_child(int signo)
{
        pid_t pid;
        int status;
        while( (pid=waitpid(-1, &status,WNOHANG)) > 0)   //2: W NO HANG   
        {
                printf("child terminated,pid:%d
", pid); if (WIFEXITED(status)) // W IF EXIT ED // 3: { printf("exit code:%d
",WEXITSTATUS(status)); //4: W EXIT STATUS } } } int main() { int listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd == -1) { printf("socket error[%d]:%s
", errno, strerror(errno)); exit(errno); } struct sockaddr_in server_addr; memset(&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(55555); if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { printf("bind error[%d]:%s
", errno, strerror(errno)); exit(errno); } if (listen(listen_fd, 3) == -1) { printf("listen error[%d]:%s
", errno, strerror(errno)); exit(errno); } //5: catch child terminate signal signal(SIGCHLD,sig_child); while (1) { struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(client_addr)); int len = sizeof(client_addr); int client_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &len); if (client_fd == -1) { printf("accept error[%d]:%s
", errno, strerror(errno)); sleep(1); continue; } pid_t pid = fork(); if (pid < 0) { printf("fork error[%d]:%s
", errno, strerror(errno)); continue; }else if (pid == 0) // child process { close(listen_fd); //6: close no use parent fd in child printf("child process[%d],ppid:%d
", getpid(), getppid()); char rb[100] = {0}; int recv_len = recv(client_fd, rb, MAXLINE, 0); if (recv_len == -1) { printf("recv error[%d]:%s
", errno, strerror(errno)); exit(errno); } printf("recv[%d]:%s
", recv_len, rb); strcat(rb, ", has been received by server, the msg from server"); if (send(client_fd, rb, strlen(rb), 0) == -1) { printf("send error[%d]:%s
", errno, strerror(errno)); exit(errno); } printf("send success
"); close(client_fd); exit(0); // 8 } close(client_fd); //7: close no use child fd in parent } close(listen_fd); }

 
 
1.登録信号SIGCHLDのための処理関数
SIGCHLD:サブプロセスが終了すると、親プロセスはこの信号を受信します.親プロセスがこの信号を処理していない場合、サブプロセスは終了しますが、カーネルプロセステーブルにテーブルアイテムが占有されます.この場合、サブプロセスはゾンビプロセスと呼ばれます.この場合、(親プロセスがSIGCHALD信号を無視したり、キャプチャしたり、waitが派生したサブプロセスが発生したり、親プロセスが先に終了したりした場合、サブプロセスの終了は自動的にinitプロセスによって引き継がれます).
 
2. 3  4
関数プロトタイプ:pid_t waitpid(pid_t pid,int * status,int options);
関数の説明:
waitpid()が呼び出されたときにサブプロセスが終了した場合、waitpid()はすぐにサブプロセス終了ステータス値を返します.サブプロセスの終了ステータス値は、パラメータstatusによって返されます.
サブプロセスのプロセス識別コードも一緒に返されます.終了状態値を気にしない場合は、パラメータstatusをNULLに設定できます.
 
パラメータpid:
待ちたいサブプロセス識別コードの数値的意味は次のとおりです.
pid<-1プロセスグループ識別コードがpid絶対値である任意のサブプロセスを待つ
pid=-1はwait()に相当する任意のサブプロセスを待つ
pid=0待機プロセスグループ識別コード現在のプロセスと同じサブプロセス
pid>0サブプロセス識別コードがpidのサブプロセスを待つ
 
パラメータ:
戻るステータス
WIFEXITED(status)正常終了サブプロセスが戻った状態であれば真である.この場合、WEXITSTATUS(status)を実行し、サブプロセスをexitまたは_に渡すことができます.eixtの下位8ビット.
WEXITSTATUS(status)は、サブプロセスexit()が返す終了コードを取得し、通常はWIFEXITEDで正常に終了するかどうかを判断してこのマクロを使用する.
 
パラメータoptions:
waitpidを制御する追加のオプションが用意されています.パラメータoptionは0または「|」演算子で接続して使用できます.たとえば、次のようにします.
WNOHANG pidが指定したサブプロセスが終了しない場合、waitpid()関数は0を返し、待たない.終了すると、そのサブプロセスのIDが返される
 
5  signal(SIGCHLD,sig_child); サブプロセス終了信号の処理関数の登録
親プロセスがこの信号を登録処理する場合、サブプロセスはexitを実行した後にゾンビプロセスを生成します.以下のようにします.
zxnms 18717 16191 0 15:53 pts/0 00:00:00 ./server
zxnms 18719 18717 0 15:53 pts/0 00:00:00 [server]
zxnms 18721 18717 0 15:53 pts/0 00:00:00 [server]
zxnms 18723 18717 0 15:53 pts/0 00:00:00 [server]
親プロセスはwaitまたはwaitpid処理ゾンビプロセスを実行します.
あるいは、親プロセスが終了すると、サブプロセスのゾンビプロセスが孤児プロセスになり、これらのゾンビプロセスがinitによって回収されます.
信号処理関数の処理では、親プロセスの現在のタスクをブロックせず、サブプロセスが信号を送信した場合にのみ処理できます.
 
6サブプロセスで無効な親プロセスのリスニングsocket fdを閉じる
 
7親プロセスでサブプロセスが使用されていないsocket fdは、マルチプロセス環境ではcloseが参照カウントを1だけ減らし、すべてのプロセスがcloseになり、参照カウントが0になるまでカーネルがFINを送信しないため閉じます.
 
8ここでは直接終了します.そうしないと、サブプロセスの後ろの文もwhileループになり、forkにも実行されます.それは2層だけでなく、ネストされ続け、サブプロセスのサブプロセスのサブプロセスになります.