您的位置:首页 > 其它

每天一小步——自写服务器与信号处理僵尸子进程

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系统上都可用。

#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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐