一些信号没有被 sigaction C 捕获

Some signals are not getting caught by sigaction C

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

我们将首先启动服务器,然后是客户端(带参数 ./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

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

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

I don't want to wait too much because that makes my program too slow

,有道理问

is there a way to put signals in "queue" so that when I want to send multiple signals in a loop, there is no need to wait between each one?

。但实际上没有,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() 同步接收信号,而不是通过异步接收信号信号处理程序。

也许尝试来回发送信号。

例如:

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

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