tcp客户/服务器回射程序之二-----处理SIGCHILD信号
来源:互联网 发布:征途单机版数据库修改 编辑:程序博客网 时间:2024/05/17 05:17
tcp客户/服务器回射程序之二-----处理SIGCHLD信号
先说一下关于信号的基本知识:
信号(signal)就是通知某个进程发生了某个事件,有时也称为软件中断。信号通常是异步发生的,也就是说进程预先不知道信号准确发生的时间。
信号可以由一个进程发给另一个进程(或自身),也可以由内核发给某个进程。SIGCHILD信号就是由内核在任何一个进程终止时发给它的父进程的一个信号。
每个信号都有一个与之关联的处置(disposition),也称为行为(action).我们通过调用sigaction函数来设定一个信号的处置,并有3种选择。
1).可以提供一个函数,它将在特定信号发生的任何时刻被调用。这样的函数称为信号处理函数,这种行为称为捕获信号。有两个信号不能被捕获,它们是SIGKILL和SIGSTOP.信号处理函数由信号值这个单一的参数来调用,且没有返回值。
2).可以把某个信号的处置设定为SIG_IGN来忽略它。SIG_KILL和SIG_STOP这两个信号不能被忽略。
3).可以把某个信号的处置设定为SIG_DFL来启用它的缺省处置。缺省处置通常是收到信号后终止进程,其中某些信号还在当前工作目录产生一个进程的核心映像。另有个别信号的缺省处置是忽略。
僵死进程:
设置僵死状态的目的是维护子进程的信息,以便父进程在以后某个时候获取。这些信息包括子进程的进程id、终止状态以及资源利用信息。如果一个进程终止,而该进程有子进程处于僵死状态,那么它的所有僵死子进程的父进程id被重置为1(init进程)。继承这些子进程的init进程将清理它们。
处理僵死进程:僵死进程占用内核中的空间,最终可能导致我们耗尽进程资源。使用wait或者waitpid来处理僵死进程。但是使用wait并不足以防止出现僵死进程。因为unix的信号是不排队的,若几个SIG_CHILD信号同时传递,则信号处理函数执行的次数不一定。正确的解决办法是调用waitpid而不是wait。我们在一个循环内调用waitpid,以获取所有终止子进程的状态。我们必须指定WNOHANG选项,它告知waitpid在有尚未终止的子进程在运行时不阻塞。
总结:在网络编程中可能遇到的3种情况:
1).当fork子进程时,必须捕获SIG_CHLD信号。
2).当捕获信号时,必须处理被中断的系统调用。
3).SIG_CHLD的信号处理函数必须正确编写,应使用waitpid函数以免留下僵死进程。
改进后的代码为:
客户端程序:
#include <sys/socket.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <netinet/in.h>#include <errno.h>#include <sys/types.h>#include "readline.c"#define MAXLINE 500void str_cli(FILE*, int);int main(char argc, char ** argv) {int i,connfd[5];struct sockaddr_in servaddr;if(argc != 2)perror("usage:tcpcli<IPaddress>");for(i=0; i<5; ++i) {if((connfd[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0)perror("socket error");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(9999);inet_pton(AF_INET, argv[1], &servaddr.sin_addr.s_addr);if((connect(connfd[i], (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0)perror("connect error");}str_cli(stdin, connfd[0]);exit(0);}void str_cli(FILE* fp, int connfd) {char sendline[MAXLINE], recvline[MAXLINE];//printf("str_cli has been used.\n");while((fgets(sendline, MAXLINE, fp)) != NULL) {//printf("ok\n");write(connfd, sendline, strlen(sendline));//printf("oo=%s\n", sendline);if((readline(connfd, recvline, MAXLINE)) == 0) {//printf("ooo\n");perror("str_cli:server terminated prematurely");}//printf("jjjjj\n");fputs(recvline, stdout);}}
服务器程序:
#include <sys/socket.h>#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <netinet/in.h>#include <sys/wait.h>//#include "unp.h"void str_echo(int);void sig_chld(int);int main(char argc, char ** argv) {int listenfd, connfd;pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)perror("socket error");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(9999);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);if((bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0)perror("bind error");if(listen(listenfd, 5) < 0)perror("listen error");signal(SIGCHLD, sig_chld);printf("listenning....\n");for(;;) {//printf("....\n");clilen = sizeof(cliaddr);//printf("o\n");//connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);if((connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen)) < 0) {if(errno == EINTR) continue;elseperror("accept error");}//printf("ooo\n");if((childpid = fork()) == 0) {close(listenfd);str_echo(connfd);//printf("done.\n");exit(0);}close(connfd);}exit(0);}void sig_chld(int signo) {pid_t pid;int stat;//printf("signal ...\n");while((pid=waitpid(-1, &stat, WNOHANG)) > 0)printf("child %d terminated.\n", pid);return;}void str_echo(int connfd) {int n;char buff[500];printf("str_echo has been used.\n");again:while((n = read(connfd, buff, 500)) > 0) { //printf("writing.....\n");write(connfd, buff, n);}//printf("here..\n");if(n < 0 && errno == EINTR)goto again;else if(n < 0)perror("str_echo: read error");}
- tcp客户/服务器回射程序之二-----处理SIGCHILD信号
- tcp客户/服务器回射程序之三-----数据格式
- tcp客户/服务器回射程序之四-----select函数的使用
- tcp客户/服务器回射程序之五-----用shutdown函数解决在批量方式下所引起的问题
- UNIX网络编程之第二步之嚼烂基本TCP套接字编程(以简单的TCP客户/服务器回射程序为例)
- TCP 回射程序(处理子进程的SIGCHLD信号)
- 回射程序(服务器)——客户接收一行数据
- TCP回射程序
- TCP回射程序
- tcp回射程序
- TCP回射程序
- TCP 回射程序
- 回射程序3(服务器)——客户服务器不定长接收数据
- TCP网络编程之echo回射程序
- 信号: SIGCHILD
- 回射程序3(客户端)——客户服务器不定长接收数据
- 用select实现TCP回射程序(服务器及客户端)
- TCP 回射程序(同步处理僵死进程的方式)
- 分享:写了一个 java 调用 C语言 开发的动态库的范例
- 发动机疯狂
- 张向荣 日语 视频 教程
- conference,workshop,symposium,congress 之间的区别
- cocos2dx一个场景添加多个层
- tcp客户/服务器回射程序之二-----处理SIGCHILD信号
- sql语句-sql学习笔记3
- 驴生态度,很值得我们学习
- Cocos2d-x 进度加载
- 贪财的富翁
- Linux终端中的各种指令
- SQLite教程
- HDU 3746利用KMP找循环节
- muduo网络库学习之ThreadLocal<T> 类、ThreadLocalSingleton<T>类封装知识点