my code is a multiprocess concurrent server process,it use system V message queue to communicate with client process,one client with one child process. first i want wait child process which is not use any more.and when i set SIGCHLD handler with SIG_IGN,the program can work correct,but always mistake when i catch SIGCHLD, the mistake is client process blocked in mesrcv system call,which means server don't send message to client . second , the server process went out when i enter ^\\ to quit my client process ,i made it become a daemon and make it run in backgroud forever,so i think maybe the waitpid calling are wait itself?although i think it's impossible
//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);
}
}
the core code of client process are below
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;
}
This code doesn't allow error handling or restarting the call after it's interrupted:
while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){
...
You don't properly handle msgrcv()
being interrupted and needing to be called again.
Per the POSIX msgrcv()
documentation :
ERRORS
The
msgrcv()
function shall fail if:...
[EINTR] The
msgrcv()
function was interrupted by a signal.
Note the Linux msgrcv()
man page states:
If no message of the requested type is available and
IPC_NOWAIT
isn't specified inmsgflg
, the calling process is blocked until one of the following conditions occurs:
A message of the desired type is placed in the queue.
The message queue is removed from the system. In this case, the system call fails with
errno
set toEIDRM
.The calling process catches a signal. In this case, the system call fails with
errno
set toEINTR
. (msgrcv()
is never automatically restarted after being interrupted by a signal handler, regardless of the setting of theSA_RESTART
flag when establishing a signal handler.)
What does this style of code achieve:
while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){
So you save some lines of code. Were you selling a textbook with lots of code in it, the saved lines of code would mean a few pages less per book, saving a few pennies. Over enough copies, that pays for the publisher's swimming pool.
Stuffing everything into a conditional like that is really, really bad. There's nothing gained over explicitly using multiple lines of code:
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;
}
...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.