Chinaunix首页 | 论坛 | 博客
  • 博客访问: 102975
  • 博文数量: 24
  • 博客积分: 105
  • 博客等级: 民兵
  • 技术积分: 244
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-09 20:05
文章分类

全部博文(24)

文章存档

2015年(1)

2014年(9)

2013年(10)

2012年(4)

我的朋友

分类: LINUX

2013-05-28 15:31:38

有这么一个需求:使用udp socket通信,其中一个udp服务端口用于接收很多用户(用户数超过端口总数65535)。这些用户需要创建不通客户端源端口用于和另一个服务器通信,并维持着这个客户端socket用于接收服务器的消息。由于是udp socket通信,TCP/IP协议栈不需要维护连接状态,从而想到了udp服务端口用于和客户通信,使用新的线程和另一服务端通信。

背景前提:原来已经存在了一个进程A,可以完成udp服务端口与客户端通信,创建udp客户端端口和另一个udp服务器通信。现在通过一个程序外壳用于提供用户的服务接口,内部通过fork + exec启动进程A的几个副本,这样把原来单一进程所做的事情,分配给多个进程来做,并且进程间无耦合,预计能达到比较理想的效果。用户和进程A副本在壳程序中形成的对应关系{用户唯一标识 + struct sockaddr_in + 分配的进程A副本端口号},通过hash表以用户唯一标识为主键组织,加快查找速度。

    调用fork处,进程执行分叉。由于进程组织成树状,父节点可能拥有多个子节点,子节点只有一个父节点,父进程返回子进程的进程id号,子进程返回0。
    注:execl最后一个参数为NULL,即execl("/usr/lcal/bin/ls", "-lh", NULL);
           char * argvs[] = {"-lh", NULL} 
           execv一般这么用execv("/usr/local/bin/ls",argvs);
            末尾是p的,是只需要给出可执行文件名,会在bash一般搜寻的路径中查找。末尾是e的,可以传递环境变量。
注:fork调用产生后,子进程的进程内存空间完全从父进程内存空间拷贝, 文件描述符等引用系数会增加。

要解决的问题:
1、子进程组中有进程结束,则整个进程组一起结束。
解决:此问题好办,在主进程中捕获SIGCHLD信号,向子进程组中的每一个进程发送一个退出信号。kill(pid, SIGKILL),最后主进程退出即可。
2、父进程结束,则整个子进程组一起结束。不能托孤给init进程
解决:捕获SIGKILL信号,发现系统不给捕获SIGKILL和SIGSTOP的机会。并且存在一个现象是前台启动CTRL+C,则整个进程组都结束。在另一个vty中,kill -9 `pidof processes_manager`则产生了孤儿进程。是否可以利用这一点?

现在探寻一下原因:在一个vty中使用前台启动proceees_manager进程,按下CTRL + C键后,整个进程组一起结束。
                           在另一个vty中使用kill -9 `pidof processes_manager`,子进程组成了孤儿进程,被托孤给init进程了。
man 7 signal
           很明确的提出来:The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored。现在足以证明靠信号是没得搞了,用户发一个SIGKILL信号过来,在信号上无解了。

父进程不能直接处死子进程,那就子进程自杀好了。子进程启动一个定时器,5秒检测一次自己的父进程pid,发现父进程pid是init进程pid时,则自己结束。

顺便写一下信号:
进程在阻塞状态捕获信号后,会立即变成触发状态,errno被置位EINTR。测试代码如下:

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <errno.h>

  5. #include <sys/types.h>
  6. #include <sys/signal.h>

  7. static void sig_hup(int sig)
  8. {
  9.     sig = sig;

  10.     fprintf(stderr, "pid: %d receive sig_hupn", getpid());
  11. }

  12. static void sig_usr(int sig)
  13. {
  14.     signal(sig, sig_usr);
  15.     fprintf(stderr, "pid: %d receive sig_usrn", getpid());
  16. }

  17. int main(int argc, char * argv[])
  18. {
  19.     int opt;
  20.     FILE * fp = stderr;
  21.     
  22.     signal(SIGHUP, sig_hup);
  23.     signal(SIGUSR1, sig_usr);

  24.     while (-1 != (opt = getopt(argc, argv, "Di:p:")))
  25.     {
  26.         switch(opt)
  27.         {
  28.             case 'D':
  29.                 fprintf(fp, "get option -Dn");
  30.                 break;
  31.             case 'i':
  32.                 fprintf(fp, "get option -i %sn", optarg);
  33.                 break;
  34.             case 'p':
  35.                 fprintf(fp, "get option -p %sn", optarg);
  36.                 break;
  37.             default:
  38.                 fprintf(fp, "get some thing that cannot be recognisedn");
  39.                 break;
  40.         }
  41.     }

  42.     sleep(300);

  43.     if (errno == EINTR)
  44.     {
  45.         fprintf(fp, "errno is EINTR(%d)n", EINTR);
  46.     }

  47.     fprintf(fp, "hello worldn");

  48.     return 0;
  49. }
使用命令kill向进程产生信号:kill -s SIGUSR1 `pidof t_main`。其中t_main为测试程序执行进程名
产生如下结果:


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

yikuo1232013-05-29 17:28:30

为什么正文里面没有提到信号量啊?

yikuo1232013-05-29 17:22:04

这系统是不是有bug,我一个人点出了两个"赞"

yikuo1232013-05-29 17:20:55