当前位置: 首页 > news >正文

网站开发的标准合肥网站建设方案书

网站开发的标准,合肥网站建设方案书,做网站在哪里租服务器,求职招聘网站排名前十名在上一讲中#xff0c;我们使用fork函数得到了一个简单的并发服务器。然而#xff0c;这样的程序有一个问题#xff0c;就是当子进程终止时#xff0c;会向父进程发送一个SIGCHLD信号#xff0c;父进程默认忽略#xff0c;导致子进程变成一个僵尸进程。僵尸进程一定要处理…在上一讲中我们使用fork函数得到了一个简单的并发服务器。然而这样的程序有一个问题就是当子进程终止时会向父进程发送一个SIGCHLD信号父进程默认忽略导致子进程变成一个僵尸进程。僵尸进程一定要处理因为僵尸进程占用内核中的空间耗费进程资源。这里通过signal函数处理信号。 1、信号是啥 信号signal就是告知某个进程发生了某个事件的通知有时也叫软件中断software interrupt。信号通常是异步发生的也就是说进程预先不知道信号的准确发生时间。 信号可以看做进程间的一种通信我的理解不但可以由一个进程发送给另一个进程还可以由自己发送给自己甚至内核发送给进程。上一讲中的SIGCHLD就是内核在任何一个进程终止时发送给父进程的一个信号。 对于信号都有一个信号发生时响应的动作也叫行为action。可以通过调用sigcation函数来设置对信号的处理方法。通常有三种方式处理信号 1调用信号处理函数处理。提供一个函数只要有信号发生就调用这个函数称为信号处理函数signal handler这种行为叫做捕获catching信号。不过SIGKILL和SIGSTOP不能捕获。信号处理函数的原型如下 void handler(int signo); 没有返回值只有一个信号值这个参数。 2忽略它。可以把某个信号的处理设置为SIG_IGN来忽略。不过SIG_KILL和SIG_STOP不能忽略 3默认处理。还可以把某个信号的处理设置成SIG_DFL来启用默认处理 可以通过调用sigaction函数建立信号处置的POSIX方法。不过sigaction优点复杂因为该函数的参数之一是需要自己分配并填写的结构。可以通过调用signal函数来简化处理。下面是signal函数的定义 sigfunc* signal(int signo,sigfunc *func) { struct sigaction act,oact; act.sa_handlerfunc; sigemptyset(act.sa_mask); act.sa_flags0; if(signoSIGALRM) { #ifdef SA_INTERRUPT act.sa_flags|SA_INTERRUPT; #endif }else{ #ifdef SA_RESTART //act.sa_flags|SA_RESTART; #endif } if(sigaction(signo,act,oact)0) return(SIG_ERR); return(oact.sa_handler); } 函数有两个参数第一个是信号名第二个是函数指针或SIG_IGN、SIG_DFL。首先我们通过下面的定义简化signal原型定义 typedef void sigfunc(int); 这个复杂的定义是这样的 void (*signal (int signo,void (*func)(int)))(int); 然后构造sigaction结构将sa_handler成员设置成传进来的参数func 7到16行设置SA_RESTART标志。这个标志会在后面介绍这里首先把设置SA_START标志注释掉。 最后调用sigaction函数设置对信号的处理方法。 2、处理SIGCHLD信号 既然通过调用sigaction函数可以设置对信号的处理那么对于这里的具体问题怎么做呢这里要处理僵尸子进程也就是SIGCHLD信号那么signal的第一个参数有了就是SIGCHLD缺少的是第二个参数即信号处理函数。 下面是我们的信号处理函数 void sig_chld(int signo) { pid_t pid; int stat; pidwait(stat); printf(child %d terminated.\n,pid); return; } 函数简单的调用wait函数来处理终止的子进程。下面是wait函数的定义它包含在sys/wait.h头文件中 pid_t wait(int *statloc); 函数返回两个值已终止的进程的进程ID以及通过statloc指针返回的子进程终止状态一个整数。如果调用wait的进程没有已终止的子进程不过有一个或多个子进程在运行那么函数将阻塞到现有子进程中第一个终止为止。 现在有了信号处理函数接下来就是如何调用在服务器程序中的listen调用之后调用signal函数 signal(SIGCHLD,sig_chld); 下面就是完整的服务器程序 #include sys/wait.h #include sys/socket.h #include errno.h #include string.h #include strings.h #include netinet/in.h #include arpa/inet.h #include stdio.h #include time.h #include unistd.h #define MAXLINE 1024 typedef void sigfunc(int); void str_echo(int sockfd); void sig_chld(int signo); sigfunc *signal(int signo,sigfunc *func); int main(int argc,char *argv[]) { int listenfd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; if((listenfdsocket(AF_INET,SOCK_STREAM,0))0) { printf(socket error\n); return 0; } bzero(servaddr,sizeof(servaddr)); servaddr.sin_familyAF_INET; servaddr.sin_porthtons(5000); servaddr.sin_addr.s_addrhtonl(INADDR_ANY); if(bind(listenfd,(struct sockaddr*)servaddr,sizeof(servaddr))0) { printf(bind error\n); return 0; } if(listen(listenfd,5)0) { printf(listen error\n); return 0; } signal(SIGCHLD,sig_chld); int connfd; socklen_t len; struct sockaddr_in cliaddr; pid_t pid; for(;;) { lensizeof(cliaddr); if((connfdaccept(listenfd,(struct sockaddr*)cliaddr,len))0) { if(errnoEINTR) { printf(Interrupted system call but continue\n); continue; } else { printf(accept error\n); return 0; } } if((pidfork())0) { if(close(listenfd)0) { printf(close listenfd error\n); return 0; } printf([PID]%ld Receive a connection from:%s.%d\n,(long)getpid(),inet_ntop(AF_INET,cliaddr.sin_addr,buff,sizeof(buff)),ntohs(cliaddr.sin_port)); str_echo(connfd); if(close(connfd)0) { printf(close child connfd error\n); return 0; } return 0; } if(close(connfd)0) { printf(close parent connfd error\n); return 0; } } }   void str_echo(int sockfd) { ssize_t n; char buf[MAXLINE]; again: while((nread(sockfd,buf,MAXLINE))0) write(sockfd,buf,n); if(n0errnoEINTR) goto again; else if(n0) { printf(read error\n); return; } } void sig_chld(int signo) { pid_t pid; int stat; pidwait(stat); printf(child %d terminated.\n,pid); return; } sigfunc* signal(int signo,sigfunc *func) { struct sigaction act,oact; act.sa_handlerfunc; sigemptyset(act.sa_mask); act.sa_flags0; if(signoSIGALRM) { #ifdef SA_INTERRUPT act.sa_flags|SA_INTERRUPT; #endif }else{ #ifdef SA_RESTART act.sa_flags|SA_RESTART; #endif } if(sigaction(signo,act,oact)0) return(SIG_ERR); return(oact.sa_handler); } 下面是执行过程 1启动服务器 2客户发起连接并输入 3然后客户输入CtrlC终止 4服务器 可以看到服务器端正确的终止了子进程。通过ps命令查看是否有僵尸进程 没有说明对SIGCHLD信号的处理正确。 不过这里还有个问题上面服务器父进程调用signal函数正确处理了子进程之后貌似有什么输出 Interrupted system call but continue 查看源程序可以知道问题出这里 for(;;) { lensizeof(cliaddr); if((connfdaccept(listenfd,(struct sockaddr*)cliaddr,len))0) { if(errnoEINTR) { printf(Interrupted system call but continue\n); continue; } else { printf(accept error\n); return 0; } } 是父进程accept函数中出现了EINTR这是啥 2、处理被中断的系统调用 来看看客户键入CtrlC来终止输入时发生了什么 1客户TCP发送一个FIN给服务器服务器响应以一个ACK 2收到客户的FIN导致服务器TCP递送一个EOF给子进程阻塞中的readline从而子进程终止 3子进程终止后内核向父进程发送一个SIGCHLD信号父进程阻塞于accept调用。sig_chld函数执行wait调用取到子进程的进程ID和终止状态然后printf返回 4accept函数是一个慢系统调用slow system call父进程阻塞在accept时捕获SIGCHLD信号内核就会使accept返回一个EINTR错误被中断的系统调用。 这样函数知道了出现EINTR通过continue来重新进入for循环相当于重新启动。 不过在signal函数中可以设置SA_RESTART标志可以使被中断的系统调用自动重启而不用使用continue。 这里有如下结论 1慢系统调用可能永远阻塞 2当阻塞于某个慢系统调用的一个进程捕获某个信号且响应信号处理函数返回时该系统调用可能返回EINTR错误 3当出现EINTR错误时有的系统内核自动重启被中断的系统调用有的不重启。应该对这个错误有所准备 3、还有什么 当然还有一个问题。上面介绍wait函数时说到如果一个进程中有多个子进程在执行那么wait函数将阻塞到第一个子进程终止时为止。如果有多个子进程终止而成为僵尸进程那么wait只能处理一个。也就是说信号处理函数没能完全处理僵尸进程。 真的是这样么 我们改变一下客户程序让这个客户程序与服务器建立5个连接 int main(int argc,char *argv[]) { int sockfd[5]; char recvline[MAXLINE]; if(argc!2||strcmp(argv[1],--help)0) { printf(Usage:%s IPaddress\n,argv[0]); return 0; }   int i; for(i0;i5;i) { if((sockfd[i]socket(AF_INET,SOCK_STREAM,0))0) { printf(socket error\n); return 0; } struct sockaddr_in servaddr; bzero(servaddr,sizeof(servaddr)); servaddr.sin_familyAF_INET; servaddr.sin_porthtons(5000); if(inet_pton(AF_INET,argv[1],servaddr.sin_addr)0) { printf(inet_pton error for %s\n,argv[1]); return 0; } if(connect(sockfd[i],(struct sockaddr*)servaddr,sizeof(servaddr))0) { printf(connect error\n); return 0; } } str_cli(stdin,sockfd[0]); return 0; } 这样可以建立5个连接 当客户终止时所有打开的描述符由内核自动关闭并且5个连接基本上同时终止这引发了5个FIN反过来时服务器的5个子进程基本上同时终止导致差不多同时有5个SIGCHLD信号递交给父进程 看看运行的怎么样 1打开服务器并使客户连接一共有5个其中一个输入字符后终止 2服务器终止了4个子进程 3使用ps命令查看僵尸进程 有一个进程ID是3625的子进程没有被处理。 严重的是父进程处理子进程不确定 这一次5个子进程全部被终止没有僵尸进程 这是由于客户FIN到达主机的时间不同。 解决的办法是调用waitpid函数函数定义如下 pid_t waitpid(pid_t,int *statloc,int options); pid参数指定等待的进程ID如果是-1表示第一个终止的子进程。options可以添加附加选项这里使用WNOHANG告诉内核在没有已终止子进程时不要阻塞。 下面使用waitpid函数改进sig_chld函数 void sig_chld(int signo) { pid_t pid; int stat; while((pidwaitpid(-1,stat,WNOHANG))0) printf(child %d terminated.\n,pid); return; } 结果如下 1打开服务器客户建立连接并输入 2客户终止后服务器成功终止5个子进程 3使用ps并没有发现僵尸进程 4、总结一下 1当fork子进程时必须捕获SIGCHLD信号 2当捕获信号时必须处理被中断的系统调用 3SIGCHLD的信号处理函数必须正确编写应使用waitpid函数来避免留下僵尸进程。 --------------------- 本文来自 Ezioooooo 的CSDN 博客 全文地址请点击https://blog.csdn.net/u012877472/article/details/50165083?utm_sourcecopy
http://www.pierceye.com/news/991160/

相关文章:

  • 南昌建站模板深圳全网推广效果如何
  • 做网站的好公司wordpress大前端模板下载
  • 建设网站的申请信用卡吗下载百度免费
  • 徐州企业网站设计做瑜伽网站
  • 网站开发就是ssh吗.net 网站开发书籍
  • 网站名称没有排名上海工商网查询企业章程
  • 网站建设方案报价费用明细价格免费开店的电商平台
  • 济南网络建站模板用c 做的网站怎么打开
  • 网站建设培训课程好人一生平安网站哪个好
  • seo怎么做网站的tdk网站优化的核心不包括
  • 如何做一份网站的数据分析网站营销案例
  • 中小企业网站建设公司个人微信号做网站行吗
  • 网站无法连接服务器哪些国家网站无须备案
  • 重庆做网站设计培训机构排名全国十大教育机构排名
  • 做网站建设销售网络营销推广技巧
  • 南宁网站制作定制北京网站seo服务
  • 门户网站网页设计规范willin kan 让你的wordpress飞起来
  • 建设银行广州招聘网站wordpress dz
  • 如何介绍自己做的网站东莞回收网站设计
  • 北京驾校网站建设厦门网页设计培训班
  • 网络公司给我做网站我有没有源代码版权吗我怎么做个人网站
  • 免费建站网站一站式做网站需要懂那些软件
  • 做新网站怎样提交360寻找销售团队外包
  • 重庆市建设网站wordpress 新闻模版
  • 国内网站建设推荐手工做的网站
  • 深圳罗湖做网站的公司网站建设与管理案例教程第三版课后答案
  • 有关网站招标商务标书怎么做做终端客户网站
  • c 网站做微信收款功能青岛网站建设定制
  • 贵州安顺建设主管部门网站网站全程设计技术
  • 公司宣传网站建设企业网站建设与实现的论文