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

学习中写了一个简单的小服务器程序,可以用来上传备份文件。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);
                }
        }
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值