简单的 daemon process 的实现,主要的步骤是:fork -> setsid -> umusk -> chdir -> close fds -> openlog -> 服务程序!
server.c
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define BUF_LEN 1024
-
#define SERV_PORT 60000
-
#define FD_SIZE 100
-
#define MAX_BACK 100
-
#define MAXFD 64
-
-
-
-
int daemon_init( char * name, int f )
-
{
-
int i;
-
pid_t pid;
-
-
if( ( pid = fork() ) < 0 )
-
{
-
printf("fork error\n");
-
return -1;
-
}
-
else if( pid )
-
{
-
_exit( 0 );
-
}
-
-
if( setsid() < 0 )
-
{
-
printf( "setsid error\n" );
-
return -1;
-
}
-
-
signal( SIGHUP, SIG_IGN );
-
-
if( ( pid = fork() ) < 0 )
-
{
-
printf("2 fork error\n");
-
return -1;
-
}
-
else if( pid )
-
{
-
_exit( 0 );
-
}
-
-
-
-
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 );
-
-
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 );
-
-
if( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
-
{
-
printf("Create socket Error : %d\n", errno );
-
exit(EXIT_FAILURE );
-
}
-
-
-
bzero( &servaddr, 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)
-
{
-
printf("Accept Error : %d\n", errno );
-
continue;
-
}
-
-
memset( buf, 0, sizeof( buf ) );
-
-
ticks = time( NULL );
-
sprintf( buf, "%s", ctime( &ticks ) );
-
-
buf[strlen(buf)] = '\0';
-
-
-
-
-
-
-
-
-
-
-
-
write( connfd, buf, strlen( buf ) );
-
-
close( connfd );
-
}
-
-
return 0;
-
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#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 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);
-
-
-
if( connect(connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0)
-
{
-
printf("Connect error..\n");
-
exit(EXIT_FAILURE);
-
}
-
-
-
-
-
send_and_recv( connfd );
-
-
-
-
close(connfd );
-
-
return 0;
-
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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而已~~~
阅读(660) | 评论(0) | 转发(0) |