9.僵尸进程的处理
来源:互联网 发布:软件微电子 综合信息 编辑:程序博客网 时间:2024/05/17 09:34
TCP是一个流协议
TCP是基于字节流传输的,只维护发送出去多少,确认了多少,没有维护消息与消息之间的边界,因而导致粘包问题.
粘包的解决方法是在应用层维护消息边界.
僵尸进程与SIGCHLD信号
signal(SIGCHLD,SIG_IGN);/// 忽略SIGCHLD信号
signal(SIGCHLD,handle_sigchld);
5个客户端一起向服务器发送连接请求
这是客户端程序,服务器程序,没有发生变换
/// echolic.c#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#define ERR_EXIT(m) \do{ \perror(m); \exit(EXIT_FAILURE); \}while(0)ssize_t readn(int fd,void *buf,size_t count){size_t nleft = count ; // 未读取的数据ssize_t nread;// 已读取的数据char *bufp= (char*)buf;while(nleft > 0){if( (nread = read(fd,bufp,nleft)) < 0){if( errno == EINTR) nread = 0;// 继续读取数据elsereturn -1;}else if( nread == 0) // 对方关闭或已经读到eofbreak;bufp +=nread;nleft -= nread;}return count-nleft;}ssize_t writen(int fd,const void *buf,size_t count){size_t nleft=count; // 未读取的ssize_t nwritten; // 已读取的 char *bufp = (char*)buf; while(nleft > 0) { if((nwritten = write(fd,bufp,nleft)) < 0) { if( errno == EINTR) continue; else return -1; } else if( nwritten == 0) continue; bufp += nwritten; nleft -= nwritten; } return count;}/// recv()只能读取套接字,而不能读取一般文件描述符ssize_t recv_peek(int sockfd, void *buf, size_t len){while(1){int ret = recv(sockfd,buf,len,MSG_PEEK);//MSG_PEEK接收缓冲区的数据,但是并没有清除if( ret == -1 && errno == EINTR)continue;return ret;}}// 读到'\n' 就返回,加上'\n'一行最多为maxline个字符ssize_t readline(int sockfd, void *buf, size_t maxline){int ret;int nread;char *bufp =(char *) buf;int nleft = maxline;//int count=0;while(1){// recv_peek读取缓冲区的字符个数,并放入到bufp缓存里面ret = recv_peek(sockfd,bufp,nleft);if(ret < 0)return ret;// 表示失败else if(ret == 0)return ret; // 表示对方关闭连接了nread = ret;// 判断接收到字符是否有'\n'int i;for(i=0; i<nread; ++i){if(bufp[i] == '\n'){ // readn读取数据,这部分缓冲会被清空的ret = readn(sockfd,bufp,i+1);if(ret != (i+1))exit(EXIT_FAILURE);return ret; //+ count;}}if( nread > nleft)exit(EXIT_FAILURE);nleft -= nread;ret = readn(sockfd,bufp,nread);if(ret != nread)exit(EXIT_FAILURE);bufp += nread;// 下一次指针偏移//count += nread;}return -1;}void echo_cli(int sock){char sendbuf[1024] = {0};char recvbuf[1024] = {0};while( fgets(sendbuf,sizeof(sendbuf),stdin) != NULL) {writen(sock,sendbuf,strlen(sendbuf));// 需要的注意的的时sizeof(sendbuf)和strlen(recvbuf)不一样的,容易出现混淆int ret = readline(sock,recvbuf,1024);///最后一个参数为缓冲区的最大值if( ret == -1 )ERR_EXIT("readline");else if(ret == 0){printf("client close \n");break;}fputs(recvbuf,stdout);memset(recvbuf,0,sizeof(recvbuf));memset(sendbuf,0,sizeof(sendbuf));} close(sock); }int main(){int sock[5];int i;for( i=0;i<5;++i){if( (sock[i] = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)ERR_EXIT("sock err");struct sockaddr_in servaddr;memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if( connect(sock[i],(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)ERR_EXIT("connect error");struct sockaddr_in localaddr;socklen_t addrlen = sizeof(localaddr);if(getsockname(sock[i],(struct sockaddr*)&localaddr,&addrlen) < 0)ERR_EXIT("getsockname err");printf("ip=%s ,port = %d \n",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.sin_port));}// 为了方便,只使用一个套接字通信echo_cli(sock[0]); return 0;}
没有处理子进程,结果出现了好多5个僵尸进程.
最简单的办法就是父进程直接忽略SIGCHLD信号,即:
signal(SIGCHLD,SIG_IGN); // 忽略SIGCHLD信号
忽略SIGCHLD信号,这常用于并发服务器的性能的一个技巧因为并发服务器常常fork很多子进程,子进程终结之后需要服务器进程去wait清理资源。如果将此信号的处理方式设为忽略,可让内核把僵尸子进程转交给init进程去处理,省去了大量僵尸进程占用系统资源。
如果我们想要捕获SIGCHLD信号的话,在信号处理函数中不能只调用一次wait/waitpid 函数,因为客户端退出发出FIN段的时机是不一定的,如果都能按一定时间顺序发送给5个服务器子进程,即子进程发生SIGCHLD信号给父进程的时间有前后之分,那handler函数会被调用多次,则是允许的,也不会产生僵尸进程;但当多个SIGCHLD信号同时到达,因为不可靠信号不能排队导致信号只保存一个,即其余信号会丢失,则产生的僵尸进程个数是不确定的,因为按前面所说取决于5个SIGCHLD信号到达的次序。解决的办法很简单,只要在handler函数中while 循环一下就ok 了,即使5个信号同时到达,只要接收到一个SIGCHLD信号,则5个子进程都会被清理掉:
void handler(int sig){ /* wait(NULL); //只能等待第一个退出的子进程 */ while (waitpid(-1, NULL, WNOHANG) > 0) ;}
signal(SIGCHLD, handler);
前几个程序,都没有注意到僵尸进程,平时的记得处理僵尸进程.
0 0
- 9.僵尸进程的处理
- 僵尸进程的处理
- 【UNIX】僵尸进程的处理
- Linux 僵尸进程的处理
- linux僵尸进程的处理
- Linux下僵尸进程的处理
- Hadoop 类僵尸进程的定期处理
- 僵尸进程的产生与处理
- linux下的僵尸进程处理办法
- 僵尸进程的产生与处理
- 处理僵尸进程导致的后遗症
- linux系统处理僵尸进程的方法
- Linux下僵尸进程的处理
- Linux的僵尸进程处理1
- Linux的僵尸进程处理2
- 【study】socket结合僵尸进程的处理
- multiprocessing对僵尸进程的处理
- 僵尸进程以及如何处理僵尸进程
- 未能加载文件或程序集“System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50
- linux下jdk的安装与配置
- Objective-C之成魔之路【2-Objective-C 编程】
- hdu1072 Nightmare 广搜
- UML用例图之泛化(generalization)、扩展(extend)和包含(include)关系--UML一波流系列讲解
- 9.僵尸进程的处理
- 最近想到的
- 第十周输出完数
- [解决方法]The connection to adb is down, and a severe error has occured.
- HDU 1720 A+B Coming
- 性能分析工具-JProfiler
- 网络流
- Android开发环境搭建(Eclipse_Windows下)
- lua学习