C语言 - 获取信号发送进程的进程ID

3

我现在遇到的问题是,我创建了两个不同的程序(一个将管理另一个,而另一个将被执行多次)。这些程序将通过信号来回通信。我的问题是,是否有可能(以及如何)获取发送信号的程序的进程ID。

我的程序使用signal()来捕获信号,使用kill()来发送信号。

4个回答

3

虽然signal()是标准C库中的函数,但它不具备可移植性,其行为取决于系统。最好使用符合POSIX.1标准的sigaction()。

以下是如何使用带有处理程序void h(int sig)的sigaction的示例:

int mysignal (int sig, void (*h)(int), int options)
{
    int r;
    struct sigaction s;
    s.sa_handler = h;
    sigemptyset (&s.sa_mask);
    s.sa_flags = options;
    r = sigaction (sig, &s, NULL);
    if (r < 0) perror (__func__);
    return r;
}

选项在man sigaction中有描述。一个好的选择是options=SA_RESTART

要知道发送信号的进程的PID,设置options=SA_SIGINFO,并使用sa_sigaction回调而不是sa_handler;它将接收一个siginfo_t结构体,其中包含一个si_pid字段。您可以使用sigqueue将数据关联到信号。

一般而言,在安全通信方面使用信号是不好的想法(当发送n个信号时,只有第一个信号有机会被传递;没有钩子来关联其他数据;可用的用户信号仅有两个)。最好使用管道、命名管道或套接字。


2
要获取发送信号的进程ID,您需要在选项SA_SIGINFO中包含。如果这样做,sigaction的接口略有不同。下面是一个正确的处理程序示例以及如何设置它。 (我包括SA_RESTART作为选项,只是因为通常是个好主意,但并非必要)
// example of a handler which checks the signalling pid
void handler(int sig, siginfo_t* info, void* vp) { 
  if (info->si_pid != getpid()) {
    // not from me (or my call to alarm)
    return;
  }
  // from me.  let me know alarm when off
  alarmWentOff = 1;
} 

这是我设置处理程序的通用代码:

typedef void InfoHandler(int, siginfo_t *, void *);

InfoHandler*
SignalWithInfo(int signum, InfoHandler* handler)
{
  struct sigaction action, old_action;

  memset(&action, 0, sizeof(struct sigaction));
  action.sa_sigaction = handler;  
  sigemptyset(&action.sa_mask); /* block sigs of type being handled */
  action.sa_flags = SA_RESTART|SA_SIGINFO; /* restart syscalls if possible */

  if (sigaction(signum, &action, &old_action) < 0)
perror("Signal error");
  return (old_action.sa_sigaction);
}

最后,针对这个特定案例:

SignalWithInfo(SIGALRM, handler);  

2
不要使用signal(),它已经过时了。如果你有它,请使用sigaction()代替,它提供了一个接口来获取发送者的进程ID。

1
它不会捕获SIGKILL和SIGSTOP信号。例如,如果你从第二个进程按下Ctrl+C,它不会被sigaction()函数捕获。 - P.P
没问题,我该如何使用sigaction()来捕获它呢? - Chris
@Chris:对于sigaction()的示例以及信号处理方面的一些复习,可以看看我之前写的这篇文章 - user405725

-1

现在已经改变了。信号信息显示的不是1个pid,而是一个简单的数字。这符合killall进程的要求。也许,当你找到/proc/DIGIT时,可以枚举/proc/目录,打开/proc/DIGIT/comm文件,读取并关闭它。也许,获取到的名称将是"shutdown"或"reboot"。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接