有时候需要同时监听标准输入,或者是多个套接字,而且不想使用多进程或者多线程的话,那么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);