Chinaunix首页 | 论坛 | 博客
  • 博客访问: 39417
  • 博文数量: 23
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 137
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-07 10:58
个人简介

http://blog.csdn.net/shanshanpt/article/details/7419184

文章存档

2017年(22)

2012年(1)

我的朋友

分类: 嵌入式

2017-01-18 14:06:11

 简单的 daemon process 的实现,主要的步骤是:fork -> setsid -> umusk -> chdir -> close fds  -> openlog -> 服务程序!

           

server.c


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14.   
  15. #define BUF_LEN 1024  
  16. #define SERV_PORT 60000  
  17. #define FD_SIZE 100  
  18. #define MAX_BACK 100  
  19. #define MAXFD   64  
  20.   
  21. //extern int daemon_proc;  
  22.   
  23. int daemon_init( char * name, int f )       //!> 注意第一个参数:服务程序名称, facility  
  24. {  
  25.     int i;  
  26.     pid_t pid;  
  27.           
  28.     if( ( pid = fork() ) < 0 )           //!> fork 一个进程  
  29.     {  
  30.         printf("fork error\n");  
  31.         return -1;  
  32.     }  
  33.     else if( pid )  
  34.     {  
  35.         _exit( 0 );  
  36.     }  
  37.       
  38.     if( setsid() < 0 )               //!> 新建一个会话组,成为leader  
  39.     {  
  40.         printf( "setsid error\n" );  
  41.         return -1;  
  42.     }  
  43.       
  44.     signal( SIGHUP, SIG_IGN );  //!> 注意要忽略挂起信号  
  45.                     //!> 因为上面的是会话头进程,下面是要被exit的,这时候发安出SIGHUP信号,为了不影响新的进程,那么必须忽略  
  46.     if( ( pid = fork() ) < 0 )      //!> 再次fork( 为了不能自动获得终端 )  
  47.     {  
  48.         printf("2 fork error\n");  
  49.         return -1;  
  50.     }  
  51.     else if( pid )  
  52.     {  
  53.         _exit( 0 );             //!> 会话leader退出  
  54.     }  
  55.       
  56.     //daemon_proc = 1;  
  57.       
  58.     chdir( "/" );                       //!> 改变目录  
  59.       
  60.     for( i = 0; i < MAXFD; i++ )         //!> 关闭所有的文件描述符( 安全性 )  
  61.     {  
  62.         close( i );  
  63.     }  
  64.       
  65.     open( "/dev/null", O_RDONLY );          //!> 也是安全性问题  
  66.     open( "/dev/null", O_WRONLY );  
  67.     open( "/dev/null", O_RDWR );  
  68.       
  69.     openlog( name, LOG_PID, f );            //!> 产生log记录  
  70.       
  71.     return 0;  
  72. }  
  73.   
  74.   
  75.   
  76. int main( int argc, char ** argv )  
  77. {  
  78.     time_t ticks;  
  79.     char buf[50];  
  80.     int listenfd, connfd;  
  81.     int addrlen, len;  
  82.     struct sockaddr_in  servaddr, chiaddr;  
  83.       
  84.     daemon_init( argv[0], 0 );              //!> 设置为daemon程序  
  85.       
  86.     if( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )  
  87.     {  
  88.        printf("Create socket Error : %d\n", errno );  
  89.        exit(EXIT_FAILURE );  
  90.     }  
  91.       
  92.     //!> 下面是接口信息  
  93.     bzero( &servaddr, sizeof( servaddr ) );  
  94.     //memset( &servaddr, 0, sizeof( servaddr ) );  
  95.     servaddr.sin_family = AF_INET;  
  96.     servaddr.sin_addr.s_addr  =htonl( INADDR_ANY );  
  97.     servaddr.sin_port = htons( SERV_PORT );  
  98.       
  99.     if( bind( listenfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) == -1 )  
  100.     {  
  101.         printf("%d\n", listenfd);  
  102.         printf("bind error\n");  
  103.         exit( 1 );  
  104.     }  
  105.       
  106.     if( listen(listenfd, MAX_BACK ) == -1 )  
  107.     {  
  108.         printf( "listen error\n" );  
  109.         exit( 1 );  
  110.     }  
  111.       
  112.     addrlen = len =sizeof( chiaddr );  
  113.       
  114.     FILE * f;  
  115.       
  116.     while( 1 )  
  117.     {  
  118.         len = addrlen;  
  119.       
  120.         if( (connfd  = accept( listenfd, (struct sockaddr*)&chiaddr, &len ) ) == -1)  
  121.         {                              //!> accept 返回的还是套接字  
  122.             printf("Accept Error : %d\n", errno );  
  123.             continue;  
  124.         }  
  125.           
  126.         memset( buf, 0, sizeof( buf ) );  
  127.           
  128.         ticks = time( NULL );  
  129.         sprintf( buf, "%s", ctime( &ticks ) );          //!> 时间server  
  130.           
  131.         buf[strlen(buf)] = '\0';  
  132.           
  133.         /* 
  134.         f = fopen( "/home/pengtao/桌面/朝花朝拾、夕有新花/data_time 后台进程server/t", "w+" ); 
  135.          
  136.         if( f ) 
  137.         { 
  138.             fwrite( buf, sizeof( buf ), 1, f );  
  139.             fclose( f ); 
  140.         } 
  141.         */  
  142.           
  143.         write( connfd, buf, strlen( buf ) );  
  144.           
  145.         close( connfd );  
  146.     }  
  147.       
  148.     return 0;  
  149. }  



我们现在想想,为什么需要fork两次呢??????我们需要知道下面的知识!

守护进程、孤儿进程的关系:

首先:Deamon进程(守护进程)就是一个孤儿进程!!!

            所以我们需要构造孤儿进程!

            也就是:守护进程创建是特意而为的,创建的方式确实是让它 fork 出来的进程成为孤儿进程。

            守护进程创建时是刻意让父进程结束执行(也就是代码中的fork两次后,将第一个子进程kill,那么由子进程创建ok的子进程就成为了orphan进程(孤儿进程)),让子进程被 init 接管,目的是不让守护进程有任何的 control terminal。然后还要调用 setsid 使它成为一个单独的 session 中的进程且只有这一个进程,除此之外还要关闭所有的文件描述符,将文件描述符 0, 1, 2 全部指向 /dev/null 保证它不会将信息打印到终端,不会读取用户输入。

Client.c


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11.   
  12. #define MAXLINE 1024  
  13. #define SERV_PORT 60000  
  14.   
  15. //!>  
  16. void send_and_recv( int connfd )  
  17. {                
  18.     char buf[50];  
  19.       
  20.     memset( buf, 0, sizeof( buf ) );  
  21.     read( connfd, buf, sizeof( buf ) );  
  22.       
  23.     puts( buf );  
  24. }  
  25.   
  26. int main( int argc, char ** argv )  
  27. {  
  28.    //!> char * SERV_IP = "10.30.97.188";  
  29.    char   buf[MAXLINE];  
  30.    int     connfd;  
  31.    struct sockaddr_in servaddr;  
  32.      
  33.     if( argc !=2 )  
  34.     {  
  35.       printf("Input server ip !\n");  
  36.        exit(EXIT_FAILURE );  
  37.     }  
  38.      
  39.    //!> 建立套接字  
  40.     if( ( connfd= socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )  
  41.     {  
  42.       printf("Socket Error...\n" , errno );  
  43.        exit(EXIT_FAILURE );  
  44.     }  
  45.   
  46.    //!> 套接字信息  
  47.    bzero(&servaddr, sizeof(servaddr));  
  48.    servaddr.sin_family = AF_INET;  
  49.    servaddr.sin_port = htons(SERV_PORT);  
  50.    inet_pton(AF_INET, argv[1],&servaddr.sin_addr);  
  51.      
  52.    //!> 链接server  
  53.     if( connect(connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0)  
  54.     {  
  55.       printf("Connect error..\n");  
  56.       exit(EXIT_FAILURE);  
  57.    }     
  58.      
  59.   
  60.    //!>  
  61.    //!> send and recv  
  62.    send_and_recv( connfd );  
  63.      
  64.    //!>  
  65.   
  66.    close(connfd );  
  67.      
  68.     return 0;  
  69. }  



 编译运行: gcc -o server server.c


                      gcc -o client client.c

                      ./server

                      ./client



简单DEMO而已~~~

阅读(660) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~