2017-10-08 96 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

相关问题