2016-11-04 77 views
1

問題:我希望我的單個處理程序按預期工作,並在按Ctrl c時輸出「EXITED NICELY」。這是一項任務,我們必須使用信號處理程序。正如你所看到的,我也對sigaction進行了嘗試,但得到了相同的結果。信號處理程序無法在我的C http服務器上工作

當前行爲:「工作」正在打印出來,表明信號處理程序正在工作,但它必須卡在某處,因爲它不會取消程序。雖然如果我按ctrl c然後發送一個http請求到服務器,例如curl http:/ localhost:port/file.name,它會優雅地退出並打印出我想要的信息。不過,我希望這樣做,而不必發送請求。

通過進一步的研究編輯。我在接受電話之前和之後打印了一張照片。打印之前將打印一次,然後接受將持有它,直到它收到連接。所以問題出在哪裏,但我們如何解決這個問題呢?

#include<stdio.h> 
#include<string.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<sys/types.h> 
#include<sys/stat.h> 
#include<sys/socket.h> 
#include<arpa/inet.h> 
#include<netdb.h> 
#include<signal.h> 
#include<fcntl.h> 
#include "http_common.h" 
#define CONNMAX 1000 
#define BYTES 1024 

char *ROOT; 
int verbose; 
int signalReceived = 1; 
int listenfd, clients[CONNMAX]; 
void error(char *); 

static void clean(int arg) 
{ 
     if(arg == SIGINT) { 
       printf("work\n"); 
       signalReceived = 0; 
       //signal(SIGINT, clean); 
     } 
     else if(arg == SIGHUP) { 
       signalReceived = 0; 
     } 
} 

int main(int argc, char *argv[]) 
{ 
     //struct sigaction act; 
     //memset (&act, '\0', sizeof(act)); 
     //act.sa_handler = clean; 
     //sigemptyset(&act.sa_mask); 
     //act.sa_flags = SA_RESTART; 
     signal(SIGINT, clean); 
     //signal(SIGHUP, clean); 
     //if (sigaction(SIGINT, &act, NULL) == -1) 
     //  printf("doing something\n"); 
     struct sockaddr_in clientaddr; 
     socklen_t addrlen; 
     char c; 
     char PORT[6]; 
     ROOT = getenv("PWD"); 
     strcpy(PORT, "8888"); 
     int slot; 
     while ((c = getopt (argc, argv, "p:v")) != -1) 

       switch (c) { 
       case'v': 
         verbose = 1; 
         break; 
       case'p': 
         strcpy(PORT, optarg); 
         break; 
       case'?': 
         fprintf(stderr, "Wrong arguments given\n"); 
         exit(1); 
       default: 
         exit(1); 
       } 
     printf("Listening on port %s%s%s, root is %s%s%s\n", "\033[92m", PORT, "\033[0m", "\033[92m", ROOT, "\033[0m"); 
     int i = 0; 
     for (i = 0; i < CONNMAX; i++) 
       clients[i] = -1; 
     startServer(PORT, &listenfd); 
     while (signalReceived == 1) { 
       addrlen = sizeof(clientaddr); 
       clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen); 
       if (clients[slot] < 0) 
         exit(0); 
       else { 
         if (fork() == 0) { 
           respond(slot, verbose, ROOT, clients); 
          exit(0); 
         } 
       } 
       while (clients[slot] != -1) 
         slot = (slot + 1) % CONNMAX; 

     } 
     printf("EXITED NICLEY\n");//ients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen); 
     return 0; 
} 

回答

1

您有sigaction()並沒有SA_RESTART標誌註冊的信號。

當您註冊信號處理程序signal()時,它將設置SA_RESTART標誌。見the glibc manual

在GNU C庫,建立與信號處理程序設置的所有標誌零除SA_RESTART,其價值取決於你與siginterrupt的設置。看到中斷的基元,看看這是關於什麼。

SA_RESTART設置,信號將中斷(大部分)系統調用,但它會重新啓動而不是他們。見the signal man page

如果信號處理程序被調用時系統調用或庫函數呼叫被阻塞,則:

  • 呼叫信號處理程序返回之後自動重啓;或
  • 該調用失敗,並顯示錯誤EINTR。

這兩個行爲中的哪一個取決於接口以及信號處理程序是否使用SA_RESTART標誌建立(請參閱sigaction(2))。

+0

非常感謝你 – TheMangaStand