2017-10-08 97 views
1

我的代碼是一個多進程併發服務器進程,它使用系統V消息隊列與客戶端進程進行通信,一個客戶端與一個子進程通信。 第一個我希望等待子進程不再使用。當我設置SIGCHLD處理程序與SIG_IGN,程序可以正常工作,但總是錯誤,當我趕上SIGCHLD,錯誤是客戶端進程阻塞在mesrcv系統調用,這意味着服務器不會發送消息給客戶端,當我輸入^ \來退出我的客戶端進程時,服務器進程終止,我使它成爲一個守護進程並使它永遠在背景中運行,所以我想也許這個waitpid調用正在等待自己?這是不可能的爲什麼我的信號處理程序不僅僅是等待子進程?

//this is signal handler 
void handler(int sig){ 
    waitpid(-1,NULL,WNOHANG); 
} 
//in main 
//my first step is make it become a daemon(fork twice) 
//my first step is using record lock to ensure only one running 
//then set signal handler and process message send by client 
if(signal(SIGCHLD,SIG_IGN)==SIG_ERR){ 
    //because its a daemon,so no tty and redirct stdin,stdout,stderr to /dev/null 
    syslog(LOG_ERR|LOG_USER,"set signal handler failed"); 
    return errno; 
} 
//now process the client request ,client message contant a client sysV message queue id and a filename,server report the file whether exist 
int pid; 
while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){ 
    if(0==rcv_size) 
     continue; 
    if((pid=fork())<=0){ 
     clibuf.mtype=srvbuf.mtype; 
     climsqid=strtol(srvbuf.filename,&filename,10); 
     if((fd=open(filename,O_RDONLY)==-1) 
      snprintf(clibuf.filename,"file doesn't exist\n"); 
     else{ 
      snprintf(clibuf.filename,"file exist\n"); 
      close(fd); 
     } 
     if(msgsnd(climsqid,&clibuf,1024,0)==-1) 
      syslog(LOG_ERR,"send message to client pid:%d failed,srvbuf.mtype); 
     if(pid==0) //if pid<0,then no child process is created 
      exit(0); 
    } 

}

客戶端進程的核心代碼都低於

int main(int argc,char*argv[]){ 
//first ,i create the client message queue and open public serve message queue,then send struct msgbuf struct to server,the mtype is pid,the buffer behind mtype is composed by client message queue key and filename(no space between them) 
while(1){ 
if(msgsnd(sermsqid,&sndbuf,1024,0)!=-1){ 
    if(msgrcv(climsqid,&rcvbuf,1024,0,0)!=-1) 
     printf("type:%ld,file state:%s\n",rcvbuf.mtype,rcvbuf.filename); 
    else 
     printf("receive message failed\n"); 
} 
printf("input a filename you want to search:(^e to quit)"); 
fgets(filename,1024,stdin); 
if(filename[0]==5)//^e is 5 
    break; 
filename[strlen(filename)-1)='\0'; 
snprintf(sndbuf.filename,1024,"%d%s",climsqid,filename); 
} 
msgctl(climsqid,IPC_RMID,NULL); 
return errno; 
} 
+1

'snprintf(clibuf.filename,「文件不存在\ n」);'size參數在這裏丟失。 (你的編譯器至少應該生成一個警告) – wildplasser

+0

對不起,這是我的拼寫錯誤。我想修復,但它似乎不支持修改。我的客戶端和服務器程序可以編譯成功 – Peterhaiker

+0

不應該編譯。更改你的編譯器標誌。對於海灣合作委員會,添加'-Wall -Wpedantic' – wildplasser

回答

1

此代碼不允許錯誤處理或重新啓動日它的中斷後è電話:

while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){ 
    ... 

你不妥善處理msgrcv()中斷並需要再次調用。

the POSIX msgrcv() documentation

錯誤

msgrcv()功能將失敗,如果:

...

[EINTR]的msgrcv()函數被信號中斷。

the Linux msgrcv() man page狀態:

如果沒有所請求的類型的消息可用和IPC_NOWAIT不在msgflg指定 ,調用進程被阻止,直到的 下列情況之一發生:

  • 將期望類型的消息放入隊列中。

  • 消息隊列已從系統中刪除。在這種情況下,系統調用失敗,errno設置爲EIDRM

  • 調用進程捕獲一個信號。在這種情況下,系統調用失敗,errno設置爲EINTR。 (msgrcv()永遠不會自動 在被信號處理程序中斷後重新啓動,而不管 SA_RESTART標誌的設置在建立信號時處理器 。)

什麼的這段代碼風格實現:

while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){ 

因此可以節省您的一些代碼行。如果您銷售的教科書中包含大量代碼,保存的代碼行數將意味着每本書少了幾頁,從而節省了幾分錢。足夠的副本,支付出版商的游泳池。

把所有東西都塞進這樣的條件是非常糟糕的。沒有明確使用多行代碼獲得的結果:

for (;;) 
{ 
    ssize_t rcv_size; 
    do 
    { 
     errno = 0; 
     rcv_size = msgrcv(...); 
    } 
    while ((-1 == rcv_size) && (EINTR == errno)); 

    if (-1 == rcv_size) 
    { 
     perror("msgrcv()"); 
     break; 
    } 
    else if (0 == rcv_size) 
    { 
     continue; 
    } 
    ... 
} 
+0

非常感謝你。現在它工作正常,我真的忽略了SIGGLD中斷msgrcv的情況,我會記住你的建議。衷心地感謝你 – Peterhaiker

相關問題