Linux 网络编程九(select应用--大并发处理)
//网络编程服务端 /* * 备注:因为客户端代码、辅助方法代码和epoll相同,所以select只展示服务器端代码 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>//htons()函数头文件 #include <netinet/in.h>//inet_addr()头文件 #include <fcntl.h> #include <sys/select.h> #include <time.h> #include "pub.h" #define MAXSOCKET 1024 int main(int arg, char *args[]) { if (arg < 2) { printf("please print one param!\n"); return -1; } //create server socket int listen_st = server_socket(atoi(args[1])); if (listen_st < 0) { return -1; } //设置非阻塞文件描述符 setnonblock(listen_st); int i = 0; int maxfd = 0; //最大的socket,select函数第一个参数使用 /* *建立客户端连接池 */ int client[MAXSOCKET]; //select最大支持1024个socket连接 //将所有的客户端连接池初始化,将每个成员都设置为-1,表示无效 for (; i < MAXSOCKET; i++) { client[i] = -1; } maxfd = listen_st; //程序刚开始执行时,只有服务端socket,所以服务端socket最大 //定义一个事件数组结构 fd_set allset; while (1) { //初始化一个fd_set对象 FD_ZERO(&allset); //将服务器端socket放入事件数组allset中(服务端socket需要特殊处理,所以没有放入socket池中) FD_SET(listen_st, &allset); //先假设最大的socket就是服务器端socket maxfd = listen_st; //遍历socket池 找出值最大的socket for (i = 0; i < MAXSOCKET; i++) { if (client[i] != -1) { //将socket池中的所有socket都添加到事件数组allset中 FD_SET(client[i], &allset); if (client[i] > maxfd) { maxfd = client[i]; //maxfd永远是值最大的socket } } } //开始等待socket发生读事件 int rc = select(maxfd + 1, &allset, NULL, NULL, NULL); /* * select函数返回之后,allset数组的数据产生变化,现在allset数组里的数据是发生事件的socket * select和epoll不同,select每次返回后, * 会清空select池中的所有socket,所有的socket等select返回后就被清除了 * 所以必须由程序建立一个socket池,每次都将socket池中的socket加入到select池中 * select不会为程序保存socket信息,这与epoll最大的不同, * epoll添加到events中的socket,如果不是程序员清除,epoll永远保留这些socket */ if (rc < 0) { //select函数出错,跳出循环 printf("select failed ! error message:%s\n", strerror(errno)); break; } //判断是否是服务器socket接收到数据,有客户端连接 if (FD_ISSET(listen_st, &allset)) { //accept int client_st = server_accept(listen_st); if (client_st < 0) { //直接跳出select循环 break; } //客户端连接成功 设置客户端非阻塞 setnonblock(client_st); //将客户端socket加入socket池中 for (i = 0; i < MAXSOCKET; i++) { if (client[i] == -1) { client[i] = client_st; break; } } if (i == MAXSOCKET) { //socket池已满,关闭客户端连接 close_socket(client_st); } } //处理客户端的socket for (i = 0; i < MAXSOCKET; i++) { if (client[i] == -1) { //无效socket直接退出 continue; } //判断是否是这个socket有事件发生 if (FD_ISSET(client[i], &allset)) { //接收消息 if (socket_recv(client[i]) < 0) { //如果接收消息出错,关闭客户端socket close_socket(client[i]); //从socket池中将这个socket清除 client[i] = -1; } rc--; } //说明所有消息的socket已经处理完成 if (rc < 0) { //备注:双循环break只能跳出最近的一重循环 break; } } } //close server socket close_socket(listen_st); return 0; }