execl не работает в цикле while (1) на стороне сервера; Сценарий - PullRequest
2 голосов
/ 30 апреля 2010

У меня проблема с небольшим C-скриптом, который должен работать как сервер и запускать всплывающее окно для каждого приходящего сообщения. Синтаксис execl правильный, потому что, если я попробую небольшой скрипт с

main() { execl(...); }

это работает.

Когда я помещаю его в цикл while (1), он не работает. Все остальное работает, как printf или строковая операция, но не execl. Даже если я разветвлюсь, это не сработает. Как я могу заставить это работать?

И я попробовал с fork(), но он тоже не работает.

Вот полный код сервера C.

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>

#define BUFLEN 512
#define PORT 9930

void diep(char *s) {
     perror(s);
     exit(1);
}

int main() {
    struct sockaddr_in si_me, si_other;
    int s, i, slen=sizeof(si_other), broadcastPermission;
    char buf[100], zeni[BUFLEN];

    if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
       diep("socket");

    broadcastPermission = 1;
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission, sizeof(broadcastPermission)) < 0)
        diep("setsockopt() failed");

    memset((char *) &si_me, 0, sizeof(si_me));
    si_me.sin_family = AF_INET;
    si_me.sin_port = htons(PORT);
    si_me.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(s, &si_me, sizeof(si_me))==-1)
       diep("bind");

    while (1) {
        if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1) diep("recvfrom()");
        //printf("Received packet from %s:%d\nData: %s\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);

 strcpy(zeni, "");
 strcat(zeni, "zenity --warning --title Hack!! --text ");
 strcat(zeni, buf);
 printf("cmd: %s\n", zeni);
 //system (zeni);
 execl("/usr/bin/zenity", "/usr/bin/zenity", "--warning", "--title", "Warn!", "--text", buf, (char *) NULL);
    }

    close(s);
    return 0;

}

Ответы [ 3 ]

3 голосов
/ 30 апреля 2010

@ jweyrich уже указал на некоторые проблемы с использованием recvfrom, однако есть более фундаментальная проблема. Код

while (1) {
    recvfrom(...);
    execl(...);
}

будет выполняться только один раз. Это связано с тем, что семейство системных вызовов exec (включая execl) заменяет программу, выполняемую в данный момент, той, которая указана в вызове execl. В действительности, execl никогда не возвращается, кроме как с ошибкой.

Чтобы создать новый дочерний процесс в unix, вы должны сначала вызвать fork, который клонирует существующий процесс, а затем внутри дочернего вызова execl (или некоторый связанный системный вызов), чтобы заменить дочерний процесс программой, которую вы на самом деле хочу бежать. Правильно сделать это вручную несколько сложно, поэтому функция system завершает это для вас, однако у нее есть свои недостатки.

2 голосов
/ 30 апреля 2010

При вызове recvfrom.

переполнение стека
recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)

Я полагаю, вы смешали 2 буфера. Вы используете buf, который имеет размер 100, но его размер равен BUFLEN, который равен 512. Всякий раз, когда кто-то отправляет более 100 байтов, очень вероятно, что ваша программа потерпит крах.

Кроме того, возможно, что recvfrom не возвращается, потому что ничего не получает. Ваша printf выполняется?


ОБНОВЛЕНИЕ: как указано @Daniel и @Dale, execl не вернется, если не произойдет ошибка. Цитата из справочной страницы:

Семейство функций exec заменяет текущий образ процесса новым образом процесса.

В качестве альтернативы вы можете использовать system.

1 голос
/ 30 апреля 2010

Пожалуйста, прочитайте справочную страницу exec (3).

В вашем случае системный вызов execl заменит изображение текущих процессов изображением /usr/bin/zenity".

У вас есть два решения: используйте system (3), как вы там пробовали, или сделайте форк, и внутри дочернего файла запустите execlp.

...