【问题标题】:SIGALRM implementationSIGALRM 实施
【发布时间】:2014-09-07 03:19:02
【问题描述】:

我是一个非常初学者的程序员,我正在开发一个客户端服务器程序,在 Ubuntu 中。这段代码属于我的serverfile,我想实现一个信号SIGALRM但我只是不知道如何正确地做到这一点。 我的目标是:在我调用信号alarm(ans.game_time)的代码部分,我想运行那个函数Time,这个函数应该等待ans.game_time秒,在这些秒内,玩家应该加入游戏(这最后一部分还没有实现,“播放”命令)。

结构:

typedef struct request req;
struct request
{
    char str[256];
    int client_pid;
    int login; // In case of client, to identify if is logged
    int whois; // To identify who is the client and the server
};

typedef struct answer ans;
struct answer
{
    char str[256];
    int server_pid;
    int type;
    int login;
    int num_users;
    char game_name[25];
    int game_time;
    int game_users[4];
};

服务器文件:

#include "header"
int array_client_PID[4], num_users = 0;
int GAME_STATUS = 0;

void Time(int sign) 
{
  signal(SIGALRM, Time);
  alarm(3);
  printf("I'm Alive");
}

int main(){

    int fifo_1,fifo_2, pid, i, number_args;
    char FIFO_CLIENT[20], command[20], arg_1[20], arg_2[20];
    struct request req;
    struct answer ans;

    signal(SIGALRM, Time);

    do{ 
        read(fifo_1, &req, sizeof(req)); // Read request

            if(req.login == 1) // USER REGISTATION: If logged
                {   
                number_args = sscanf(req.str, "%s %s %s", command, arg_1, arg_2);

                    if(strcasecmp(command, "new") == 0) 
                    {
                        if(GAME_STATUS == 0) 
                        {   
                            ans.game_time = atoi(arg_2);    // Converts the string into a integrer time game
                            strcpy(ans.game_name, arg_2);   // Put the name of the game on the structure
                            ans.game_users[0] = req.client_pid; // Put on the users avaiable to play, the name of the game creator
                            alarm(ans.game_time);           
                            //CreateGame(ans); // not implemented yet

                        }
                        else
                        {
                            strcpy(ans.str,"One game is in execution. Just wait...\n");
                        }                   

                    }

        if(GAME_STATUS== 1) // GAME STATUS: ON
        {
            printf("INSIDE GAME_STATUS 1\n");
            // Receive commands inside the game
        }
    }
    sprintf(FIFO_CLIENT, "FIFO_%d", req.client_pid); //2nd FIFO name with client PID
    fifo_2=open(FIFO_CLIENT, O_WRONLY); // Open 2nd FIFO to answer
    write(fifo_2, &ans, sizeof(ans)); // Write an answer

    }while(1);
}

我试图了解它是如何正常工作的,但这个信号让我很困惑。

【问题讨论】:

  • 阅读signal(7)poll(2)。你可能想poll。另见Advanced Linux Programming
  • 正如@BasileStarynkevitch 暗示的那样,您根本不应该为此使用信号。正确使用信号对于初学者来说不是任务,大多数应用程序都不需要它。
  • @BasileStarynkevitch 我真的需要在这部分代码中使用信号,我的教授说这是强制性的。
  • @JohnZwinck 实际上信号对我来说并不新鲜,但是这个特定的信号,很难理解它是如何工作的

标签: c linux ubuntu


【解决方案1】:

alarm() 不是在服务器中实现周期性事件的好方法。它用作异步信号,因此在发生其他事情时难以正确处理。例如,如果您的服务器正在向客户端发送消息,则警报响起并开始生成输出可能会中断消息。底线是,这不是正确的做法。

大多数客户端/服务器应用程序在其核心使用 select()poll() 系统调用。这些系统调用允许您的应用程序在任意数量的文件描述符上等待事件发生(例如,数据到达),并带有可选的超时。这是大多数服务器应用程序一次处理与多个客户端的连接的方式。

使用这些系统调用可能需要您围绕“状态机”模型重构应用程序,而不是使用程序流来表示状态。解释如何有效地做到这一点是一个比这样的简短答案合理的更大的任务;准备做一些研究!

【讨论】:

  • 你好。在此先感谢您的提示,但我确实需要使用信号来完成程序的这一部分。在do{}while 圈子中,我没有显示所有代码,我正在多次读取和写入服务器客户端,但我无法停止一个功能,让所有客户端等待。我认为这就是我需要使用信号的原因,同时做两件事,而且我的教授特别要求在这部分使用信号。
  • 如果您正在编写此程序作为课堂作业的一部分,请联系您的教授以获得支持。当你在做的时候......请指导他这个答案,并提醒他许多系统调用和库函数在信号处理程序中使用是安全的。
【解决方案2】:

当警报 (ALRM) 信号熄灭时,您很可能正在等待read(fifo_1 ...); 呼叫,但您不处理这种情况。

if (read(fifo_1, ...) == -1) {
    /* some error occurred in the read... */
    if (errno == EINTR) {
        /* error was interruption, most likely by the ALARM */
        /* handle this in whatever way is appropriate */
    }
}

几乎总是进行更多改进,最好的做法是在信号处理程序中尽可能少做 - 通常,只需设置一个表明信号发生的标志。

static volatile sig_atomic_t alarms_happened = 0;
static sig_atomic_t alarms_handled = 0;

static void Time ( int signo ) {
    if (signo == SIGALRM) alarms_happened++;
}

然后在您准备处理警报的主循环中:

if (alarms_happened != alarms_handled) {
    alarms_handled = alarms_happened;
    /* do whatever you need to do when there was an alarm */
}

【讨论】:

  • 仅供参考,volatile 意味着可以在正常程序流程之外更改变量——它基本上告诉编译器某些优化是不正确的,因为它的假设可能是错误的。而 sig_atomic_t 是系统保证可以'atomically'(一次全部更新)的大小/对齐的整数——因此它不可能被看到部分更新。
  • 哦,我没有这样想!谢谢你的时间,这将是非常有用的!
猜你喜欢
  • 1970-01-01
  • 2019-12-16
  • 2022-07-16
  • 2018-01-01
  • 1970-01-01
  • 2011-05-04
  • 2010-10-03
  • 2015-10-03
  • 2019-12-19
相关资源
最近更新 更多