select 版 高并发服务器

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main()
{// 1 创建套接字int lfd = socket(AF_INET, SOCK_STREAM, 0);// 2 绑定// 2.1 复用端口int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt,     sizeof(opt));// 2.2 设置IP和端口的结构体struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr)); // 清空结构体server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8888);server_addr.sin_addr.s_addr = htonl(INADDR_ANY);// 2.3 绑定bind(lfd, (struct sockaddr*)&server_addr, sizeof(server_addr));// 3 设置同时监听上限listen(lfd, 128);// 4 自定义的文件描述符数组,需要监听的文件描述符就放进client数组,用于select后遍历判断事件int client[FD_SETSIZE]; // FD_SETSIZE = 1024int i; // 循环因子for(i = 0; i< FD_SETSIZE; i++)client[i] = -1; // 将文件描述符数组元素都初始化为-1,代表各个位置可用// 5 准备select集合fd_set set, orgset; // orgset是原始集合,set用于保存传出集合FD_ZERO(&orgset);FD_SET(lfd, &orgset); // 在原始集合中监听lfd,准备select参2// 6 监听读事件int nfds = lfd; // 记录最大文件描述符编号,准备select参1struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr); // 用于接收客户端信息char buf[BUFSIZ] = {0}; // 读写缓存区while(1){set = orgset; // select中参2是传入传出属性,因为不希望改变原始监听集合orgset,所以使用setint nready = select(nfds+1, &set, NULL, NULL, NULL);if(nready < 0){perror("select err");exit(1);}// 6.1 如果是新连接if(FD_ISSET(lfd, &set)){int cfd = accept(lfd, (struct sockaddr*)&client_addr, &client_len); // 获得连接描述符char ip[16] = {0};printf("conn from %s at %d\n",inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),ntohs(client_addr.sin_port)); // 打印客户端信息for(i = 0; i< FD_SETSIZE; i++) // 更新遍历client数组,将cfd添加进去{if(client[i] < 0){client[i] = cfd; // 给到数组中可用的最小位置break; // 退出for循环}}if(i == FD_SETSIZE) // 如果数组中没有位置{printf("client too many\n");break; // 退出while循环,执行returm}FD_SET(cfd, &orgset); // 监听cfd , 更新select参数2if(cfd > nfds) // 增加判断条件是因为,一旦nfds前有可用位置,nfds不需要更新nfds = cfd; // 更新select参数1if(--nready == 0)continue; // 就一个事件,而且是新连接,没必要往下执行了}// 6.2 ,如果不是以上情况,那就是普通读事件for(i = 0; i < FD_SETSIZE ; i++) // 遍历client数组,看哪个文件描述符变化{if(client[i] < 0)continue; // 如果是-1,代表空位,没必要向下走了,继续for循环if(FD_ISSET(client[i], &set)) //判断传出set中是否有client[i],如果有,代表有读事件发生{int n = read(client[i], buf, sizeof(buf));if(n < 0){perror("read err");close(client[i]); // 该文件描述符无用了,关闭FD_CLR(client[i],&orgset); // 更新select参数2,注意:nfds不能动client[i] = -1; // 将client数组元素置为初始态}if(n == 0){printf("client[%d] closed\n", i);close(client[i]);FD_CLR(client[i],&orgset);client[i] = -1;}if(n > 0){write(client[i], buf, n);write(STDOUT_FILENO, buf, n);}if(--nready == 0)break; // 为了防止循环1024}}}close(lfd);return 0;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部