/********************************************************************************* * Copyright: (C) 2025 LingYun IoT System Studio * All rights reserved. * * Filename: select.c * Description: This file is select example. * * Version: 1.0.0(11/06/2025) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "11/06/2025 10:33:45 AM" * ********************************************************************************/ #include #include #include #include #include int main(void) { int sockfd; struct sockaddr_in addr; fd_set readfds; int maxfd; struct timeval timeout; int ret; int reuse = 1; sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 创建套接字 */ addr.sin_family = AF_INET; addr.sin_port = htons(8888); addr.sin_addr.s_addr = INADDR_ANY; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); listen(sockfd, 5); printf("select() monitor socket[8888] and stdin now...\n"); while (1) { /* * 由于下面select系统调用中Linux内核会修改readfds集合, 所以每次进入循环都要 * 重新清除并设置要监听的文件描述符集合。 */ FD_ZERO(&readfds); /* 清除 readfds 集合 */ FD_SET(sockfd, &readfds); /* 将socket加入 readfds 集合 */ FD_SET(STDIN_FILENO, &readfds); /* 将标准输入(键盘)加入 readfds集合 */ /* 找出最大的文件描述符 */ maxfd = (sockfd > STDIN_FILENO) ? sockfd : STDIN_FILENO; /* 设置超时事件 */ timeout.tv_sec = 10; timeout.tv_usec = 0; /* 告诉Linux内核开始帮忙监听 readfds 集合里所有的文件描述符,只关心有数据可读事件 */ ret = select(maxfd + 1, &readfds, NULL, NULL, &timeout); if (ret == -1) { perror("select error"); break; } else if (ret == 0) { printf("timeout...\n"); continue; } /* * 程序走到这里说明ret>0,即监听的文件描述符中有事件发生了. Linux内核会在返回前会将 * readfds集合中没有事件发生的文件描述符清除, 那留在里面的就是有事件发生的文件描述符 */ /* 判断标准输入是否还在集合中,如果还在的话就说明键盘有输入了 */ if (FD_ISSET(STDIN_FILENO, &readfds)) { char buf[128]; read(STDIN_FILENO, buf, sizeof(buf)); printf("You typed in keyboard: %s\n", buf); } /* 判断socket是否还在集合中,如果还在的话就说明有客户端连接来了 */ if (FD_ISSET(sockfd, &readfds)) { int client = accept(sockfd, NULL, NULL); printf("Accept and close connection: %d\n", client); close(client); } } close(sockfd); return 0; }