天下网吧 >> 网吧天地 >> 网吧技术 >> 网吧系统 >> 正文

介绍守护进程XINETD与SOCKET程序的含义

2008-4-8赛迪网佚名
1.Xinetd提供被动式的超级服务,也就是服务程序是被使用端所启动,平时则无须存在。例如,ftp, telnetd, pop3,imap, auth等等,这些服务没有人使用时,无须启动。此外,xinetd将socket转换成stdin/stdout,因而使得网路服务程式设计大大简化,您可以只用printf及fgets便可完成处理很复杂的网路协定。 2.一个简单的服务程序 goodie #include #include #include char *cmds[]={ "help", "say", "hello", "bye", "exit", NULL }; int getcmd(char *cmd) { int n=0; while (cmds[n]!=NULL) { if (strncasecmp(cmd,cmds[n],strlen(cmds[n]))==0) return n; n++; } return -1; } void main(void) { char buf[1024]; int ok; printf("Welcome to goodie service! "); fflush(stdout); ok=0; do { while (fgets(buf,1023,stdin)==NULL); switch (getcmd(buf)) { case -1: printf("Unknown command! "); break; case 0: printf("How may I help you, sir? "); int j=0; while(cmds[j++]!=NULL)printf(” %s\t\t“,cmds[j-1]); break; case 1: printf("I will say %s",&buf[3]); break; case 2: printf("How're you doing today? "); break; case 3: printf("Si ya, mate! "); ok=1; break; case 4: printf("Go ahead! "); ok=1; break; } fflush(stdout); } while (!ok); } 3.配置文件 在/etc/services 中加入如下项 goodie 12345/tcp 服务名是 goodie 服务端口是 12345 服务类型是 TCP 在/etc/xinetd.d目录下新检服务文件 goodie 输入内容: service goodie { socket_type=stream protocal =tcp wait =no server = /{goodie dir}/goodir disable =no #初始化为开启服务监听 } 4.启动服务 先停止服务 killall xinetd 启动服务 /usr/sbin/xinetd -f /etc/xinetd.conf 5.开启终端连接 telnet localhost 12345 6.xinetd 的工作原理 通过配置xinetd,然后查看相应的套接字和进程,可以看出,xinetd是这样工作的(针对tcp服务) A.启动时读取/etc/xinetd.conf文件并为文件中指定的所有服务创建相应的套接字(流或数据报),xinetd能处理的服务的数目依赖于所创建的套接字数目。每个新创建的套接字都被加入到select调用所用到的描述符集中。 B.对每一个套接字调用bind,绑定服务端口(/etc/services中定义),端口号通过调用getservbyname获得。 C.所有套接字建立后,调用select等待它们变为可读,当tcp套接字上有数据报到来时变为可读。xinetd在大部分时间阻塞在select的调用处; D.xinetd守护进程fork,由子进程处理服务请求;子进程关闭除了要处理的套接字之外的所有描述字,子进程三次调用dup2,把套接字描述字复制到0、1、2,然后关闭原套接字;以后程序对套接字操作就是对0、1、2进行操作;子进程exec执行相应的服务器程序,并将配置文件中的参数传递。 E. 因为tcp服务器通常设置nowait标记,表示xinetd在该套接字上再次选择之前,必须等待在该套接字上服务的子进程终止。所以,父进程中的fork返回时,把子进程的进程号记录下来,这样,在子进程终止时,父进程可以用waitpid的返回值查知是那一个子进程;父进程用FD_CLR宏关闭select使用的描述字集中与这个套接字对应的位,以便不对该套接字select;当子进程终止时,父进程收到一个SIGCHLD信号,父进程的信号处理程序得到终止子进程的进程号,父进程通过打开描述字集中对应的位恢复对该套接字的select。 7.重新实现的XINETD超级守护程序 A.程序利用上面的原理在思路上重新实现了超级守护进程。 B.程序在一些地方只是概念性的代码,完全实现还有待补充。 C.程序能演示XINETD 的功能,但是在注释有BUG 和NOTE 的地方还需改进 D.这是一个总结性的资料,参考了“利用INETD实现UDP守护进程“和“www.douzhe.com“上的文章。 #include #include #include #include #include #include #include #include #include #include //为每一个服务分配一个包含socket,及路径的信息结构。 struct param{ int sock; //BIND的套接字 char path[256]; //服务程序 路径 pid_t pid ; //CHILD 进程ID struct param *next; } fd_set readfds; struct param *phead,*ptail,*p; /* 响应子进程结束的信号函数; 如果服务中wait=yes; 则bind socket 必须等到子进程结束才能监听下一个请求 */ void signal_handler(int signum) { pid_t pid; pid= waitpid(-1,NULL,WUNTRACED); for(p=phead;p!=NULL;p=p->next) if(p->pid==pid) { //FD_SET(p->sock,&readfds); printf("child exit pid= %d\n",pid); break; } signal(SIGCHLD,signal_handler); } int main(int argc,char *argv[]) { int sock,ss; int nret; int sock_len; struct sockaddr_in addr; struct sockaddr_in addr_clt; FILE *file; fd_set testfds; sock_len=sizeof(addr); p=(struct param*)malloc(sizeof(struct param)); ptail=p; phead=NULL; p->sock=socket(AF_INET,SOCK_STREAM,0); // file=fopen("/etc/xinetd.conf","r"); // while(1)//省略从"/etc/xinetd.conf"文件中读每一个服务并启动 { addr.sin_family=AF_INET; addr.sin_addr.s_addr=htonl(INADDR_ANY); addr.sin_port=htons(9734);//从“/etc/service”文件中读服务的端口号 getservbyname; bind(p->sock,(struct sockaddr *)&addr,sock_len); listen(p->sock,5); FD_ZERO(&readfds); FD_SET(p->sock,&readfds); strcpy(p->path,"~/socket/");//省略从"/etc/xinetd.conf"文件中读每一个服务的路径 if(phead==NULL) { p->next=NULL; phead=ptail=p; printf("phead==null\n"); } else { ptail->next=p; ptail=p; ptail->next=NULL; } printf("path=%s,sock=%d\n",phead->path,phead->sock); } while(1) { int fd; int clientfd; int n; pid_t pid; int flag=0; testfds=readfds; nret=select(FD_SETSIZE,&testfds,NULL,NULL,NULL); //if(nret<0){perror(strerror(errno));exit(5);}// bug 1:如果子进程END,会显示“interrupt system call”错误。 for(fd=0;fdnext) if(p->sock==fd) { printf("child runing \n"); //execve(); //note 1:未调用SERVER PATH(FILE) } sleep(1); exit(5); default:// >0 close(clientfd); if(flag) //note 2: 由service name 的wait 标志决定 FD_CLR(fd,&readfds); for(p=phead;p!=NULL;p=p->next) if(p->sock==fd) { p->pid=pid; printf("sock:%d, child pid=%d\n",p->sock,p->pid); } signal(SIGCHLD,signal_handler);//note 3:放到开始,还是这儿呢? break; } } } }

欢迎访问最专业的网吧论坛,无盘论坛,网吧经营,网咖管理,网吧专业论坛https://bbs.txwb.com

关注天下网吧微信,了解网吧网咖经营管理,安装维护:


本文来源:赛迪网 作者:佚名

声明
本文来源地址:0
声明:本站所发表的文章、评论及图片仅代表作者本人观点,与本站立场无关。若文章侵犯了您的相关权益,请及时与我们联系,我们会及时处理,感谢您对本站的支持!联系Email:support@txwb.com.,本站所有有注明来源为天下网吧或天下网吧论坛的原创作品,各位转载时请注明来源链接!
天下网吧·网吧天下
  • 本周热门
  • 本月热门
  • 阅读排行