每天一小步——自写服务器与信号处理僵尸子进程
2013-10-13 20:54
302 查看
学习中写了一个简单的小服务器程序,可以用来上传备份文件。tcp/ip协议的三次握手是不变的,我们所要做的就是在这个框架上搭建自己想要的功能实现扩展,并优化程序!
虽然是一个小服务器程序,但是也是会遇到不少问题,但最后还是努力解决了!如文件名与文件内容出现交错,最后用传完文件名后,采用一个确认,然后再传送文件内容来解决了内容!
为了实现服务多用户的功能,采用了fork函数。但是采用fork后必然会出现僵尸子进程,处理好僵尸进程也为难了我一会!刚开始采用了wait和waitpid函数!
wait函数会阻塞住进程,影响了服务多用户的功能。子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可!但是我的程序在采用这个方法时遇到了一个至今没法解决的问题,老是无限循环一个错误!有兴趣的同学可以帮我实现!
waitpid函数虽然是封装了wait函数,但是比wait灵活许多,但是我用了 waitpid(0,&status,WNOHANG|WUNTRACED);时总是会残留一个僵尸进程,无法全部处理完全,有兴趣的高手,可以帮一下小弟!
由于UNIX的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理
掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的,但这是一个特例。这个方法是方法我没出现错误,但此方法对于Linux可用,但不保证在其它UNIX系统上都可用。
虽然是一个小服务器程序,但是也是会遇到不少问题,但最后还是努力解决了!如文件名与文件内容出现交错,最后用传完文件名后,采用一个确认,然后再传送文件内容来解决了内容!
为了实现服务多用户的功能,采用了fork函数。但是采用fork后必然会出现僵尸子进程,处理好僵尸进程也为难了我一会!刚开始采用了wait和waitpid函数!
wait函数会阻塞住进程,影响了服务多用户的功能。子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可!但是我的程序在采用这个方法时遇到了一个至今没法解决的问题,老是无限循环一个错误!有兴趣的同学可以帮我实现!
waitpid函数虽然是封装了wait函数,但是比wait灵活许多,但是我用了 waitpid(0,&status,WNOHANG|WUNTRACED);时总是会残留一个僵尸进程,无法全部处理完全,有兴趣的高手,可以帮一下小弟!
由于UNIX的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理
掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的,但这是一个特例。这个方法是方法我没出现错误,但此方法对于Linux可用,但不保证在其它UNIX系统上都可用。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h> #include <sys/wait.h> #define MAXLINE 128 #define SERV_PORT 8000 void pid_action(int pid,int listenfd,int connfd,struct sockaddr_in *cliaddr) { int i,n,ret=0; int dest; char buf[MAXLINE],ibuf[MAXLINE]; char str[INET_ADDRSTRLEN]; char *copy=NULL; close(listenfd); bzero(buf,MAXLINE); n=read(connfd,buf,MAXLINE); dest=open(buf,O_RDWR|O_CREAT|O_TRUNC,0666); if(dest<0){ perror("open"); exit(1); } write(connfd,"1",1);/*transmission on demand*/ bzero(buf,MAXLINE); /*receive the file content*/ while((n=read(connfd,buf,MAXLINE))>0){ copy=buf; while(n>0){ ret=write(dest,copy,n); n=n-ret; copy=copy+ret; } write(dest,buf,n); bzero(buf,MAXLINE); } printf("received from %s at PORT %d\n",inet_ntop(AF_INET,&cliaddr->sin_addr,str,sizeof(str)),ntohs(cliaddr->sin_port)); close(dest); close(connfd); } int main(void) { struct sockaddr_in servaddr,cliaddr; struct sigaction newact,oldact; socklen_t cliaddr_len; int listenfd,connfd,status; pid_t pid; /*sigaction configuration*/ newact.sa_handler=SIG_IGN; sigemptyset(&newact.sa_mask); newact.sa_flags=0; sigaction(SIGCHLD,&newact,&oldact); listenfd=socket(AF_INET,SOCK_STREAM,0); /*net configuration*/ bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(SERV_PORT); bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); listen(listenfd,20); printf("Accepting connections ..\n"); while(1){ cliaddr_len=sizeof(cliaddr); connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); if((pid=fork())<0){ perror("fork"); exit(1); } if(pid==0){ pid_action(pid,listenfd,connfd,&cliaddr); exit(1); } if(pid>0){ close(connfd); } } }
相关文章推荐
- 36-多进程并发服务器(僵尸进程与信号处理)
- 子进程调用execv函数后,对信号的处理不保留
- 子进程中调用system命令执行openssl后,程序退出了,原因是SIGCHLD信号的处理
- 【学习笔记】启动Nginx、查看nginx进程、查看nginx服务主进程的方式、Nginx服务可接受的信号、nginx帮助命令、Nginx平滑重启、Nginx服务器的升级
- linux信号处理、killall、SIGALRM、sigaction函数和结构体、向进程发送信号
- 用select单个进程处理并发服务器
- NGINX单进程服务器主处理流程
- Linux系统多线程讲解与实现,包含服务器实现、信号处理
- Linux并发回射服务器(二):处理僵死进程
- 子进程信号处理及wait waitpid区别
- 搭建一个服务器框架,进程间利用管道通信,线程处理数据
- fork exec对子进程继承父进程信号处理机制的影响--APUE
- 你想建设一个能承受500万PV/每天的网站吗?服务器每秒要处理多少个请求才能应对?
- 进程对信号的处理
- 《unix网络编程》(10)wait/waitpid处理僵死进程(SIGCHLD信号)
- 回射客户端服务器中僵尸进程的处理( the solution of zombie process in the echo client && server )
- Unix高级编程:线程的同步之信号量、进程通信之信号量集、system函数、简单web服务器代码
- fork exec对子进程继承父进程信号处理机制的影响--APUE
- uc笔记08---信号处理,signal,子进程的信号处理
- SIGHUP信号的默认处理是终止收到该信号的进程