先试着写一个udpserver的daemon

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <unistd.h>
  9. #define PORT 4444
  10. #define FDMAX 64
  11. void initdaemon();
  12. int main()
  13. {
  14. #ifdef DAEMON
  15. initdaemon();
  16. #endif
  17. int fd = socket(AF_INET, SOCK_DGRAM, 0);
  18. if(fd < 0)
  19. return -1;
  20. struct sockaddr_in server, client;
  21. server.sin_family = AF_INET;
  22. server.sin_port = htons(PORT);
  23. server.sin_addr.s_addr = htonl(INADDR_ANY);
  24. bind(fd, (const struct sockaddr *)&server, sizeof(struct sockaddr));
  25. socklen_t len = sizeof(struct sockaddr);
  26. char buff[2048] = {0};
  27. while(1)
  28. {
  29. recvfrom(fd, buff, 2048, 0,(struct sockaddr *)&client, &len);
  30. // printf("%s send msg: %s \n", inet_ntoa(client.sin_addr), buff);
  31. sendto(fd, "OK", 2, 0, (const struct sockaddr *)&client, len);
  32. }
  33. }
  34. void initdaemon()
  35. {
  36. pid_t pid = fork(); //第一次fork 是因为创建会话的进程不能是进程组长,否则setsid会失败。
  37. if(pid > 0)
  38. {
  39. _exit(0);
  40. }
  41. else if(pid < 0)
  42. {
  43. _exit(1);
  44. }
  45. if(setsid() < 0)
  46. _exit(1);
  47. pid_t id = fork();//第二次fork是因为当前进程是会话组长 他有可能会获取控制终端,为了不让它获得控制终端,不让它成为组长。
  48. if(id > 0){
  49. _exit(0);
  50. }
  51. else if(id < 0)
  52. {
  53. _exit(1);
  54. }
  55. int i = 0;
  56. chdir("/");
  57. for(i; i < FDMAX; ++i)
  58. close(i);
  59. open("/dev/null", O_RDONLY);
  60. open("/dev/null", O_RDWR);
  61. open("/dev/null", O_RDWR); //将0 1 2重定向
  62. }
  1. gcc -DDAEMON udpserver.c -o udpserver添加宏DAEMON进行编译

下面是测试client端:

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <sys/types.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <unistd.h>
  7. #define PORT 4444
  8. int main(int argc, char *argv[])
  9. {
  10. if(argc != 2)
  11. {
  12. printf("./udpclient IP\n");
  13. return 1;
  14. }
  15. int fd = socket(AF_INET, SOCK_DGRAM, 0);
  16. if (fd < 0)
  17. return 1;
  18. struct sockaddr_in server;
  19. server.sin_family = AF_INET;
  20. server.sin_port = htons(PORT);
  21. if (!inet_pton(AF_INET, argv[1], (void *)&server.sin_addr))
  22. {
  23. printf("IP error\n");
  24. return -1;
  25. }
  26. char buff1[2048] ="sdfsdf";
  27. char buff2[2048] = {0};
  28. socklen_t size = sizeof(struct sockaddr);
  29. while(1)
  30. {
  31. sendto(fd, buff1, 2048, (const struct sockaddr *)&server, size);
  32. sleep(5);
  33. recvfrom(fd, buff2, 2048, 0, NULL, NULL);
  34. printf("recv : %s\n", buff2);
  35. }
  36. }

先看一下system v init管理服务的一种写法:
我们可以看到在/etc/init.d 下面有很多脚本文件, 当系统启动时,init进程会根据不同的运行级别去执行不同的/etc/rcN.d 里面的脚本文件并会自动加上start参数,我们看一下sshd的例子:

  1. set -e
  2. # /etc/init.d/ssh: start and stop the OpenBSD "secure shell(tm)" daemon
  3. test -x /usr/sbin/sshd || exit 0
  4. ( /usr/sbin/sshd -\? 2>&1 | grep -q OpenSSH ) 2>/dev/null || exit 0
  5. umask 022
  6. if test -f /etc/default/ssh; then
  7. . /etc/default/ssh
  8. fi
  9. case "$1" in
  10. start)
  11. check_for_upstart 1
  12. check_privsep_dir
  13. check_for_no_start
  14. check_dev_null
  15. log_daemon_msg "Starting OpenBSD Secure Shell server" "sshd" || true
  16. if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sshd.pid --exec /usr/sbin/sshd -- $SSHD_OPTS; then
  17. log_end_msg 0 || true
  18. else
  19. log_end_msg 1 || true
  20. fi
  21. ;;
  22. stop)
  23. check_for_upstart 0
  24. log_daemon_msg "Stopping OpenBSD Secure Shell server" "sshd" || true
  25. if start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/sshd.pid; then
  26. log_end_msg 0 || true
  27. else
  28. log_end_msg 1 || true
  29. fi
  30. ;;
  31. reload|force-reload)
  32. check_for_upstart 1
  33. check_for_no_start
  34. check_config
  35. log_daemon_msg "Reloading OpenBSD Secure Shell server's configuration" "sshd" || true
  36. if start-stop-daemon --stop --signal 1 --quiet --oknodo --pidfile /var/run/sshd.pid --exec /usr/sbin/sshd; then
  37. log_end_msg 0 || true
  38. else
  39. log_end_msg 1 || true
  40. fi
  41. ;;
  42. restart)
  43. check_for_upstart 1
  44. check_privsep_dir
  45. check_config
  46. log_daemon_msg "Restarting OpenBSD Secure Shell server" "sshd" || true
  47. start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /var/run/sshd.pid
  48. check_for_no_start log_end_msg
  49. check_dev_null log_end_msg
  50. if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sshd.pid --exec /usr/sbin/sshd -- $SSHD_OPTS; then
  51. log_end_msg 0 || true
  52. else
  53. log_end_msg 1 || true
  54. fi
  55. ;;
  56. try-restart)
  57. check_for_upstart 1
  58. check_privsep_dir
  59. check_config
  60. log_daemon_msg "Restarting OpenBSD Secure Shell server" "sshd" || true
  61. RET=0
  62. start-stop-daemon --stop --quiet --retry 30 --pidfile /var/run/sshd.pid || RET="$?"
  63. case $RET in
  64. 0)
  65. # old daemon stopped
  66. check_for_no_start log_end_msg
  67. check_dev_null log_end_msg
  68. if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sshd.pid --exec /usr/sbin/sshd -- $SSHD_OPTS; then
  69. log_end_msg 0 || true
  70. else
  71. log_end_msg 1 || true
  72. fi
  73. ;;
  74. 1)
  75. # daemon not running
  76. log_progress_msg "(not running)" || true
  77. log_end_msg 0 || true
  78. ;;
  79. *)
  80. # failed to stop
  81. log_progress_msg "(failed to stop)" || true
  82. log_end_msg 1 || true
  83. ;;
  84. esac
  85. ;;
  86. status)
  87. check_for_upstart 1
  88. status_of_proc -p /var/run/sshd.pid /usr/sbin/sshd sshd && exit 0 || exit $?
  89. ;;
  90. *)
  91. log_action_msg "Usage: /etc/init.d/ssh {start|stop|reload|force-reload|restart|try-restart|status}" || true
  92. exit 1
  93. esac
  94. exit 0

写法也就是大致这个样子的利用shell 里的case 给不同参数运行不同的function 至于start-stop-daemon的用法可以查阅man page。
我们就可以将我们的udpserver 放到/usr/bin/目录下面,然后在/etc/init.d/目录下加上udp_server 脚本文件写法如下:

  1. #!/bin/bash
  2. SERVER=/usr/bin/udpserver
  3. if [ ! -e $SERVER ];then
  4. exit 1
  5. fi
  6. case "$1" in
  7. start)
  8. if [ -n "`pidof $SERVER`" ];then
  9. echo "Udpserver is running......"
  10. else
  11. $SERVER
  12. fi
  13. ;;
  14. stop)
  15. PID=`pidof /usr/bin/udpserver`
  16. [ -n "$PID" ] && kill -9 $PID
  17. ;;
  18. restart)
  19. PID=`pidof $SERVER`
  20. [ -n "$PID" ] && kill -9 $PID
  21. $SERVER
  22. ;;
  23. *)
  24. exit 1
  25. ;;
  26. esac

再将你需要运行的等级目录下添加连接/etc /rc2.d/目录下K开头表示不启动服务,S打头表示启动服务 建立连接 ln -s ../init.d/udp_server S99udpserver , 表名开机启动 S后的数字字母等表示启动顺序。如此就可以实现system v init类型的启动服务。

若以systemd形式 将更为简单方便 此时就不需要udpserver 是一个daemon 可去掉宏进行编译。

在/etc/systemd/system/下建立文件udpserver.service 文件 内容大概为

  1. [Unit]
  2. Description=my dup server
  3. After=network.target
  4. [Service]
  5. EnvironmentFile=
  6. ExecStart=/usr/bin/udpserver
  7. ExecReload=/bin/killall udpserver
  8. KillMode=process
  9. Restart=on-failure
  10. [Install]
  11. WantedBy=multi-user.target

然后再执行 systemctl daemon-reload systemctl enable udpserver即可开机自启动。
systemctl start /stop/reload控制服务。journalctl可以查看启动日志。
总得来说还是systemd这种形式较为简单,它还有较好的日志系统,方便管理 不用将服务写为daemon。

daemon 启动system V init 和 systemd 配置的更多相关文章

  1. 编写CentOS的System V init启动脚本

    系统本身自带了说明,在/usr/share/doc/initscripts-(*)/sysvinitfiles,内容如下: 所有System V init脚本都命名为/etc/rc.d/init.d/ ...

  2. Systemd初始化进程/RHEL 6系统中System V init命令与RHEL 7系统中systemctl命令的对比

    Linux操作系统的开机过程是这样的,即从BIOS开始,然后进入Boot Loader,再加载系统内核,然后内核进行初始化,最后启动初始化进程.初始化进程作为Linux系统的第一个进程,它需要完成Li ...

  3. systemd、upstart和system V

    http://blog.csdn.net/kumu_linux/article/details/7653802  systemd是Linux下的一种init软件,由Lennart Poettering ...

  4. Linux system V

    Sysvinit 的小结 Sysvinit 的优点是概念简单.Service 开发人员只需要编写启动和停止脚本,概念非常清楚:将 service 添加/删除到某个 runlevel 时,只需要执行一些 ...

  5. /etc/init.d/sshd配置SSHD路径忘记修改导致启动失败

    [root@lnlte2dmr3 ~]# bash[root@lnlte2dmr3 ~]# install -v -m700 -d /var/empty/sshdinstall: 正在创建目录&quo ...

  6. Linux启动流程和服务管理(init和systemd)

    目录 一:Linux启动流程 init和Systemd的区别 二:Linux服务管理(service,systemctl) 一:Linux启动流程 Rhel6启动过程: Rhel7启动过程: GRUB ...

  7. Linux init 系列一 System V风格

    传统的Linux init有两种风格,System V风格和BSD风格,本文主要介绍System V风格. System V风格init的主要流程是, 1. 内核执行init进程. 2. Init 运 ...

  8. System V启动脚本启动的服务

    /etc/rc.d/init.d/目录下的内容如下:这些常用的服务器都是System v的服务,要控制System V 的服务,我们可以使用以下命令 #/etc/rc.d/init.d/script  ...

  9. 提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll

    新版本SQLITE,如果下载Precompiled Binaries版会出现提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll. 下载Prec ...

随机推荐

  1. 如何用CropBox实现头像裁剪并与java后台交互

    如何用CropBox实现头像裁剪并与java后台交互 参考网站:https://developer.mozilla.org/zh-CN/docs/Web/API/Blob 参考: http://blo ...

  2. Java基础-方法(07)

    方法的定义 方法其实就是完成特定功能的代码块在很多语言里面都有函数的定义函数在Java中被称为方法 格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…) { 函数体; ret ...

  3. 【译】Java中的字符串字面量

    原文地址:https://javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html 作者:Corey McGlone 让我们由一个简 ...

  4. js如何获取地址栏的参数

    //获取参数的方法(利用正则表达式) function GetUrlParam(name){ var reg = new RegExp("(^|&)"+ name +&qu ...

  5. IIS 服务无法在此时接受控制信息

    应用程序池无法重新启动,报错:服务无法在此时接受控制信息 解决方法:重启 Credential Manager服务即可

  6. route命令实例练习

    第1章 命令配置 虚拟服务器 网卡配置信息 虚拟网卡名称 虚拟网卡模式 服务器01 eth1 10.0.0.10/24 nat模式 服务器02 eth2 10.0.0.11/24 nat模式 eth3 ...

  7. 特征提取方法: one-hot 和 IF-IDF

    one-hot 和 IF-IDF是目前最为常见的用于提取文本特征的方法,本文主要介绍两种方法的思想以及优缺点. 1. one-hot 1.1 one-hot编码 什么是one-hot编码?one-ho ...

  8. cookie在不同域名domain、path下的读取规则

    cookie 子域名可以读父域名中的cookie 如在 .ping.com域下注入cookie,则该子域下的网页如p1.ping.com.p2.ping.com 都能读取到cookie信息 path的 ...

  9. 高性能 AJAX

    请求数据的常用的五种方式 1.XMLHttpRequest (XHR) var url = '/data.php'; var params = [     'id=934875',     'limi ...

  10. 一个“”字引发的痛苦经历

    (一篇老文章,还有点价值,特意整理了一下.由于涉及客户项目,已经进行了脱敏处理) 1 写在前面的话 虽然这个问题是有解决方案的,但我不建议大家提供给客户,理由见此. 2 问题描述 2010.10.12 ...