要點(diǎn):
1.服務(wù)器子進(jìn)程中止時,給父進(jìn)程發(fā)送一個 SIGCHLD信號,該信號默認(rèn)是被忽略,需要自己處理------信號處理
2.為了 可移植性,使用自己的 signal 函數(shù)。代碼如下:
#include"unp.h"
Sigfunc*
signal(int signo,Sigfunc*func)
{
struct sigaction act,oact;
act.sa_handler=func;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
if(signo==SIGALM)
{
#ifdef SA_INTERRUPT
? ? ? ?act.sa_flags |=SA_INTERRUPT;
#endif
}else{
#ifdef SA_RESTART
act.sa_flags|=SA_RESTART;
#endif
}
if(sigaction(signo,&act,&oact)<0)
return(SIG_ERR);
return(oact.sa_handler);
}
}
}
附上sigaction的說明:
定義函數(shù) int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
函數(shù)說明 sigaction()會依參數(shù)signum指定的信號編號來設(shè)置該信號的處理函數(shù)。參數(shù)signum可以指定SIGKILL和SIGSTOP以外的所有信號。
如參數(shù)結(jié)構(gòu)sigaction定義如下
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
信號處理函數(shù)可以采用void (*sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t *, void *)。到底采用哪個要看sa_flags中是否設(shè)置了SA_SIGINFO位,如果設(shè)置了就采用void (*sa_sigaction)(int, siginfo_t *, void *),此時可以向處理函數(shù)發(fā)送附加信息;默認(rèn)情況下采用void (*sa_handler)(int),此時只能向處理函數(shù)發(fā)送信號的數(shù)值。
sa_handler此參數(shù)和signal()的參數(shù)handler相同,代表新的信號處理函數(shù),其他意義請參考signal()。
sa_mask 用來設(shè)置在處理該信號時暫時將sa_mask 指定的信號集擱置。
sa_restorer 此參數(shù)沒有使用。
sa_flags 用來設(shè)置信號處理的其他相關(guān)操作,下列的數(shù)值可用。
sa_flags還可以設(shè)置其他標(biāo)志:
SA_RESETHAND:當(dāng)調(diào)用信號處理函數(shù)時,將信號的處理函數(shù)重置為缺省值SIG_DFL
SA_RESTART:如果信號中斷了進(jìn)程的某個系統(tǒng)調(diào)用,則系統(tǒng)自動啟動該系統(tǒng)調(diào)用
SA_NODEFER :一般情況下, 當(dāng)信號處理函數(shù)運(yùn)行時,內(nèi)核將阻塞該給定信號。但是如果設(shè)置了 SA_NODEFER標(biāo)記, 那么在該信號處理函數(shù)運(yùn)行時,內(nèi)核將不會阻塞該信號.
之后使用wait()/waitpid()處理以終止的子進(jìn)程。
void sig_chld(int signo)
{
pid_t pid;
int stat;
while((pid=waitpid(-1,&stat,WNOHANG))>0)
printf("child %d terminated\n",pid);
return ;
}
3.SIGCHLD信號是在父進(jìn)程阻塞在慢系統(tǒng)調(diào)用(accept)時由父進(jìn)程捕獲,內(nèi)核就會使accept返回EINTR錯誤(被中斷的系統(tǒng)調(diào)用),而不處理該錯誤,于是中止。因此需要自己處理。雖然有些系統(tǒng)提供SA_RESTART,但可移植性的方法更好。如下:
for( ?; ? ; ? ?)
{
? ? ? ? ? clilen=sizeof(cliaddr);
? ? ? ? ? if((connfd=accept(listenfd,(SA*)&cliaddr,&clilen))<0){
? ? ? ? ? ? ? if(errno==EINTR)
? ? ? ? ? ? ? continue;
? else
? ? err_sys("accept error");
}
注意:有一個函數(shù)不能重啟:connect.必須調(diào)用select來等待連接完成。