linux kill发送信号量,linux fork+exec+信号量的使用

有这么一个需求:使用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。测试代码如下:

点击(此处)折叠或打开

#include

#include

#include

#include

#include

#include

static void sig_hup(int sig)

{

sig = sig;

fprintf(stderr, "pid: %d receive sig_hupn", getpid());

}

static void sig_usr(int sig)

{

signal(sig, sig_usr);

fprintf(stderr, "pid: %d receive sig_usrn", getpid());

}

int main(int argc, char * argv[])

{

int opt;

FILE * fp = stderr;

signal(SIGHUP, sig_hup);

signal(SIGUSR1, sig_usr);

while (-1 != (opt = getopt(argc, argv, "Di:p:")))

{

switch(opt)

{

case 'D':

fprintf(fp, "get option -Dn");

break;

case 'i':

fprintf(fp, "get option -i %sn", optarg);

break;

case 'p':

fprintf(fp, "get option -p %sn", optarg);

break;

default:

fprintf(fp, "get some thing that cannot be recognisedn");

break;

}

}

sleep(300);

if (errno == EINTR)

{

fprintf(fp, "errno is EINTR(%d)n", EINTR);

}

fprintf(fp, "hello worldn");

return 0;

}

使用命令kill向进程产生信号:kill -s SIGUSR1 `pidof t_main`。其中t_main为测试程序执行进程名

产生如下结果:

d483d6d8175c59b72d872cceffffb60d.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值