当前位置: 首页 > news >正文

select

select函数简介:        

select是Linux中常用的多路复用IO机制,它允许程序同时监控多个文件描述符(可以是套接字socket,也可以是普通文件)的读、写和异常事件。
 

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfd, fd_set* readset, fd_set* writeset, fd_set* exceptset, 
const struct timeval* timeout);//参数:
//maxfd:监视对象文件描述符数量。
//readset:将所有关注“是否存在待读取数据”的文件描述符注册到fd_set变量,并传递其地址值。
//writeset: 将所有关注“是否可传输无阻塞数据”的文件描述符注册到fd_set变量,并传递其地址值。
//exceptset:将所有关注“是否发生异常”的文件描述符注册到fd_set变量,并传递其地址值。
//timeout:调用select后,为防止陷入无限阻塞状态,传递超时信息。//返回值:错误返回-1,超时返回0。当关注的事件返回时,返回大于0的值,该值是发生事件的文件描述符数。

关于文件描述符的操作,以下四个函数是用于处理fd_set类型数据的:

FD_ZERO(fd_set *set): 这个函数用于清除一个fd_set的所有位,即初始化一个fd_set。

FD_SET(int fd, fd_set *set): 这个函数用于将特定的文件描述符fd加入到fd_set中。

FD_CLR(int fd, fd_set *set): 这个函数用于将特定的文件描述符fd从fd_set中移除。

FD_ISSET(int fd, fd_set *set): 这个函数用于检查特定的文件描述符fd是否在fd_set中,如果在,函数返回非零值,否则返回0。

        使用这些函数,我们可以方便地对文件描述符集合进行操作,以便于使用select函数进行IO操作的复用。
 

select函数优缺点:

优点:在poll和epoll面前主要是缺点,它出现的比较早。

缺点:

  • 文件描述符有限:默认为1024(这个值可以修改)。如果需要处理的并发连接数过多,select可能无法满足需求。

  • 多次copy:每次select都要把文件描述符拷贝到内核,增加了系统的开销。
  • 使用复杂:select在返回时,只会告诉用户哪些描述符集合是就绪的,但并不会直接告诉用户哪一个具体的文件描述符就绪,用户需要自己去遍历这些集合,操作比较复杂。
  • 重复操作:每次select返回后,所有未就绪的文件描述符都会被移除,因此每次使用都需要重新向集合中添加描述符。

select可以让一个线程同时处理多个客户端的连接。而避免了太多线程导致占用资源过大多,下边是一个tcp协议的服务器代码示例。客户端可以用网络调试助手进行模拟,服务器功能:客户端发送过来的数据接收后,再转发给客户端。

#include<stdlib.h>
#include<stdio.h>
#include<netinet/in.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/select.h>#define SERV_PORT 8888
#define BUFFER_SIZE 128int main(void)
{int sockfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in servaddr;memset(&servaddr,0,sizeof(struct sockaddr_in));servaddr.sin_port = htons(SERV_PORT);servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);if(-1 ==bind(sockfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr))){perror("bind");return -1;}listen(sockfd,10);fd_set fds1,fds2;FD_ZERO(&fds1);FD_SET(sockfd,&fds1);int maxfd = sockfd;printf("select test:\n");while(1){fds2 = fds1;int nready = select(maxfd+1,&fds2,NULL,NULL,NULL);if(FD_ISSET(sockfd,&fds2)){struct sockaddr_in clientaddr;socklen_t len = sizeof(clientaddr);int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);FD_SET(clientfd,&fds1);maxfd = clientfd;printf("clientfd:%d\n",clientfd);}int i = 0;for(i = sockfd + 1;i<=maxfd;i++){if(FD_ISSET(i,&fds2)){char buffer[BUFFER_SIZE] = {0};int count = recv(i,buffer,BUFFER_SIZE,0);if(!count){printf("disconnect\n");FD_CLR(i,&fds1);close(i);break;}send(i,buffer,BUFFER_SIZE,0);printf("clientfd:%d,count:%d,buffer:%s\n",i,count,buffer);}}}
}

http://www.lryc.cn/news/414172.html

相关文章:

  • 按照指定格式打印pprint()
  • Study--Oracle-07-ASM常用维护操作(五)
  • [Git][分支管理][上]详细讲解
  • C语言指针(1)
  • C语言中的指针与数组
  • CentOS7.9升级OpenSSL1.1.1w
  • 环境搭建:如何安装和使用 MySQL Connector/J——与 MySQL Community Server 的关系
  • SAP 财务管理系统 —— 企业财务智能化的领航者
  • python通过pyautogui自动给微信聊天窗口发消息
  • QML中的Date将时间戳和指定格式时间互转
  • C++ new/delete 重载
  • 读取连接中文件流和页面展示base64编码的文件
  • 【大模型从入门到精通4】openAI API 分类
  • 仓颉 -- 标识符 , 变量以及数据类型详解
  • CC++:贪吃蛇小游戏教程
  • C#中投影运算的深入解析与实例应用
  • HTML+CSS練習---空隙產生記錄
  • 【leetcode】相同的树、另一棵树的子树、翻转二叉树(利用深度优先遍历)
  • Linux系统窗口水印难点分析
  • LabVIEW与CANopen实现自动化生产线的设备控制与数据采集
  • 吃惊!这个Windows双系统方法逆天了|UEFI篇
  • 【C语言基础】C语言试题复习
  • 一拖三无线充底座-带给你极致的便利生活
  • 探索 Electron:打造深度书籍挖掘机的搜索体验
  • tomato靶场
  • 【Vue】computed计算对象不生效问题?
  • 算法小白的进阶之路(力扣9~12)
  • DOCKER容器中安装JDK1. 8 详细步骤
  • 计算机毕业设计Python+Tensorflow股票推荐系统 股票预测系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI
  • 深度学习常见的卷积和注意力机制文章集锦(持续更新)