socket () возвращает 0 в клиент-серверном приложении C - PullRequest
8 голосов
/ 25 января 2010

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

Изначально я использовал system() для выполнения этого внешнего скрипта, но мы не могли его использовать, потому что мы должны были убедиться, что сокеты сервера были закрыты в дочернем элементе, который был разветвлен для выполнения внешнего скрипта.
Теперь я сама звоню fork() и execvp(). Я fork(), а затем в дочерней системе я закрываю все сокеты сервера и затем вызываю execvp() для выполнения сценария.

Теперь все это прекрасно работает. Проблема в том, что иногда скрипт сообщает об ошибках на сервер приложения. Сценарий отправляет эти ошибки, вызывая другое приложение (клиент), которое открывает сокет TCP и отправляет соответствующие данные. Моя проблема в том, что клиентское приложение получает значение 0, возвращаемое системным вызовом socket().

ПРИМЕЧАНИЕ. Это ТОЛЬКО происходит, когда приложение-скрипт / клиент вызывается с использованием моей функции forkExec (). Если приложение скрипт / клиент вызывается вручную, вызов socket() выполняется надлежащим образом и все работает нормально.

Основываясь на этой информации, я подозреваю, что это что-то в моем коде fork () execvp () ниже ... Есть идеи?

void forkExec()
{    
    int stat;

    stat = fork();
    if (stat < 0)
    {
        printf("Error forking child: %s", strerror(errno));
    }
    else if (stat == 0)
    {
        char *progArgs[3];

        /*
         * First, close the file descriptors that the child 
         * shouldn't keep open
         */
        close(ServerFd);
        close(XMLSocket);
        close(ClientFd);
        close(EventSocket);
        close(monitorSocket);

        /* build the arguments for script */
        progArgs[0] = calloc(1, strlen("/path_to_script")+1);
        strcpy(progArgs[0], "/path_to_script");
        progArgs[1] = calloc(1, strlen(arg)+1);
        strcpy(progArgs[1], arg);
        progArgs[2] = NULL; /* Array of args must be NULL terminated for execvp() */

        /* launch the script */
        stat = execvp(progArgs[0], progArgs);
        if (stat != 0)
        {
            printf("Error executing script: '%s' '%s' : %s", progArgs[0], progArgs[1], strerror(errno));
        }
        free(progArgs[0]);
        free(progArgs[1]);
        exit(0);
    }

    return;
}

Код клиентского приложения:

static int connectToServer(void)
{
int socketFD = 0;
int status;
struct sockaddr_in address;
struct hostent* hostAddr = gethostbyname("localhost");

socketFD = socket(PF_INET, SOCK_STREAM, 0);

Вышеуказанный вызов возвращает 0.

if (socketFD < 0)
{
    fprintf(stderr, "%s-%d: Failed to create socket: %s", 
                                __func__, __LINE__, strerror(errno));
    return (-1);
}

memset(&address, 0, sizeof(struct sockaddr));
address.sin_family = AF_INET;
memcpy(&(address.sin_addr.s_addr), hostAddr->h_addr, hostAddr->h_length);
address.sin_port = htons(POLLING_SERVER_PORT);

status = connect(socketFD, (struct sockaddr *)&address, sizeof(address));
if (status < 0)
{
    if (errno != ECONNREFUSED)
    {
        fprintf(stderr, "%s-%d: Failed to connect to server socket: %s",
                   __func__, __LINE__, strerror(errno));
    }
    else
    {
        fprintf(stderr, "%s-%d: Server not yet available...%s",
                   __func__, __LINE__, strerror(errno));
        close(socketFD);
        socketFD = 0;
    }
}

return socketFD;
}

FYI
ОС: Linux
Арка: ARM32
Ядро: 2.6.26

Ответы [ 4 ]

11 голосов
/ 25 января 2010

socket () возвращает -1 при ошибке.

Возвращение 0 означает, что socket () завершился успешно и дал вам файловый дескриптор 0. Я подозреваю, что один из файловых дескрипторов, который вы закрываете, имеет файловый дескриптор 0, и как только он будет закрыт, при следующем вызове функции, выделившей файловый дескриптор верните fd 0, как это доступно.

7 голосов
/ 25 января 2010

Сокет со значением 0 в порядке, это означает, что stdin был закрыт, что сделает fd 0 доступным для повторного использования - например, сокетом.

Скорее всего, один из файловых дескрипторов, который вы закрываете в дочернем пути forkExec () (XMLSocket / ServerFd) и т. Д.), Был fd 0. Это запустит дочерний процесс с закрытым fd 0, что не произойдет, когда вы запустите приложение из командной строки, так как fd 0 уже будет открыт как stdin оболочки.

Если вы хотите, чтобы ваш сокет не был 0,1 или 2 (stdin / out / err), после всех вызовов close () вызовите следующее в вашей функции forkExec ()

void reserve_tty()
{
  int fd;

  for(fd=0; fd < 3; fd++)
    int nfd;
    nfd = open("/dev/null", O_RDWR);

    if(nfd<0) /* We're screwed. */
    continue;

    if(nfd==fd)
    continue;

    dup2(nfd, fd);
    if(nfd > 2)
     close(nfd);

}

Проверка возврата сокета -1, что означает, что произошла ошибка.

1 голос
/ 25 января 2010

Не забудьте позвонить на

waitpid()

Конец «режима очевидного вопроса». Я предполагаю немного здесь, но вы ничего не делаете с pid, возвращаемым вызовом fork (). (-:

0 голосов
/ 02 ноября 2016

Как уже упоминалось в другом комментарии, вы действительно не должны закрывать 0,1 или 2 (stdin / out / err), вы можете поставить проверку, чтобы убедиться, что вы не закрываете их, и поэтому он не будет назначен как новые fd`s при запросе нового сокета

...