【问题标题】:Server receiving and showing string from client using signals SIGUSR1 and SIGUSR2 can't handle with big amount of symbols服务器使用信号 SIGUSR1 和 SIGUSR2 从客户端接收和显示字符串无法处理大量符号
【发布时间】:2021-12-25 01:11:50
【问题描述】:

我有一个学校的任务,我需要编写一个客户端,它将使用信号(仅 SIGUSR1 为 1 或 SIGUSR2 为 0)向服务器发送字符串,然后服务器应显示该字符串。问题是服务器通常只能处理少量的符号。在其他情况下,它会在客户端暂停或仅显示奇怪的符号。我尝试使用客户端中的全局变量以不同的方式编写以从服务器确认(有和没有暂停客户端),使用usleep()(100/600/1000/10000),使用pause(),结果总是就像我一次又一次快速呼叫客户时一样。

我正在使用 VirtualBox Ubuntu 编写它。

UPD:问题解决了在客户端使用sleep (5)而不是pause()并将usleep()增加到1000

客户:

#include "minitalk.h"

int g_recieve;

void    sending_bits(char c, int pid)
{
    int i;

    i = 128;
    while(i >= 1)
    {
        if (g_recieve == 1)
        {
            if (i & c)
            {
                if (kill(pid, SIGUSR1) == -1)
                    errors("Error in sending signal!\n");
            }
            else
            {
                if (kill(pid, SIGUSR2) == -1)
                    errors("Error in sending signal!\n");
            }
            i /= 2;
            g_recieve = 0;
        }
        //usleep(600);
    }
}


int send_str(int pid, char *s)
{
    int i;

    i = 0;
    while (s[i])
    {
        sending_bits(s[i], pid);
        i++;
    }
    return (0);
}

void    cl_handler(int signum, siginfo_t *siginfo, void *context)
{
    (void)context;
    (void)siginfo;
    (void)signum;
    g_recieve = 1;
    write(1, "Recieved signal from server\n", 28);
    return ;
}

int main(int argc, char **argv)
{
    struct sigaction    sigac;

    g_recieve = 1;
    sigemptyset(&sigac.sa_mask);
    sigaddset(&sigac.sa_mask, SIGINT);
    sigaddset(&sigac.sa_mask, SIGQUIT);
    sigaddset(&sigac.sa_mask, SIGUSR1);
    sigac.sa_flags = SA_SIGINFO;
    sigac.sa_sigaction = cl_handler;
    if (sigaction(SIGUSR2, &sigac, NULL) == -1)
        errors("Error in client sigaction\n");
    if (ft_atoi(argv[1]) < 0)
        errors("Wrong PID!\n");
    if (argc == 3)
        send_str(ft_atoi(argv[1]), argv[2]);
    else
        errors("Wrong arguments!\n");
    while (1)
        pause ();
    return (0);
}

服务器:

#include "minitalk.h"

void    sv_handler(int signum, siginfo_t *siginfo, void *unused)
{
    static int  ascii = 0;
    static int  power = 0;

    (void)unused;
    if (signum == SIGUSR1)
        ascii += (128 >> power);
    power += 1;
    if (power == 8)
    {
        ft_putchar(ascii);
        power = 0;
        ascii = 0;
    }
    if (siginfo->si_pid == 0)
        errors("Server didn't get client's PID\n");
    if (kill(siginfo->si_pid, SIGUSR2) == -1)
        errors("Error in returning signal!\n");
}

int main(int argc, char **argv)
{
    struct sigaction    sigac;

    (void)argv;
    if (argc != 1)
        errors("Error arguments\n");
    write(1, "Server started!\nPID: ", 21);
    ft_putnbr(getpid());
    write(1, "\n", 1);
    sigemptyset(&sigac.sa_mask);
    //sigaddset(&sigac.sa_mask, SIGINT);
    //sigaddset(&sigac.sa_mask, SIGQUIT);
    sigac.sa_flags = SA_SIGINFO;
    sigac.sa_sigaction = sv_handler;
    if ((sigaction(SIGUSR1, &sigac, 0)) == -1)
        errors("Error sigaction\n");
    if ((sigaction(SIGUSR2, &sigac, 0)) == -1)
        errors("Error sigaction\n");
    while (1)
        pause();
    return (0);
}

【问题讨论】:

  • 你的导师非常刻意地预先考虑到恶意,给你分配了一项道德上相当于用锤子拧螺丝的任务。信号用于事件,而不用于数据。当您尝试发送大量信号时,您总是会遇到可怕的问题,因为它们不能很好地排队,因为它们从来都不是为 IPC 设计的。
  • @SteveSummit 是对的:信号非常非常不适合这个问题。 “快速调用客户端一次又一次”是什么意思?您的意思是您多次调用客户端程序,同时或重叠,每次都使用相同的服务器 PID 作为其目标?如果没有客户之间的某种协调,这将是行不通的。
  • @Shawn 感谢您花时间挖掘链接。但是,[我相信你已经知道]它充满了竞争条件。发件人usleep 可以与收件人竞争。不能保证发送者不会发送(例如)两个 SIGUSR1,被接收者视为单个 SIGUSR1。或者,这两个信号是按顺序传递的。在接收器中,它至少需要volatile 和/或原子处理程序/主同步。回复:man7.org/linux/man-pages/man7/signal.7.html 具有讽刺意味的是,如果使用 Posix/RT 信号,它们保证排队并按顺序传递。
  • @CraigEstey 是的,这很糟糕。在问题的约束范围内没有好的方法。

标签: c linux unix signals sigaction


【解决方案1】:

在客户端中使用sleep(5) 而不是pause() 解决了问题,并将客户端中的usleep() 增加到1000。

【讨论】:

    猜你喜欢
    • 2021-12-01
    • 1970-01-01
    • 2021-11-06
    • 2011-09-17
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    相关资源
    最近更新 更多