UNIX操作系统为用户提供inetd daemon 进行网络服务管理。它将所有的后台应用程序置于它的管理之下,在客户端没有请求时,所有的后台应用程序都不启动,一旦客户端有特定的请求上来,它将根据/etc/services 和/etc/inetd.conf 文件描述的请求端口号和服务名调动相应的应用程序进行处理,而其它后台应用程序是不启动的。被启动的应用程序完成了特定任务后就终结自己的进程,这就减轻了系统负载,节约了系统资源,极大地提高了系统效率,是实现应用系统网络互连的一个实用工具。
inetd daemon 在开机时由/etc/rc.tcpip文件启动,一旦inetd daemon 启动即从 /etc/inetd.conf 文件中读取它的配置信息,然后在特定的套接字上监听连接请求,该文件的作用是告诉 inetd daemon 各端口号上的请求如何处理。即该服务采用何种套接字类型,是字节流还是数据报,采用什么协议(TCP/UDP),应用程序等待否,在监听套接字之前是否释放套接字,应用程序的名字、参数及路径等。
下面是守护进程实例
时间服务器:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <syslog.h> #include <signal.h> #include <time.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #define MAXFD 64 #define MAXLINE 255 //extern int daemon_proc; void daemon_init(const char *pname, int facility) { int i = 0; pid_t pid; if ((pid = fork()) != 0) //创建第一个子进程 { exit( 0); //父进程结束 } //第一个子进程继续 setsid(); //成为会话头 signal(SIGHUP, SIG_IGN); //忽略SIGHUP信号 if ((pid = fork()) != 0) { exit(0); //第一个子进程结束 } //daemon_proc = 1; //第二个子进程继续 chdir("/"); //改变工作目录 umask(0); //清除文件模式创建掩码 for (i=0; i<MAXFD; i++) { close(i); } open( "/dev/null", O_RDONLY); open( "/dev/null", O_RDWR); open( "/dev/null", O_RDWR); openlog(pname, LOG_PID, facility); //用syslogd处理错误 } int main(int argc, char **argv) { int listenfd, connfd; socklen_t addrlen, len; struct sockaddr cliaddr; struct sockaddr_in server; char buff[MAXLINE]; time_t ticks; (void)addrlen; bzero(&cliaddr, sizeof(cliaddr)); bzero(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(1234); server.sin_addr.s_addr = htonl(INADDR_ANY); daemon_init(argv[0], 0); listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { syslog(LOG_NOTICE|LOG_LOCAL0, "socket error"); return -1; } if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0) { syslog(LOG_NOTICE|LOG_LOCAL0, "bind error"); return -1; } if (listen(listenfd, 5) < 0) { return -1; } for (;;) { len = sizeof(cliaddr); connfd = accept(listenfd, &cliaddr, &len); if (connfd < 0) { syslog(LOG_NOTICE|LOG_LOCAL0, "accept error"); return -1; } ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); if (write(connfd, buff, strlen(buff)) < 0) { syslog(LOG_NOTICE|LOG_LOCAL0, "write error"); return -1; } close(connfd); } close(listenfd); return 1; }
客户端程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define PORT 1234 #define MAXSIZE 1024 int main(int argc, char **argv) { int sockfd; struct sockaddr_in serverSock; int num = 0; char buff[MAXSIZE] = {0}; struct hostent *he; if (argc != 2) { printf("Usage: %s <IP Address>\n", argv[0]); return -1; } he = gethostbyname(argv[1]); if (he == NULL) { printf("gethostbyname fails!\n"); return -1; } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { printf("Create socket fails!\n"); return -1; } bzero(&serverSock, sizeof serverSock); serverSock.sin_family = AF_INET; serverSock.sin_port = htons(PORT); serverSock.sin_addr = *((struct in_addr *)he->h_addr); if (connect(sockfd, (struct sockaddr *)&serverSock, sizeof serverSock) < 0) { printf("connect fails!\n"); return -1; } num = recv(sockfd, buff, MAXSIZE, 0); if (num < 0) { printf("recv message fails!\n"); return -1; } buff[num-1] = '\0'; printf("%s\n", buff); close(sockfd); return 1; }
编译后,运行服务器程序,用ps -axu命令就能找到刚运行的守护进程。从显示的结果中可以看到,其中tty项为?的就表示为守护进程。