//Daemon.cpp//This example shows a fork system call that combines the ASIO and POSIX standard systems to produce a daemon. //time server? //Copyright (c) 2003-2014 Christopher M. Kohlhoff (Chris at kohlhoff dot com)////distributed under the Boost software License, Version 1.0. (See accompanying//file license_1_0.txt or copy atHttp://www.boost.org/LICENSE_1_0.txt)//#include<boost/asio/io_service.hpp>#include<boost/asio/ip/udp.hpp>#include<boost/asio/signal_set.hpp>#include<boost/array.hpp>#include<boost/bind.hpp>#include<ctime>#include<iostream>#include<syslog.h>#include<unistd.h>usingboost::asio::ip::udp;//defining a UDP time server classclassudp_daytime_server{ Public: Udp_daytime_server (Boost::asio::io_service&io_service): socket_ (Io_service, Udp::endpoint (Udp::v4 (), -)) { //start receiving immediately after instantiationstart_receive (); }Private: voidstart_receive () {Socket_.async_receive_from (Boost::asio::buffer (Recv_buffer_), Remote_endpoint_, Boost::bind (&udp_daytime_server::handle_receive, This, _1)); } voidHandle_receive (Constboost::system::error_code&EC) { if(!ec | | ec = =boost::asio::error::message_size) { using namespaceStd//for time_t, time and CTime;time_t now = time (0); STD::stringMessage = CTime (&Now ); Boost::system::error_code Ignored_ec; Socket_.send_to (boost::asio::buffer (message), Remote_endpoint_,0, IGNORED_EC); } start_receive (); } Udp::socket socket_; Udp::endpoint Remote_endpoint_; Boost::array<Char,1>Recv_buffer_;};intMain () {Try{Boost::asio::io_service io_service; //initialise the server before becoming a daemon. If the process is//started from a shell, this means any errors 'll be reported back to the//user. //If the program is started through the shell, all errors are returned to the user. udp_daytime_server Server (io_service); //Register signal handlers So, the daemon is shut down. May//also want to register-signals, such as SIGHUP to trigger a//re-read of a configuration file. //register the signal handlers. In order to exit, stop. Boost::asio::signal_set Signals (Io_service, SIGINT, SIGTERM); Signals.async_wait (Boost::bind (&boost::asio::io_service::stop, &io_service)); //Inform the io_service that we is about to become a daemon. the//Io_service cleans up any internal resources, such as threads, which may//interfere with forking. //notify Io_service that to daemon the process, Io_service will clear any internal resources? threads, for example, will affect the forkio_service.notify_fork (Boost::asio::io_service::fork_prepare); //Fork the process and has the parent exit. If The process was started//From a shell, this returns control to the user. Forking a new process is//also a prerequisite for the subsequent call to Setsid (). //after the process is fork, the parent process exits. If the process is started from the shell, it will be returned immediately to the user. //Fork A new process is also a prerequisite for subsequent calls to Setsid. SETSID create a new session. //These steps are daemon programming rules. For details, see Chapter 13th Apue. if(pid_t pid =Fork ()) { if(PID >0) { //We ' re in the parent process and need to exit. // //When the exit () function was used, the program terminates without//invoking local variables ' destructors. Only global variables is//destroyed. As the Io_service object is a local variable, this means//We don't have a to call:// //io_service.notify_fork (boost::asio::io_service::fork_parent); // //However, this line should is added before each call to exit () if//using a global Io_service object. An additional call:// //io_service.notify_fork (Boost::asio::io_service::fork_prepare); // //should also precede the second fork (). /*This is the parent process logic, when the Exit function is called. The program will not call the destructor for the local variable, and the destructor for the global variable will be called. Because Io_service is a local object, this means that we do not need to call Io_service.notify_fork (boost::asio::io_service::fork_parent); However, when using Io_service as a global object, it is necessary to call the preceding line of code before each call to exit. Also need to call O_service.notify_fork (Boost::asio::io_service::fork_prepare) before the second fork; */Exit (0); } Else{syslog (Log_err| Log_user,"First fork failed:%m"); return 1; } } //Make the process a new session leader. This detaches it from the//terminal. //opens a new session and leader as a session, separated from the terminal. Setsid (); //A Process inherits its working directory from its parent. This could is//On a mounted filesystem, which means that the running daemon would//prevent this filesystem from being unmounted. Changing to the root//directory avoids this problem. //To prevent the daemon's file system from being mounted, change to the root directory. ChDir"/"); //The file mode creation mask is also inherited from the parent process. //We don ' t want to restrict the permissions on files created by the//Daemon, so the mask is cleared. //to avoid restricting the permissions of the files created by the daemon, Umask is set to 0Umask0); //A second fork ensures the process cannot acquire a controlling terminal. //The second fork ensures that the process cannot get the terminal because it is not a leader? if(pid_t pid =Fork ()) { if(PID >0) {exit (0); } Else{syslog (Log_err| Log_user,"Second Fork failed:%m"); return 1; } } //Close the standard streams. This decouples the daemon from the terminal//That started it. //error closing standard input and output, separate from terminal. Close0); Close (1); Close (2); //We don ' t want the daemon to has any of the standard input. //no standard input is required. Why is it so used? if(Open ("/dev/null", o_rdonly) <0) {syslog (Log_err| Log_user,"Unable to open/dev/null:%m"); return 1; } //Send standard output to a log file. //REDIRECT standard output to log file Const Char* Output ="/tmp/asio.daemon.out"; Const intFlags = O_wronly | O_creat |O_append; Constmode_t mode = S_IRUSR | S_IWUSR | S_irgrp |S_iroth; if(Open (output, flags, mode) <0) {syslog (Log_err| Log_user,"Unable to open output file%s:%m", output); return 1; } //Also send standard error to the same log file. if(DUP (1) <0) {syslog (Log_err| Log_user,"unable to DUP output descriptor:%m"); return 1; } //Inform The Io_service, we have finished becoming a daemon. the//Io_service uses this opportunity to the create any internal file descriptors//That's need to is private to the new process. //inform Io_service that it has become a daemon process. io_service.notify_fork (Boost::asio::io_service::fork_child); //The Io_service can now is used normally.Syslog (Log_info | Log_user,"Daemon started"); Io_service.run (); Syslog (Log_info| Log_user,"Daemon stopped"); } Catch(std::exception&e) {syslog (Log_err| Log_user,"Exception:%s", E.what ()); Std::cerr<<"Exception:"<< e.what () <<Std::endl; }}
In the ASIO example, the daemon initialization