关于一个 date-time 时间服务的daemon process 的代码实现

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

           

server.c


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define BUF_LEN 1024
#define SERV_PORT 60000
#define FD_SIZE 100
#define MAX_BACK 100
#define MAXFD	64

//extern int daemon_proc;

int daemon_init( char * name, int f )		//!> 注意第一个参数:服务程序名称, facility
{
	int i;
	pid_t pid;
		
	if( ( pid = fork() ) < 0 )			//!> fork 一个进程
	{
		printf("fork error\n");
		return -1;
	}
	else if( pid )
	{
		_exit( 0 );
	}
	
	if( setsid() < 0 )				//!> 新建一个会话组,成为leader
	{
		printf( "setsid error\n" );
		return -1;
	}
	
	signal( SIGHUP, SIG_IGN );	//!> 注意要忽略挂起信号
					//!> 因为上面的是会话头进程,下面是要被exit的,这时候发安出SIGHUP信号,为了不影响新的进程,那么必须忽略
	if( ( pid = fork() ) < 0 )      //!> 再次fork( 为了不能自动获得终端 )
	{
		printf("2 fork error\n");
		return -1;
	}
	else if( pid )
	{
		_exit( 0 );				//!> 会话leader退出
	}
	
	//daemon_proc = 1;
	
	chdir( "/" );				        //!> 改变目录
	
	for( i = 0; i < MAXFD; i++ )			//!> 关闭所有的文件描述符( 安全性 )
	{
		close( i );
	}
	
	open( "/dev/null", O_RDONLY );			//!> 也是安全性问题
	open( "/dev/null", O_WRONLY );
	open( "/dev/null", O_RDWR );
	
	openlog( name, LOG_PID, f );			//!> 产生log记录
	
	return 0;
}



int main( int argc, char ** argv )
{
	time_t ticks;
	char buf[50];
	int listenfd, connfd;
	int addrlen, len;
	struct sockaddr_in  servaddr, chiaddr;
	
	daemon_init( argv[0], 0 );				//!> 设置为daemon程序
	
    if( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
    {
       printf("Create socket Error : %d\n", errno );
       exit(EXIT_FAILURE );
    }
	
	//!> 下面是接口信息
	bzero( &servaddr, sizeof( servaddr ) );
	//memset( &servaddr, 0, sizeof( servaddr ) );
   	servaddr.sin_family = AF_INET;
   	servaddr.sin_addr.s_addr  =htonl( INADDR_ANY );
   	servaddr.sin_port = htons( SERV_PORT );
   	
   	if( bind( listenfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) == -1 )
   	{
   		printf("%d\n", listenfd);
   		printf("bind error\n");
   		exit( 1 );
   	}
   	
   	if( listen(listenfd, MAX_BACK ) == -1 )
   	{
   		printf( "listen error\n" );
   		exit( 1 );
   	}
   	
   	addrlen = len =sizeof( chiaddr );
   	
   	FILE * f;
   	
   	while( 1 )
   	{
   		len = addrlen;
   	
   		if( (connfd  = accept( listenfd, (struct sockaddr*)&chiaddr, &len ) ) == -1)
        {                              //!> accept 返回的还是套接字
         	printf("Accept Error : %d\n", errno );
           	continue;
       	}
       	
       	memset( buf, 0, sizeof( buf ) );
       	
       	ticks = time( NULL );
       	sprintf( buf, "%s", ctime( &ticks ) );			//!> 时间server
       	
       	buf[strlen(buf)] = '\0';
   		
   		/*
   	 	f = fopen( "/home/pengtao/桌面/朝花朝拾、夕有新花/data_time 后台进程server/t", "w+" );
   		
   		if( f )
   		{
   			fwrite( buf, sizeof( buf ), 1, f );	
   			fclose( f );
   		}
   		*/
   		
   		write( connfd, buf, strlen( buf ) );
   		
   		close( connfd );
   	}
   	
   	return 0;
}




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

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

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

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

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

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


Client.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>

#define MAXLINE 1024
#define SERV_PORT 60000

//!>
void send_and_recv( int connfd )
{			   
	char buf[50];
	
	memset( buf, 0, sizeof( buf ) );
   	read( connfd, buf, sizeof( buf ) );
   	
   	puts( buf );
}

int main( int argc, char ** argv )
{
   //!> char * SERV_IP = "10.30.97.188";
   char   buf[MAXLINE];
   int     connfd;
   struct sockaddr_in servaddr;
   
    if( argc !=2 )
    {
      printf("Input server ip !\n");
       exit(EXIT_FAILURE );
    }
   
   //!> 建立套接字
    if( ( connfd= socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
    {
      printf("Socket Error...\n" , errno );
       exit(EXIT_FAILURE );
    }

   //!> 套接字信息
   bzero(&servaddr, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(SERV_PORT);
   inet_pton(AF_INET, argv[1],&servaddr.sin_addr);
   
   //!> 链接server
    if( connect(connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0)
    {
      printf("Connect error..\n");
      exit(EXIT_FAILURE);
   }   
   

   //!>
   //!> send and recv
   send_and_recv( connfd );
   
   //!>

   close(connfd );
   
    return 0;
}


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

                      gcc -o client client.c

                      ./server

                      ./client



简单DEMO而已~~~

你可能感兴趣的:(socket,struct,Stream,server,gcc,Signal)