select用法


有时候需要同时监听标准输入,或者是多个套接字,而且不想使用多进程或者多线程的话,那么select是一个不错的选择。步骤大概是FD_ZERO重置fd_set,然后使用FD_SET挨个设置所有的描述符(文件或者是套接字)。调用select同时监听所有的描述符,这里可以通过参数TIMEOUT设置一下返回的时间,使得在没有消息来临时能够阻塞一段时间,而不是立即返回,节约CPU资源。然后通过FD_ISSET挨个判断是来自哪个描述符的消息,并作出特定的处理。

fd_set hset;
do
{
    FD_ZERO(&hset);
    //设置全部的fd
    FD_SET(listenfd, &hset);
    //遍历clients
    dplist_node_t *node = dpl_get_first_reference(clients);
    maxSock = listenfd;
    time_t cur = time(NULL);
    while (node != NULL)
    {
        sensor_data_t *data = (sensor_data_t *)get_element(node);
        tcp_get_sd(data->sock, &fd);
        node = dpl_get_next_reference(clients, node);
        if(cur - data->ts > TIMEOUT)
        {
            tcp_close(&data->sock);
            dpl_remove_element(clients, (void*)data, true);
            continue;
        }
        FD_SET(fd, &hset);
        node = dpl_get_next_reference(clients, node);
        maxSock = max(fd, maxSock);
    }
    if(dpl_size(clients) == 0)
    {
        if(cur - last_ative > TIMEOUT)
            break;
    }
    int nret = select(maxSock + 1, &hset, NULL, NULL, &tv);
    if(nret < 0)
    {
        printf("Select Error!\n");
        continue;
    }
    if (0 == nret)
    {
        continue;
    }
    if (FD_ISSET(listenfd, &hset))
    {
        //create an sensor_node
        sensor_data_t *new_sensor_node = malloc(sizeof(sensor_data_t));
        memset(new_sensor_node, 0, sizeof(sensor_data_t));
        new_sensor_node->ts =cur;
        if (tcp_wait_for_connection(listener, &new_sensor_node->sock) != TCP_NO_ERROR)
            exit(EXIT_FAILURE);
        dpl_insert_at_index(clients, new_sensor_node, -1, true); //sensor的数据用于给list加入新node 

        printf("Incoming client connection\n");
        tcp_get_sd(new_sensor_node->sock, &fd);
        maxSock = max(fd, maxSock);
        last_ative = cur;
    }
    else
    {
        dplist_node_t *node = dpl_get_first_reference(clients);
        while(node != NULL)
        {
            sensor_data_t *data = (sensor_data_t*)get_element(node);
            tcp_get_sd(data->sock, &fd);
            if (FD_ISSET(fd, &hset))
            {
                connmgr_process(data);
                break;
            }
            node = dpl_get_next_reference(clients, node);
        }
        last_ative = cur;
    }
} while (true);

Author: 蒋璋
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 蒋璋 !