【问题标题】:Some signals are not getting caught by sigaction C一些信号没有被 sigaction C 捕获
【发布时间】:2021-07-10 22:36:45
【问题描述】:

我正在尝试编写一个程序,使用服务器和客户端这两个进程来模拟服务器和客户端之间的通信:

我们将首先启动服务器,然后启动客户端(带有参数./client [SERVER PID] [Message]),我被允许仅使用 UNIX 信号向服务器发送字符串消息,所以我使用两个信号 SIGUSR1SIGUSR2以二进制形式发送字符的值,然后在服务器中将其转换回 char 并显示:所以这是我客户端的代码:

#include <minitalk_client.h>

void    send_message_to_server(pid_t ppid, const unsigned char *msg)
{
    unsigned char   mask;
    int             i;

    ft_putstr("Sending message `");
    ft_putstr((const char *)msg);
    ft_putstr("` to server: ");
    ft_putnbr(ppid);
    ft_putchar('\n');
    while (*msg)
    {
        mask = 1 << 7;
        while (mask)
        {
            if (*msg & mask)
                kill(ppid, SIGUSR1);
            else
                kill(ppid, SIGUSR2);
            usleep(300);
            mask >>= 1;
        }
        msg++;
    }
    i = -1;
    while (++i < 8)
    {
        kill(ppid, SIGUSR2);
        usleep(300);
    }
}

int main(int argc, char **argv)
{
    int ppid;

    if (argc != 3)
    {
        write(2, "Invalid arguments\n", 18);
        return (1);
    }
    ppid = ft_atoi(argv[1]);
    send_message_to_server(ppid, (const unsigned char *)argv[2]);
    return (0);
}

和服务器:

#include <minitalk_server.h>

void    sig_handler(int sig)
{
    static unsigned char    character;
    static unsigned char    mask = 1 << 7;
    static bool             is_new_message = true;

    if (is_new_message)
    {
        ft_putstr("Received message from client: ");
        is_new_message = false;
    }
    if (sig == SIGUSR1)
        character |= mask;
    mask >>= 1;
    if (!mask)
    {
        if (character)
            ft_putchar(character);
        else
        {
            ft_putchar('\n');
            is_new_message = true;
        }
        character = 0;
        mask = 1 << 7;
    }
}

int main(void)
{
    struct sigaction    act;
    const pid_t         pid = getpid();

    sigemptyset(&act.sa_mask);
    act.sa_handler = sig_handler;

    sigaction(SIGUSR1, &act, 0);
    sigaction(SIGUSR2, &act, 0);
    ft_putstr("Started minitalk server with pid: ");
    ft_putnbr(pid);
    ft_putchar('\n');
    while (1)
        pause();
    return (0);
}

所以我的代码有效,但是当我没有等待足够的时间时,sleep 出现问题,一些信号没有被捕获,它会执行以下操作:

Suspendisse consectetur consequaa�@������\@����@����@��������@�����\@��������@������@����@��@���������@������\@�����@���@������@���������X

我不想等待太多,因为这会使我的程序太慢,所以有没有办法将信号放入“队列”中,这样​​当我想在一个循环中发送多个信号时,就不需要了在每个人之间等待?

(我知道信号不是最好的方法,但这是一个学校项目,我只能这样做)

【问题讨论】:

  • 有些信号可以排队,但 SIGUSR1 和 SIGUSR2 不在其中。选择信号有什么灵活性?如果这是家庭作业,请编辑您的问题以包含任何限制条件,以便我们避开您无法使用的建议。
  • 信号是错误的机制——你想使用管道或套接字
  • @Mark Plotnick 确实是一个学校项目,我只能使用 SIGUSR1 和 SIGUSR2 在进程之间进行通信

标签: c signals


【解决方案1】:

自从

我不想等待太多,因为这会让我的程序太慢

,问有道理

有没有办法将信号放入“队列”中,这样​​当我想在一个循环中发送多个信号时,每个信号之间就不需要等待了?

。但实际上没有,SIGUSR1SIGUSR2等普通信号不排队。因此,您不仅一次最多只能有一个待处理,而且如果您同时有一个SIGUSR1 和一个SIGUSR2 待处理,那么它们的交付顺序是未指定的,并且可能与客户提出它们的顺序不同。

但可能还有另一种方法可以加快交互速度并使其更可靠,同时仍仅依靠信号进行通信。通过在注册处理程序时设置SA_SIGINFO 标志,您可以使用接受三个参数的处理程序,第二个是指向siginfo_t 的指针,该结构包含有关信号的信息。该信息包括发送它的进程的 PID。您可以使用它来使服务器能够通过将信号发送回客户端来确认收到每个信号。然后,客户端将等待每个信号的确认,然后再发送下一个信号。

服务器会按照以下方式做一些事情:

void sig_handler(int sig, siginfo_t *info, void *ignore) {
    // ...

    kill(info->si_pid, SIGUSR1);
}

int main(void) {
    struct sigaction act = { .sa_sigaction = sig_handler, .flags = SA_SIGINFO };

    sigemptyset(&act.sa_mask);
    sigaction(SIGUSR1, &act, 0);
    sigaction(SIGUSR2, &act, 0);

    // ...
}

如果您想追求这一点,那么我将客户端修改留给您,但我建议您考虑(至少)通过sigwait() 同步接收信号,而不是通过信号处理程序异步接收信号。

【讨论】:

    【解决方案2】:

    也许尝试来回发送信号。

    例如:

    • 服务器等待来自客户端的信号
    • 客户端发送信号然后等待服务器确认
    • 服务器收到信号后发送确认信号
    • 然后通信开始,您逐位发送消息,每个位都从服务器发送确认,然后再继续(使用与上述相同的机制)
    • 消息发送后,客户端发送一个不同的信号,告诉服务器消息结束

    不要忘记使用掩码使信号挂起,以防止服务器和客户端无限期地等待对方。

    【讨论】:

      猜你喜欢
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多