ネットワークプログラミング学習_シンプルなマルチプロセス同時サーバ/クライアント

4739 ワード

本文はUNP第五章学習ノート
一、waitとwaitpid関数
#include
pid_t wait(int* statloc);
pid_t waitpid(pid_t pid,int statloc,int options);
この2つの関数は、サブプロセスの終了を待つために使用される.パラメータstatlocはプロセスの終了状態を返し、終了したサブプロセスidを返します.
waitpidはwaitの機能強化版で、いくつかの有用な機能を追加したので、もっとよく使われています.
  • pid関数は、どのサブプロセスidを待つかを特定し、-1は、最初の終了を表すサブプロセス
  • を表す.
  • optionsでは、WNOHANGが一般的に使用される追加オプションを指定できます.サブプロセスが終了していない場合、
  • はブロックされません.
  • linuxは信号量をキュー処理しないため、waitを使用すると信号量が失われる可能性があり、waitpid+WNOHNG処理
  • を推奨する.
    二、捕獲信号量
    ネットワークプログラミングはsignal関数でいくつかの信号量をキャプチャして処理します.
    typedef void(*sig_t) ( int );
    sig_t signal(int signum,sig_t handler);
    SignumはSIGPIPEなどの信号量であり、handlerは信号処理関数であり、フォーマットは
    void handler(int signum);
    handlerはまだ
    SIG_IGN(無視)またはSIG_DFL(既定値)
    三、EINTRエラー
    プログラムが信号をキャプチャしている場合、read、write、acceptなどのいくつかのブロック関数は、信号をキャプチャして処理することによってエラー値を返し、errnoをEINTRに設定すると、通常の処理方法は再実行されます.たとえば、次のようになります.
    Again:
    int newfd = accept(fd,NULL,NULL);
    if(newfd<0 && errno==EINTR)
        goto Again;
    ......
    

    四、SIGCHLD信号量
    サブプロセスが終了すると、親プロセスはこの信号を受信し、デフォルトの効果は無視されます.これによりサブプロセスはゾンビプロセスとなり、多くなるとプロセス番号がいっぱいになってforkの新しいプロセスができなくなる可能性があります.だから普通は処理します.
    1はSIGCHLD信号にhandler関数を指定し、関数でwaitpidを使用してサブプロセスを終了する
    void sig_chld(int signum)
    {
        pid_t pid;
        while( (pid=waitpid(-1,NULL,WNOHANG))>0 )
                printf("process %d close
    ",pid); }

    2 SIGCHLDをSIGに直接バインドするIGN
    signal(SIGCHLD,SIG_IGN);
    

    五、SIGPIPE信号量
    この信号量は、相手が接続を閉じる、2回目にこの接続を書き込み操作したときに発生する(1回目の書き込みは0に戻る).正しい流れはこの信号を生成しません.最初のwriteが0を返した後、この接続を閉じるべきだからです.この信号はプログラムを終了しますが、多くの場合無視すべきです.
    signal(SIGPIPE,SIG_IGN); 
    mysqlなどのアプリケーションを使用して大量の接続を生成する場合は、プログラムがわけがわからずに終了しないように無視したほうがいいです.
    六、簡単なマルチプロセス同時サーバプログラムの例
    エラー処理を省略
    void sig_chld(int signo)
    {
            pid_t pid;
            while((pid=waitpid(-1,NULL,WNOHANG))>0)
            {
                    printf("child %d terminated
    ",pid); } return ; } int main() { int ret; int listenfd = socket(AF_INET,SOCK_STREAM,0); sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_port=htons(8003); addr.sin_addr.s_addr=htonl(INADDR_ANY); printf("read ret =0,close socket
    "); printf("read from newfd failed! ret=%d,%s
    ",ret,strerror(errno)); ret = bind(listenfd,(sockaddr*)&addr,sizeof(sockaddr_in)); ret = listen(listenfd,5); setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, NULL, sizeof(int)); int newfd; sockaddr_in client_addr; socklen_t client_addr_len; char* cli_ip; int cli_port; char recv_buf[100]; char send_buf[100]; signal(SIGCHLD,sig_chld); while ( (newfd = accept(listenfd,(sockaddr*)&client_addr,&client_addr_len)) >0 ) { pid=fork(); if(pid==0) { close(listenfd); while(1) { ret = read(newfd,recv_buf,sizeof(recv_buf)); if(ret<0) { printf("read from newfd failed! ret=%d,%s
    ",ret,strerror(errno)); break; }else if(ret == 0) { close(newfd); break; }else{ recv_buf[ret]='\0'; printf("recv %d bytes:[%s]
    ",ret,recv_buf); strcpy(send_buf,"world"); ret = write(newfd,send_buf,strlen(send_buf)); printf("send %d bytes,[%s]
    ",ret,send_buf); } } close(newfd); } close(newfd); } return 0; }
    void sig_chld(int signum)
    {
        pid_t pid;
        while( (pid=waitpid(-1,NULL,WNOHANG))>0 )
                printf("process %d close
    ",pid); }
    void sig_chld(int signum)
    {
        pid_t pid;
        while( (pid=waitpid(-1,NULL,WNOHANG))>0 )
                printf("process %d close
    ",pid); }