1

我必须在两个不同的终端上运行进程(服务器和客户端)。客户端读取用户输入,将其保存到文件(hello.txt),发出 SIGUSR1 信号,然后休眠。服务器然后唤醒,读取文件(hello.txt),打印它,向客户端发出信号它工作,然后休眠。客户端然后唤醒,打印成功,然后等待另一个用户输入。

稍后还有更多内容,但这就是我目前想要完成的全部。我很难在两个独立的、不相关的进程之间找到使用 sigaction 和 SIGUSR1 的示例。这是我到目前为止的代码:

服务器.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

volatile sig_atomic_t myFlag = 0;
static void myHandler(int);
struct sigaction newAction, oldAction;


int main(int argc, char* argv[])
{
    //setup signal stuff
    sigset_t zeromask;
    sigemptyset(&newAction.sa_mask);
    sigemptyset (&oldAction.sa_mask);
    sigemptyset(&zeromask);
    newAction.sa_flags = 0;
    newAction.sa_handler = myHandler;
    sigaddset (&newAction.sa_mask, SIGUSR1);
    if ( sigaction(SIGUSR1, &newAction, &oldAction))
            return;

    for ( ; ; ) {
            //Loop
            //This is so I can manually enter the pid into the client 
            printf("%d\n",getpid());
            while(myFlag == 0)
                    sigsuspend (&zeromask);
            myFlag = 0;
            printf("Got signal, process it\n");

    //signal occured process it
    }

    sigprocmask (SIG_SETMASK, &oldAction.sa_mask, NULL);
    exit(0);
    }

static void myHandler(int sigNo) {
    myFlag = 1;

    printf("finally made it");
    sigprocmask (SIG_BLOCK, &newAction.sa_mask, &oldAction.sa_mask);
    return;
}

客户端.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

volatile sig_atomic_t myFlag = 0;
static void myHandler(int);
struct sigaction newAction, oldAction;


int main(int argc, char* argv[])
{
    printf("begin\n");
    //Signal stuff 
    sigset_t zeromask;
    sigemptyset(&newAction.sa_mask);
    newAction.sa_flags = 0;
    newAction.sa_handler = myHandler;
    sigemptyset (&oldAction.sa_mask);
    sigemptyset(&zeromask);
    sigaddset (&newAction.sa_mask, SIGUSR1);
    if ( sigaction(SIGUSR1, &newAction, &oldAction))
            return;
    sigprocmask (SIG_BLOCK, &newAction.sa_mask, &oldAction.sa_mask);

    //loop
    for ( ; ; ) {
            printf("This is where you would get user input\n");
            //Signal Server
            //For now I just manually enter the pid that was printed out when I ran server.c. This does not work and I do not think it is the right thing to do 
            kill(27514,SIGUSR1);
            //loop while waiting for server to respond
            while(myFlag == 0)
                    sigsuspend (&zeromask);

            myFlag = 0;
            printf("this is where you would process return signal\n");
    //signal occured process it
    }

    sigprocmask (SIG_SETMASK, &oldAction.sa_mask, NULL);
    exit(0);
    }

    static void myHandler(int sigNo) {
          myFlag = 1;
          sigprocmask (SIG_BLOCK, &newAction.sa_mask, &oldAction.sa_mask);
          return;
    }

现在,所有这些代码应该做的就是从客户端向服务器发送信号。从那里我将实施其余的。但是,这不起作用,我似乎无法弄清楚。

kill 是用来实现 SIGUSR1 的正确命令吗?我是否需要知道每个客户端和服务器的 PID 才能进行通信?我完全只是在做错事吗?

4

2 回答 2

2

您尚未说明实际发生的情况,但要回答您的问题:

“kill 是用来执行 SIGUSR1 的正确命令吗?” 是的。

“我是否需要知道每个客户端和服务器的 PID 才能进行通信?” 是的。

“我完全只是在做错事吗?” 是的。

使用信号的主要问题是 1)它在程序执行的任何时候到达,2)你只准备在特定时间处理它。

您上面的代码只有在信号恰好在 sigsuspend() 中等待时才会正确处理它。这不是每时每刻都是真的!当您处于循环的其他部分时,即当您向另一个进程发送 kill() 时,请考虑如果另一个进程 kill() 在您再次到达 sigsuspend 之前返回会发生什么......您赢了不要等待信号,它会来来去去。您的实现不可靠。

更可靠的实现是在进程之间使用套接字连接;您可以通过这种连接传递信号甚至数据本身。事实上,有很多方法可以做到这一点,请参阅http://en.wikipedia.org/wiki/Inter-process_communication(您似乎正在使用上面的 POSIX 接口)。

结果是信号是异步的,会中断任何程序的流程,并且特定于您的程序,您并不总是为它做好准备,如果您错过它,它就消失了。使用套接字(或管道或其他具有实际文件描述符的东西),数据(您的信号)将导致 select() 或 poll() 返回,而不仅仅是飞过。

于 2013-02-19T20:57:02.007 回答
0

这确实不是客户端和服务器之间通信的最佳方式。您应该查看命名管道。

您的主要问题是myFlag客户端和服务器之间不共享。两个程序在独立内存中运行;如果您想以这种方式进行交流,则需要使用共享内存。(这将是命名管道的另一种选择。)

正如您所指出的,另一个问题是客户端没有简单的方法来发现服务器的 pid。确实没有一个好的方法可以做到这一点,尽管服务器可以将其 pid 存储在具有已知名称的文件中(许多这样做是为了使管理任务更容易),但这会产生许多可能比赛条件;无论如何,它都不是一个可靠的机制。同样,命名管道(或命名共享内存段)为同一主机上的进程之间的进程间通信提供了可靠的机制。

如果客户端和服务器可能在不同的机器上运行——一个非常常见的用例——你可能想要使用套接字,它也适用于单个主机。

于 2013-02-19T20:53:00.100 回答