2017-10-08 13 views
1

mon code est un processus serveur simultané multiprocessus, il utilise la file d'attente de messages système V pour communiquer avec le processus client, un client avec un processus enfant. premier je veux attendre le processus de l'enfant qui n'est plus utiliser.et quand j'ai défini SIGCHLD gestionnaire avec SIG_IGN, le programme peut fonctionner correctement, mais toujours erreur quand je attrape SIGCHLD, l'erreur est le processus client bloqué dans l'appel système mesrcv, ce qui signifie que le serveur n'envoie pas de message au client. deuxième, le processus du serveur est sorti quand j'ai entré^\ pour quitter mon processus client, je l'ai fait devenir un démon et le faire tourner en backgroud pour toujours, donc je pense que les appels waitpid sont attendent lui-même? il est impossiblepourquoi mon gestionnaire de signal n'attend pas juste un processus enfant?

//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); 
    } 

}

le code de base du processus client sont inférieurs

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, "fichier n'existe pas \ n");' L'argument de taille manque ici. (votre compilateur devrait au moins générer un avertissement) – wildplasser

+0

désolé, c'est mon erreur d'orthographe. Je veux corriger mais il ne semble pas prendre en charge modification.my client et le programme du serveur peut être compilé avec succès – Peterhaiker

+0

Ne devrait pas compiler. Changez les drapeaux du compilateur. Pour gcc, ajoutez '-Wall -Wpedantic' – wildplasser

Répondre

1

Ce code ne permet pas le traitement des erreurs ou le redémarrage e e appel après sa interrompu:

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

Vous ne gère pas correctement msgrcv() étant interrompue et qu'il convient d'appeler à nouveau.

par the POSIX msgrcv() documentation:

ERREURS

La fonction msgrcv() doit échouer si:

...

[EINTR] La fonction msgrcv() a été interrompu par un signal.

Remarque the Linux msgrcv() man page états:

Si aucun message du type demandé est disponible et IPC_NOWAIT n'est pas spécifié dans msgflg, le processus d'appel est bloqué jusqu'à ce que l'une des conditions suivantes se produit:

  • Un message du type souhaité est placé dans la file d'attente.

  • La file d'attente de messages est supprimée du système. Dans ce cas, l'appel système échoue avec errno défini sur EIDRM.

  • Le processus appelant capte un signal. Dans ce cas, l'appel système échoue avec errno défini sur EINTR. (msgrcv() n'est jamais automatiquement redémarré après avoir été interrompu par un gestionnaire de signal, indépendamment de le réglage du drapeau SA_RESTART lors de l'établissement d'un gestionnaire de signal .)

Qu'est-ce que ce style de code de réaliser:

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

vous sauver quelques lignes de code. Si vous vendiez un manuel contenant beaucoup de code, les lignes de code sauvegardées signifieraient quelques pages de moins par livre, ce qui vous permettrait d'économiser quelques sous. Sur un nombre suffisant de copies, cela paye pour la piscine de l'éditeur. Remplacer tout dans un conditionnel comme ça est vraiment, vraiment mauvais. Il n'y a rien gagné sur explicitement en utilisant plusieurs lignes de 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; 
    } 
    ... 
} 
+0

merci beaucoup.maintenant fonctionne bien.J'ignore vraiment la situation que msgrcv est interrompue par SIGCHLD.and je vais garder à l'esprit de vous suggestion.thank sincèrement – Peterhaiker