【linux下c言語サーバ開発シリーズ1】マルチプロセス処理マルチクライアントの接続


上記では、非常に簡単なリターンサーバのdemoが提供されているが、このdemoの役割は非常に限られており、1つのクライアントの接続しか受信できず、その後、それと連絡を取り、通信を行うことができる.このクライアントが接続を切断してから、別の接続を処理することができます.機能が弱すぎます.マルチプロセスプログラムの設計を習ったことがあるので、複数のクライアントの接続を同時に処理できるように、ここではリターンサーバのマルチプロセスバージョンを提供します.
マルチプロセスは主にfork関数によって行われ、彼は特殊な関数であり、1回の呼び出し、2回の戻りである.戻り値が0より大きい場合は、親プロセスを表し、戻り値が子プロセスのpidを表します.戻り値が0に等しい場合は、サブプロセスであることを示します.サブプロセスは、親プロセスのコピーであり、親プロセスのすべてのものを保持します.しかし、サブプロセスに別の関数を実行させる必要があります.この関数は、プログラムに書いてサブプロセスで呼び出すことができます.既存のファイルでも、execファミリーの関数を使用して、サブプロセスの内容を複写することができます.この部分を具体的にどのように処理するかは、あなたのビジネスニーズを完全に見ています.この例では,既に受け入れられた接続に対して読み書き操作を行う.
返される親プロセスでは、プロセッサのメインフレームワークの内容を続行する必要があることがよくあります.また、サブプロセスのリソースを回収する必要があります.すなわち、サブプロセスの実行が完了するのを待って、waitとwaitpid関数でサブプロセスを回収し、ゾンビプロセスになってリソースを占有しないようにする必要があります.waitはサブプロセスの終了状態を返すことができ、waipidはブロックされていない処理を行うことができる.waitの補強版です.
次はこのバージョンのリターンサーバのdemoコードです.貼ってください.コードが再構築されていないため、乱れているように見えます.特に読み書き関数は,現在はまだばらばらな状態であり,抽出されていない.また,waitを行わないと引っかかりやすくなり,これは次に解決策を提供する.
#include"head.h"
#define MAX_USER 1024
#define BUF_SIZE 1024 

typedef struct user  //yon {
        int conn;   //           
        sockaddr_in client_addr; //     
        char bufread[BUF_SIZE]; //       
        char bufwrite[BUF_SIZE]; //      
} user;


int main(int argc, char **argv)
{
        if(argc<3)
        {
                printf("usage: %s ip port
",basename(argv[0])); exit(0); } printf("start echoback server...
"); char * ip=(char * ) argv[1]; int port =atoi(argv[2]); /* , sockaddr_in */ struct sockaddr_in server_address; bzero(&server_address,sizeof(server_address)); server_address.sin_family=AF_INET; inet_pton(AF_INET,ip,&server_address.sin_addr); server_address.sin_port=htons(port); int listenfd=socket(AF_INET,SOCK_STREAM,0); assert(listenfd>=0); int reuse=1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)); setnonblock(listenfd); int ret=bind(listenfd,(struct sockaddr *) &server_address, sizeof(server_address)); assert(ret==0); ret=listen(listenfd,5); assert(ret==0); /* , */ int run_flag=1; char buf[1024]; int conn=-1; user users[MAX_USER]; int stop[MAX_USER]; for(int i=0;i<MAX_USER;i++) stop[i]=0; int user_number=0; while(run_flag) { int acfd=accept(listenfd,NULL,NULL); if(acfd>=0) { printf("acfd>0,hhahahaha"); user_number++; /*users[user_number] conn, */ users[user_number].conn=acfd; pid_t pid=fork(); if(pid<0) { printf("fork error
"); exit(0); } else if (pid==0) /* */ { close(listenfd); // , setnonblock(users[user_number].conn); //while(!stop[ users[user_number].conn] ) while(1) { int readn=read(users[user_number].conn,users[user_number].bufread,BUF_SIZE); // printf("readn=%d
",readn); //printf("errno=%d
",errno); if( (readn<0) && (errno!=EAGAIN)) { printf("a
"); printf("read fail, client %d
",users[user_number].conn); close(users[user_number].conn); //stop[ users[user_number].conn ]=1; //break; exit(0); } else if (readn==0) { printf("b
"); close(users[user_number].conn); //stop[ users[user_number].conn ]=1; //break; exit(0); } else if (readn>0) { printf("pid= %d
",getpid()); users[user_number].bufread[readn]='\0'; memcpy(users[user_number].bufwrite,users[user_number].bufread,sizeof(users[user_number].bufread)); int writen=write(users[user_number].conn,users[user_number].bufwrite,sizeof(users[user_number].bufwrite)); memset(users[user_number].bufread,0,sizeof(users[user_number].bufread)); printf("write %d bytes to %d
",writen,users[user_number].conn); } } } /*parent process*/ else { close(users[user_number].conn); int stat_loc; /* , , sigchld */ // wait((int *)&stat_loc); printf("parent, finished wait
"); } } } }

このコードは、実行後、複数のtelnetでサーバに接続でき、サーバが複数のクライアントにサービスできることを発見します.コードに存在する欠点は、読み書き論理が悪い、サブプロセスの回収が行われていないなどで、次のバージョンで変更されます.また、マルチプロセスは一般的にプロセスプールを使用し、後のバージョンでも実装されます.お楽しみに.