2014-10-22 99 views
0

我有一個客戶機/服務器程序,現在我要處理的信號。當客戶端關閉連接時(例如關閉終端),服務器必須處理SIGPIPE,對嗎?我想實現這樣的事情。可能嗎?sigpipe c服務器/客戶端 - 程序重新啓動?

server.c:

void function(){ 
    printf("..."); 
    read(socket,buff,size); 
    //IF THE CLIENT CLOSES, THE SERVER RECEIVES A SIGPIPE 
    ...the resting part of the scheduled code should be ignored if sigpipe is received, and the program should begin from where I wrote on the handler of the sigpipe... 
    printf("not working"); //this should be ignored, but it's printed 2 times immediatly, and when I've finished the actions indicated in the function by the handler, it prints it another time, because the program counter restarts from here... 
} 

void sigpipehandler(){ 
    close(socket); 
    main(); //I'd like that the program restarts from the main when I've received a SIGPIPE. It restarts from the main, but only after having printed "not working" two times... 
} 

int main(){ 
    sigPipe.sa_sigaction = &sigpipehandler; 
    sigPipe.sa_flags = SA_SIGINFO; 
    sigaction(SIGPIPE, &sigpipehandler, NULL); 
    ...code... 
} 
+0

當你寫一個封閉的管你得到SIGPIPE;當你從一個封閉的管道讀取時,你會得到EOF(零字節讀取)。 – 2014-10-22 05:54:37

+0

@JonathanLeffler感謝您的回覆。因此,如果我在示例中更改了讀取操作,那麼如何處理SIGPIPE? – testermaster 2014-10-22 06:00:48

+3

簡單的方法是忽略SIGPIPE,然後監視來自'寫入返回值()'。如果返回-1並將errno設置爲EINTR,則可能懷疑您獲得了SIGPIPE,特別是如果您沒有任何其他信號處理集。當然,你應該看看'write()'和'read()'的返回值 - 無論如何。你不想從你的信號處理器遞歸調用main()。你可以在'main()'中編寫一個循環,並讓信號處理程序設置一個標誌,並在循環中進行測試。根據標準C,關於您在信號處理程序中可以做的唯一事情是修改變量或退出。 – 2014-10-22 06:02:56

回答

1

轉換註釋到一個答案。

請注意,只有在寫入到沒有進程打開管道讀取結束的進程的管道時,纔會獲得SIGPIPE。當您從沒有進程打開管道的寫入結束的管道讀取時,會得到EOF(零字節讀取)。

因此,如果我在示例中將read()更改爲write()。我該如何處理SIGPIPE?

簡單的是忽略SIGPIPE(signal(SIGPIPE, SIG_IGN)),然後從write()監視返回值。如果回來了-1和errno設置爲EINTR,你可以假設你被一些信號中斷,並極有可能一個SIGPIPE,特別是如果你沒有任何其他的信號處理組。和read() - - 當然,你應該從write()在看的返回值呢。

或者,如果你想要一個明確的SIGPIPE處理程序,那麼你肯定不想遞歸調用main()從信號處理程序。您可以在main()中編寫一個循環,並讓信號處理程序設置一個您在循環中測試的標誌。根據標準C,關於您在信號處理程序中可以做的唯一事情是修改變量或退出。

static volatile sigatomic_t sig_recvd = 0; 
static int sock_fd = -1; 

void sigpipehandler(int signum) 
{ 
    close(sock_fd); 
    sock_fd = -1; 
    sig_recvd = signum; 
} 

int main(void) 
{ 
    sigPipe.sa_sigaction = &sigpipehandler; 
    sigPipe.sa_flags = SA_SIGINFO; 
    sigemptyset(&sigPipe.sa_mask); 
    sigaction(SIGPIPE, &sigpipehandler, NULL); 

    int done = 0; 

    while (!done) 
    { 
     if (sock_fd == -1) 
     { 
      if (sig_recvd != 0) 
      { 
       ...report signal received... 
       sig_recvd = 0; 
      } 
      ...(re)open socket on sock_fd... 
     } 
     ...code as before - sets done = 1 when loop should terminate... 
    } 
    return 0; 
} 

注意,命名的變量相同的系統調用(socket在您的代碼)被如履薄冰;因此,我將其重命名爲sock_fd。一個名爲socket的全局變量將是一個非常糟糕的主意。