/********************************************************************************* * Copyright: (C) 2025 LingYun IoT System Studio * All rights reserved. * * Filename: socketd_select.c * Description: This file is TCP socket server(select) example program. * * Version: 1.0.0(10/20/2025) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "10/20/2025 09:48:51 PM" * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BACKLOG 13 #define MAX_FDS 1024 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) int g_stop = 0; /* program stop or not */ void sig_handler(int signum); int socket_init(int port); void print_usage(char *progname) { printf("%s usage: \n", progname); printf(" -p(--port): sepcify listen port.\n"); printf(" -h(--Help): print this help information.\n"); return ; } int main(int argc, char **argv) { int i, j; int rv = -1; int listen_fd, client_fd = -1; int port = 10086; int debug = 0; struct sockaddr_in cli_addr; socklen_t addr_len = sizeof(cli_addr); char buf[1024]; int fds_array[MAX_FDS]; int max_fd; int found; fd_set readfds; int ch; struct option opts[] = { {"debug", no_argument, NULL, 'd'}, {"port", required_argument, NULL, 'p'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; /* 解析命令行参数 */ while( (ch=getopt_long(argc, argv, "dp:h", opts, NULL)) != -1 ) { switch(ch) { case 'd': debug = 1; break; case 'p': port=atoi(optarg); break; case 'h': print_usage(argv[0]); return 0; } } /* 如果不是debug调试运行,就放到后台去运行 */ if( !debug ) daemon(0, 0); /* 安装信号 */ signal(SIGTERM, sig_handler); /* capture kill/killall signal */ signal(SIGINT, sig_handler); /* capture Ctrl+C signal */ signal(SIGSEGV, sig_handler); /* capture segmentation fault signal */ signal(SIGPIPE, sig_handler); /* capture socket error signal */ /* 创建监听套接字 */ if( (listen_fd = socket_init(port)) < 0 ) return 2; /* 将文件描述符数组中所有值设置为-1, 用来表示这个位置没有被使用 */ for(i=0; i= 0) { /* 将存在的文件描述符加入读事件集合 */ FD_SET(fds_array[i], &readfds); /* 找出所有这些文件描述符最大的值 */ max_fd = fds_array[i]>max_fd ? fds_array[i] : max_fd; } } /* select一直阻塞等待, 永不超时 */ rv=select(max_fd+1, &readfds, NULL, NULL, NULL); if( rv <= 0 ) { /* select()超时或有异常发生(如有信号到来),继续下次循环 */ printf("select failure: %s\n", strerror(errno)); continue; } /* 程序走到这里说明 rv>0, 有文件描述符发生事件了 */ /* 检查是不是 listen_fd 发生了事件,如果有说明有新的客户端连接请求到来 */ if( FD_ISSET(listen_fd, &readfds) ) { /* 接收新的客户端连接请求 */ client_fd = accept(listen_fd, (struct sockaddr*)&cli_addr, &addr_len); if(client_fd < 0) { printf("accept new socket failure: %s\n", strerror(errno)); continue; } printf("Accept new client[%s:%d] with fd [%d]\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), client_fd); /* 从文件描述符数组中找一个空位置,将新的客户端文件描述符加进去 */ found = 0; for(i=0; i