不得不说,看网络编程这本书比之前学的要轻松多了.unp.h这个辅助类让我轻松太多了。
先来一个简单回射的例子
服务端代码如下
#include#include "unp.h" //连接客户端成功后的逻辑处理。只是单纯的回射 void recv_str(int clifd){ char readbuff[MAXLINE]; int n; for(;;){ n=Readline(clifd,readbuff,sizeof(readbuff)); if(n<0){ if(errno==EINTR) continue; else{ err_sys("read err"); } } if(n==0){ printf("read n=0"); break; } Writen(clifd,readbuff,n); } } //信号处理函数 子进程关闭时触发.可以防止主进程阻塞的情况下导致僵死子进程 void sig_chld(int signo){ pid_t pid; int stat; //pid=wait(&stat); //测试wait同样可以解决多个子进程不僵死 for(;;){ pid=waitpid(-1,&stat,WNOHANG); if(pid<=0) break; } } int main() { int clifd,serfd; int pid; struct sockaddr_in serAddr; bzero(&serAddr,sizeof(serAddr)); serAddr.sin_family=AF_INET; serAddr.sin_port=htons(SERV_PORT); serAddr.sin_addr.s_addr=htonl(INADDR_ANY); serfd=Socket(AF_INET,SOCK_STREAM,0); Bind(serfd,(SA*)&serAddr,sizeof(serAddr)); Listen(serfd,LISTENQ); Signal(SIGCHLD,sig_chld); for(;;){ clifd=Accept(serfd,(SA*)NULL,NULL); if(clifd<0){ if(errno==EINTR) continue; else err_sys("accept err"); } if((pid=fork())==0){ Close(serfd); recv_str(clifd); exit(0); } Close(clifd); } }
客户端代码如下
#include#include "unp.h" //链接服务端之后的逻辑处理,从标准输入接收了发送给服务器 void send_str(int clifd,FILE* infd){ char buff[MAXLINE]; char recvbuff[MAXLINE]; while(Fgets(buff,sizeof(buff),infd)!=NULL){ Writen(clifd,buff,strlen(buff)); if(Readline(clifd,recvbuff,sizeof(recvbuff))==0) err_quit("read fd close"); Fputs(recvbuff,stdout); } } int main(int argc,char** argv) { if(argc!=2) err_quit("argc err"); char* addr=argv[1]; int i,sockfd[10]; for(i=0;i<10;i++){ sockfd[i]=Socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in serAddr; bzero(&serAddr,sizeof(serAddr)); serAddr.sin_family=AF_INET; serAddr.sin_port=htons(SERV_PORT); Inet_pton(AF_INET,addr,&serAddr.sin_addr); Connect(sockfd[i],(SA*)&serAddr,sizeof(serAddr)); } send_str(sockfd[0],stdin); exit(0); }
这里主要是说了一个僵死子进程的问题。
服务端每接受到一个请求后开了一个子进程去处理客户端的对应请求。
而当客户端关闭退出时。服务端子进程读取到了0.然后子进程退出。在子进程终止时给父进程发送了一个SIGCHLD信号。而父进程在Accept中。此时正在阻塞中。
如果父进程没有处理该信号。子进程就进入了僵死状态。
在信号处理函数的wait的这里。我测试了wait和waitpid的效果并没有出入。
书本上面的意思是信号触发多次而设定的处理函数并不一定会触发多次。会导致有若干子进程依然是僵死状态。
但是实际测试效果似乎是每个信号都会触发。为了稳妥起见。我还是写了waitpid来处理。