Сервер и несколько клиентов, использующих pthreads и select()

Рассмотрим следующий кусок кода -

int get_ready_connection(int s) {
    /* socket of connection */
    int caller;
    if ((caller = accept(s,NULL,NULL)) < SUCCESS)
    {
        server_log->write_to_log(sys_call_error(SERVER, "accept"));
        return FAILURE;
    }

    return caller;
}


int establish_connection(sockaddr_in& connection_info)
{
    // Create socket
    if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < SUCCESS)
    {
        server_log->write_to_log(sys_call_error(SERVER, "socket"));
        return FAILURE;
    }

    // Bind `sock` with given addresses
    if (bind(server_sock, (struct sockaddr *) &connection_info, \
             sizeof(struct sockaddr_in)) < SUCCESS)
    {
        close(server_sock);
        server_log->write_to_log(sys_call_error(SERVER, "bind"));
        return FAILURE;
    }

    // Max # of queued connects
    if (listen(server_sock, MAX_PENDING_CONNECTIONS) < SUCCESS)
    {
        server_log->write_to_log(sys_call_error(SERVER, "listen"));
        return FAILURE;
    }

    // Create a set of file descriptors and empty it.
    fd_set set;
    bool is_inside;
    int ret_val;

    while(true)
    {
        FD_ZERO(&set);

        FD_SET(STDIN_FILENO, &set);
        FD_SET(server_sock, &set);

        struct timeval tv = {2, 0};

        ret_val = select(server_sock + 1, &set, NULL, NULL, &tv); // TODO ret_val

        is_inside = FD_ISSET(STDIN_FILENO, &set);
        if(is_inside)
        {
            // get user input
            string user_input;
            getline(cin, user_input);

            if ((strcasecmp(user_input.c_str(), EXIT_TEXT) == 0))
            {
                return SUCCESS;
            }
        }

        is_inside = FD_ISSET(server_sock, &set);
        if(is_inside)
        {
            // get the first connection request
            int current_connection = get_ready_connection(server_sock);
            if (current_connection == FAILURE) {
                free_allocated_memory();
                exit_write_close(server_log, sys_call_error(SERVER, "accept"),
                                 ERROR);
            }

            // if exit was not typed by the server's stdin, process the request
            pthread_t thread;

            // create thread
            if (pthread_create(&thread, NULL, command_thread_func, &current_connection) != 0)
            {
                free_allocated_memory();
                exit_write_close(server_log, sys_call_error(SERVER, "pthread_create"), ERROR);
            }
        }
    }
}

Все, что я пытаюсь сделать, это "прослушать" STDIN, чтобы пользователь набрал "EXIT" в оболочке сервера, и дождаться, пока клиенты передадут команды из своих оболочек (каждый раз, когда сервер получает команду от пользователя, сервер анализирует его, а сервер создает поток, который обрабатывает выполнение команды.) Для одновременного выполнения этой задачи я использовал select().

Когда я работаю с одной нитью, все идеально. Но проблема в том, что когда я подключаю другого клиента, я получаю ошибку сегмента. Я подозреваю, что проблема здесь. какие-либо предложения?

1 ответ

Решение

Трудно понять, если это именно ваша проблема, но это определенно проблема:

Ты не можешь позвонить pthread_create и предоставить указатель на переменную стека (&current_connection) в качестве аргумента вашей функции потока. С одной стороны, он подлежит немедленному уничтожению, как только родитель выходит из этой области.

Во-вторых, он будет перезаписан при следующем вызове get_ready_connection,

Другие вопросы по тегам