在C语言中的系统调用:信号与进程复制

3

嗨,我需要使用C语言编写一个功能程序来解决这个问题。

“编写一个C程序,在该程序中进程F创建一个子进程C。子进程C等待用户输入密码,如果密码正确,则向父进程发送SIGUSR1信号;如果在3次尝试后密码仍然不正确,则向父进程发送SIGUSR2信号并终止;如果它从父进程接收到SIGUSR1信号,则必须停止查看“超时”消息。

30秒后,父进程(如果没有从子进程接收到任何信号)必须向子进程发送SIGUSR1信号并以exit(1)结束;如果它收到SIGUSR1信号,则必须以exit(0)结束;如果它收到SIGUSR2信号,则必须以exit(2)结束。”

我正在尝试解决它,但我陷入了困境。这是我已经完成的:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>

void fatherprocess(int mysignal){
    if (mysignal == SIGUSR1) {
        printf("ACCESS GRANTED!\n");
        exit(0);
    }

    if (mysignal == SIGUSR2){
        printf("ACCESS DISCARDED! More than 3 tentatives!\n");
        exit(2);
    }

}


void childprocess(int mysignal){
    if (mysignal == SIGUSR1) {
        printf("TIMEOUT\n");
        exit(1);
    }
}


int main(int argc, char *argcv[]){
    int fatherpid, childpid;
    char enteredpassword[], password[] = "test";
    int i =0;
    unsigned int time_to_sleep = 30;

   fatherpid = getpid();
   childpid = fork();

   if (childpid == 0) {
       printf("Child Process waiting for a password\n");
       while (1){
           if (i < 3) {
               printf("Enter Password: ");
               scanf("%s", enteredpassword);
               if (enteredpassword == password)
                   signal(SIGUSR1, fatherprocess);
           } else {
               signal(SIGUSR2, fatherprocess);
               exit(1);
           }
          i++;
      }
    } else {
        printf("Father Process\n");
        while(time_to_sleep){
            time_to_sleep = sleep(time_to_sleep);
            signal(SIGUSR1, childprocess);
        }
    }
    return 0;
    }

我已按照以下方式编辑了我的程序:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>

void fatherprocess(int mysignal, int fatherpid){
    if (mysignal == SIGUSR1) {
        printf("ACCESS GRANTED!\n");
        kill(fatherpid, SIGUSR1);
        exit(0);
    }

    if (mysignal == SIGUSR2){
        printf("ACCESS DISCARDED! More than 3 tentatives!\n");
        kill(fatherpid, SIGUSR2);
        exit(2);
    }

}


void childprocess(int mysignal, int childpid){
    if (mysignal == SIGUSR1) {
        printf("TIMEOUT\n");
        kill(childpid, SIGUSR1);
        exit(1);
    }
}


int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[] = "test", password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;

fatherpid = getpid();
childpid = fork();

if (childpid == 0) {
    printf("Child Process waiting for a password\n");
    while (1){
        if (i < 3) {
            printf("Enter Password: ");
            scanf("%s", enteredpassword);
            if (strcmp(enteredpassword, password) == 0)
                fatherprocess(SIGUSR1, fatherpid);
        } else {
            fatherprocess(SIGUSR2, fatherpid);
            exit(1);
        }
        i++;
    }
} else {
    printf("Father Process\n");
    while(time_to_sleep){
        time_to_sleep = sleep(time_to_sleep);
        childprocess(SIGUSR1, childpid);
    }
}
return 0;
}

现在它运行得很好,但我不知道是否符合练习文本的要求。

这是完整的代码吗?您还没有安装信号处理程序。 - Nish
这不完整,因为我不知道如何设置信号处理程序 :( 你能帮我吗? - Dave
我需要使用kill系统调用而不是signal吗? - Dave
是的,你需要使用 kill() 系统调用。你还需要使用 sigaction()(首选)或 signal()(次选)来处理信号。由于你没有调用 sigaction()signal() 中的任何一个,所以你的代码不是自证正确的。 - Jonathan Leffler
正如您所看到的,我在第一个代码块中尝试调用signal(),但似乎它从未调用那些处理程序,我不知道为什么。因此,唯一有效的策略是在第二个代码块中,但正如您所说,这并不是显然正确的。 - Dave
有什么建议吗?我该怎么办? - Dave
1个回答

1

正如Jonathan Leffler在评论中提到的那样,您需要使用kill()系统调用(发送信号)并使用类似于sigaction()的调用注册一个信号处理程序。我已经链接了这两个调用到提供有关它们的附加信息的在线手册页面。

以下是演示如何使用这些内容来实现您所述目标的一些代码。您仍需要添加/修改代码以满足您想要的提示和可接受的输入字符串等内容。请注意,我不是声称这是最好的方法,只是它可以作为示例来说明如何完成(对我来说编译并工作):

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

static void get_password(char* buf, int maxbuf)
{
    fgets(buf, maxbuf, stdin);
}

static int is_password_correct(char* buf)
{
    return buf[0] == 'a';
}

volatile int got_signal = 0;
volatile int child_signal = 0;

static void parent_sig_handler(int signum)
{
    if (!got_signal)
    {
        got_signal = signum;
        printf("parent_sig_handler: got sig %d\n", signum);
    }
}

static void child_sig_handler(int signum)
{
    if (!child_signal)
    {
        child_signal = signum;
        printf("child_sig_handler: got sig %d\n", signum);
    }
}

int main()
{
    struct sigaction act;
    sigfillset(&act.sa_mask);
    act.sa_handler = parent_sig_handler;
    sigaction(SIGALRM, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);

    pid_t child_pid = fork();
    if (child_pid == -1)
    {
        perror("error forking");
        exit(3);
    }
    if (child_pid == 0)
    {
        printf("child running\n");
        act.sa_handler = child_sig_handler;
        sigaction(SIGUSR1, &act, NULL);
        pid_t parent_pid = getppid();
        for (int i = 0; i < 3; ++i)
        {   
            char passwd[64];
            passwd[0] = '\0';
            get_password(passwd, sizeof(passwd));
            if (is_password_correct(passwd))
            {       
                kill(parent_pid, SIGUSR1);
                exit(0);    
            }       
        }   
        kill(parent_pid, SIGUSR2);
        exit(2);
    }

    printf("parent running\n");
    alarm(30); /* sets parent up to receive a SIGALRM signal in 30 seconds */
    sigset_t sigmask;
    sigemptyset(&sigmask);
    while (!got_signal)
    {
        sigsuspend(&sigmask);
    }

    switch (got_signal)
    {
        case SIGALRM:
            kill(child_pid, SIGUSR1);
            exit(1);
        case SIGUSR1:
            exit(0);
        case SIGUSR2:
            exit(2);
        default:
            exit(3);
    }
    exit(3);
}

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