zoukankan      html  css  js  c++  java
  • [第二版]多线程的发送与接收

    三个基本问题

    1. 服务器请求处理完毕, 处理僵尸进程
    2. 慢系统调用被SIGCHLD信号中断
    3. 多个SIGCHLD同时到达的情况

    wait和waitpid

    子进程终止时会产生SIGCHLD信号并发送给父进程
    父进程可以捕获处理该信号也可以不捕获
    SIGCHLD只是个数值信号, 并不包含结束子进程的pid, wait和waitpid需要通过遍历子进程来判断是哪个子进程结束.
    书上关于waitpid与wait两个版本主要是两个方面的不同:
    a. wait没有nowait选项, 而waitpid有nowait选项(WNOHANG)
    b. waitpid版本加了个while循环. 如果多个SIGCHLD同时到达, wait用while请求也会处理完所有僵死进程, 但如果还有子进程未结束, 由于wait没有nowait选项, 所以会等待所有子进程结束再返回(在wait时无法接入新的客户端). 而waitpid用while循环, 由于参数-1和nowait选项, 处理完所有僵死进程后就立即返回.

    accept被中断

    经过测试在现在linux系统上, accept是可重入函数且signal函数已经自带重入属性, 如果要模拟被SIGCHLD中断可以自己写一个信号处理函数

    Sigfunc *Signal(int signo,Sigfunc *func){
    /* test the different between system's signal and user's signal function */
      struct sigaction act,oact;
      act.sa_handler=func;
      sigemptyset(&act.sa_mask);
      act.sa_flags=0;
      if(sigaction(signo,&act,&oact) <0)
          err_quit("sigaction error");
      return(oact.sa_handler);
    }
    

    client.c

    #include "unp.h"
     
    void str_cli(FILE *fp,int sockfd);
    int main(int argc,char *argv[]){
        int sockfd[5],i;
        struct sockaddr_in servaddr;
     
        if(argc != 2)
            err_quit("usage: client <ip address>");
     
        for(i=0;i<5;i++){
            sockfd[i]=Socket(AF_INET,SOCK_STREAM,0);
            bzero(&servaddr,sizeof(servaddr));
            servaddr.sin_family=AF_INET;
            servaddr.sin_port=htons(13);
            inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
     
            Connect(sockfd[i],(struct sockaddr *)&servaddr,sizeof(servaddr)); 
        }
     
        str_cli(stdin,sockfd[0]);
     
        exit(0);
    }
     
    void str_cli(FILE *fp,int sockfd){
        char sendline[MAXLINE],recvline[MAXLINE];
        int n;
     
        while(Fgets(sendline,MAXLINE,fp) != NULL){
            writen(sockfd,sendline,strlen(sendline));
            if((n=read(sockfd,recvline,MAXLINE)) < 0)
                err_quit("str_cli: server terminated permaturely");
            recvline[n]=0;
            Fputs(recvline,stdout);
        }
    }
    

    serv.c

    #include "unp.h"
     
    void str_echo(int sockfd);
    void sig_chld(int signo);
    int main(int argc, char *argv[]){
        int listenfd,connfd;
        pid_t childpid;
        socklen_t len;
        struct sockaddr_in servaddr,cliaddr;
     
        Signal(SIGCHLD,sig_chld);
        listenfd=Socket(AF_INET,SOCK_STREAM,0);
     
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family=AF_INET;
        servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        servaddr.sin_port=htons(13);
     
        Bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
     
        Listen(listenfd,10);
     
        for(;;){
            len=sizeof(cliaddr); 
    
            //如果系统signal函数打开重入选项, 此处可用自定义的Accept
            if((connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&len)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    err_quit("accept error");
            }
     
            if((childpid=Fork())==0){
                Close(listenfd);
                str_echo(connfd);
                exit(0);
            }
            Close(connfd);
        }
    }
     
    void str_echo(int sockfd){
        ssize_t n;
        char buf[MAXLINE];
     
    again:
        while((n=read(sockfd,buf,MAXLINE)) >0)
            writen(sockfd,buf,n);
        if(n<0 && errno==EINTR)
            goto again;
        else if(n < 0)
            err_quit("str_echo read error");
    }
     
    void sig_chld(int signo){
        pid_t pid;
        int stat;
     
        while((pid=waitpid(-1,&stat,WNOHANG)) > 0)
            printf("child %d terminated
    ",pid);
        return;
    }
    
  • 相关阅读:
    Vue 下拉刷新及无限加载组件
    VUE常用问题hack修改
    CSS滤镜让图片模糊(毛玻璃效果)实例页面
    滑动删除
    拖动选择单元格并合并方法
    Windows7上开启ftp服务器功能
    js 向上滚屏
    理解Clip Path
    图标制作
    transition实现图片轮播
  • 原文地址:https://www.cnblogs.com/cfans1993/p/5883371.html
Copyright © 2011-2022 走看看