2

これは私のコードのスニペットです:

signal (SIGINT, ( void *)sig_handler); 

while(1){
    newsockd = -1;
    memset(&cli_addr, 0, sizeof(cli_addr));

    if((newsockd = accept(sockd, (struct sockaddr *) &cli_addr, (socklen_t *) &socket_len)) < 0){
        perror("Errore nella connessione\n");
        onexit(newsockd, sockd, 0, 2);
    }
    fprintf(stdout, "Ricevuta richiesta di connessione dall' indirizzo %s\n", inet_ntoa(cli_addr.sin_addr));

    child_pid = fork();
    if(child_pid < 0){
        perror("Fork error");
        onexit(newsockd, sockd, 0, 2);
    }
    if(child_pid == 0){
        do_child(newsockd);
        exit(0);
    }
    else{
       while(waitpid(child_pid, NULL, WNOHANG) > 0)
        continue;
       }
    }
}

および関数 sig_handler:

void sig_handler(const int signo, const int sockd, const int newsockd){
  if (signo == SIGINT){
    printf("Received SIGINT, exiting..\n");
    if(newsockd) close(newsockd);
    if(sockd) close(sockd);
    exit(EXIT_SUCCESS);
  }
}

sighandlerが複数回呼び出されるため、「CTRL + C」を押すと問題が発生します。
例:

  1. サーバーはリッスンしています。
  2. 2 x 接続が受信されました。
  3. 2 x 子供用フォーク;
  4. 2 x 子は閉じています。
  5. サーバーを閉じたいので、CTRL + Cを押します。

予想される出力:
received SIGINT, exiting....
実際の出力:
received SIGINT, exiting....
received SIGINT, exiting....
received SIGINT, exiting....

なぜこのような動作になったのですか?

編集:コードが更新されました
これは、1つのフォークが完了し、子が終了したときにサーバーを閉じたときに起こることです:

^C7518
7516
Received SIGINT, exiting...
Received SIGINT, exiting...

exit(0)解決策が見つかりました: 問題は、命令の後に書いていないことでしたdo_child()...コードが更新されました!

4

4 に答える 4

4

シグナルは、現在のプロセスのすべての子プロセスに送信されます。
コードで を使用している場合fork、メイン プロセスからSIGINTハンドラを継承する子プロセスを作成します。そのため、メッセージが数回出力されます。

于 2012-09-05T08:48:11.053 に答える
2

観察数は少なく、

1) signal 関数の代わりに sigaction を使用することをお勧めします。 http://pubs.opengroup.org/onlinepubs/7908799/xsh/sigaction.html

2)現在のコードにいくつかの修正を加えました。あなたは使用することができます

if(child_pid == 0)
{
   /*Now in the child make again the action for SIGINT default, so that 
   your handler does not get called.*/ 
       signal (SIGINT, SIG_DFL);
       do_child(newsockd);
}   

3) メインループで waitpid を呼び出しているのはなぜですか? SIGCHLD のハンドラーを用意し、その中で wait/waitpid を使用する必要があります。

理想的には、クライアントにサービスを提供する子を作成した後、メイン ループは受け入れに戻る必要があります。(子の作成後にブロックされている場合、サーバーはどのように並行サーバーになりますか?)

(または、最初のバージョンでは、SIGINT のシグナル ハンドラーを呼び出した後、代わりにこれを使用しないことをお勧めします。

signal(SIGCHLD, SIG_IGN);  //This should  automatically get rid of zombies.

(あなたのシステムでこれを実験してください)

参照用リンク - http://en.wikipedia.org/wiki/SIGCHLD

4)SIGINTのハンドラへの引数も適切ではないようです.適切なプロトタイプは

void (*signal(int sig, void (*func)(int)))(int);

しかし、あなたのハンドラーは

void sig_handler(const int signo, const int sockd, const int newsockd).

sockfd と newsockfd の値はどのように渡されますか?
リンク

http://pubs.opengroup.org/onlinepubs/009696899/functions/signal.html

于 2012-09-05T10:07:32.990 に答える
0

子プロセスを強制終了する方法がわかりません。子プロセスがまだ Zomb ステータスになっていない場合、sign_handler が動作します。子プロセスのライフサイクルの順序を明確にするために、さらにログを追加する必要がある場合があります。

于 2012-09-05T09:12:59.453 に答える