服务器和多个客户端使用pthreads和select()

server and multiple clients using pthreads and select()

本文关键字:pthreads select 客户端 服务器      更新时间:2023-10-16

考虑下一个代码 -

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()。

当我使用一个线程时,一切都是完美的。但是问题是当我连接另一个客户端时,我会得到SEG错误。我怀疑问题就在这里。有任何建议吗?

很难知道这是否是您的确切问题,但这绝对是 a 问题:

您无法调用pthread_create,并提供指向堆栈变量(&current_connection)的指针作为线程函数的参数。一方面,一旦父母退出该范围,这会立即遭到破坏。

其次,它将在下一个呼叫get_ready_connection中覆盖。