2014-09-07 2 views
0

Я начинающий программист, и я разрабатываю клиентскую серверную программу в Ubuntu. Этот код принадлежит моему файлу server, и я хочу реализовать сигнал SIGALRM, но я просто не знаю, как я могу это сделать правильно. Моя цель: в той части кода, что я вызываю сигнал alarm(ans.game_time), я хочу запустить эту функцию Time, и эта функция должна ждать ans.game_time секунд, и в течение этих секунд игроки должны присоединиться к игре (последняя часть еще не реализована, команда «играть»).Реализация SIGALRM

Estructures:

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); 
} 

Я пытался понять, как он работает правильно, но этот сигнал действительно запутанным для меня.

+1

Read [Сигнал (7)] (http://man7.org/linux/man-pages/man7 /signal.7.html) и [poll (2)] (http://man7.org/linux/man-pages/man2/poll.2.html). Вероятно, вы хотите «опросить». См. Также [Расширенное программирование на Linux] (http://advancedlinuxprogramming.com/) –

+1

Как следует из @BasileStarynkevitch, вы не должны использовать сигналы для этого вообще. Правильное использование сигналов не является задачей для начинающего программиста, и это не должно требоваться для большинства приложений. –

+0

@BasileStarynkevitch Мне действительно нужно использовать сигналы в этой части кода, мой профессор сказал, что это обязательно. –

ответ

2

Когда сигнал ALARM (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 */ 
} 
+0

FYI, * volatile * означает, что переменная может быть изменена вне нормального потока программы - она ​​в основном сообщает компилятору, что некоторые оптимизации будут неправильными, поскольку его предположения могут быть неправильными. И * sig_atomic_t * - это целое число размера/выравнивания, которое гарантирует систему, может быть обновлено * «атомарно» (все сразу), чтобы его нельзя было увидеть частично обновленным. –

+0

О, я не думал об этом так! Спасибо за то, что это будет действительно полезно! –

3

alarm() не является хорошим способом реализации периодических событий на сервере. Он функционирует как асинхронный сигнал и, как таковой, обрабатывается надлежащим образом, пока что-то еще происходит. Например, если ваш сервер находится в середине отправки сообщения клиенту, то при выключении будильника и при запуске генерации выход будет скорее всего нарушить сообщение. Итог - это не правильный путь.

Большинство клиентских/серверных приложений используют системные вызовы select() или poll(). Эти системные вызовы позволяют вашему приложению ждать появления события (например, прихода данных) на любое количество файловых дескрипторов с дополнительным тайм-аутом. Таким образом, большинство серверных приложений обрабатывают соединения с несколькими клиентами одновременно.

Использование этих системных вызовов, вероятно, потребует от вас реструктурировать приложение вокруг модели «конечного автомата», а не использовать поток программы для представления состояния. Объяснение того, как сделать это эффективно, - это более сложная задача, чем разумная для такого короткого ответа; подготовитесь к некоторым исследованиям!

+0

Здравствуйте. Спасибо заранее за подсказку, но мне действительно нужно использовать сигналы для выполнения этой части программы. В цикле 'do {} while' я не показываю каждый код, я читаю и пишу серверным клиентам много раз, и я просто не могу остановиться в одной функции и оставить все клиенты ждут. Я думаю, что это причина того, что мне нужно использовать сигналы, одновременно делать две вещи, и, кроме того, мой профессор просит использовать сигналы в этой части. –

+0

Если вы пишете эту программу как часть задания класса, обратитесь за поддержкой к своему профессору. Пока вы на это ... пожалуйста, направить его на этот ответ с напоминанием о том, что многие системные вызовы и библиотечные функции ** не ** безопасны для использования в обработчиках сигналов. – duskwuff

Смежные вопросы