热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>编程开发>

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

来源: 作者: 时间:2007-06-25 Tag: 点击:

 

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<stdio.h>
#include<stdlib.h>
#include<unistd.h>

#include<netinet/in.h>
#include<sys/socket.h>

#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>

#include<errno.h>
#include <sys/ioctl.h>
//为每一个服务分配一个包含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;fd<FD_SETSIZE;fd++)
    if(FD_ISSET(fd,&readfds))
      { //bug 2:第一次接收到串“sock addr=3.190.0.64,client sock=4”,以后用LOOPBACK 连接返回为"127.0.0.1"
 clientfd=accept(fd,(struct sockaddr*)&addr_clt,&n);
        printf("sock addr=%s,client sock=%d\n",inet_ntoa(addr_clt.sin_addr),clientfd);
         pid=fork(); 
        switch(pid)
 {
 case -1:
   perror("error");                   
   exit(5);     
        case 0: 
                    
   //dup2(clientfd,stdin);
          //dup2(clientfd,stdout);
          //dup2(clientfd,stderr); 
          //close(clientfd);
   for(p=phead;p!=NULL;p=p->next)
   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;      
 }
 
      }
  
 } 

}



相关文章:
ioctl函数
struts与spring三种整合方法
进程的创建fork
jsp速成
Hibernate单向一对多应注意的问题
Java RMI之HelloWorld篇
常用的Eclipse快捷键
sparc linux 系统调用
一个关于jboss "Halting VM"的情况处理
编写更好的Linux程序3(这次只讲void *)
Tikiwiki 2.2+ Ucenter 1.5(Discuz)整合
玩转ptrace(一)
玩转ptrace(二)
dup2
pipe
Jboss的学习
gcc用法
将UI从代码中解放出来
数据结构与算法(2)
有关于JAVA中的CLASSPATH的作用
const成员函数
虚函数
《c和指针》读书笔记2
初次接触Zend Framework需要掌握的内容
php中require和include的简单区别
正则表达式在PHP中的应用
在PHP中使用与Perl兼容的正则表达式
Zend Studio 生成 wsdl
freebsd7 + php5.2.6 + xdebug2.0.2安装
PHP抓取远程网站数据的代码