目录
一、学习的知识点
man 2 属于系统调用
read 系统调用 先到内核空间(操作系统层)取数据 ,存放到 buff(应用层 用户空间)
1 五种 I/O
1.1 阻塞式I/O
通过read系统调用 到内核空间读取数据到用户空间,没有数据读取时 会阻塞。占用资源
1.2 非阻塞式I/O
阻塞和非阻塞是针对文件描述符来说。
通过 fcntl 函数设置 文件描述符的属性 默认为阻塞 可以设置为非阻塞 fd ctrl
1.3 I/O复用(select 和pool)
对I/O的操作只有 读 写,
1.3.1 select 文件描述符的管理
select 相当于一个管家 管理和socket有关的所有文件描述符 select只用一个进程就可以实现群聊服务器
select要知道当前进程的最大文件描述符是多少
管什么:暂时只管理 文件描述符的可读事件 可读事件(新的客户端连接、 文件描述符有数据可读包括客户端下线)
管理?文件描述符
会知道新客户端连按時文件描述符
会知道有数据需要去取的文件描述符
会知道下线的文件描述符
函数等待集合中产生可读事件的文件描述符。连接一个客户端 集合的值会变,哪个文件描述符产生可读事件 集合就变成几。 fd_ set是一个输入输出参数
- int select(int nfds, fd_ set *readfds, fd_ set *writefds,fd set *exceptfds, struct timeval *t imeout) ;
- 参数1:当前进程 最大文件描述符的数值是多少
- 参数2:文件描述符的可读事件集合
- 参数3 可写
- 参数4 异常
- 返回值:有几个文件描述符产生事件 就返回几
select 缺点
通过轮询查找文件描述符 如果文件描述符太多 效率就不高 没有可读事件产生会等待 select阻塞
对文件描述符的集合操作
- void FD_ CLR(int fd, fd_ set *set); 从集合删除某个文件描述符
- int FD_ ISSET(int fd, fd_ set *set); 判断集合中是否包含某个文件描述符
- void FD SET(int fd, fd_ set *set); 吧文件描述符加入集合
- void FD_ ZERO(fd_ set *set); 把集合清空
int maxfd = listen_fd;
fd_set rset; //文件描述符集合
fd_set allset; //放最新最全的文件描述符
FD_ZERO(&allset);
FD_ZERO(&rset);
FD_SET(listen_fd, &allset);//吧 listen_fd放入allset 里面 交给select 监管
cout << "select is wait..." << endl;
char buff[1024] = {
0 };
while (1)
{
rset = allset; //因为select每返回一次 rset存放的都是产生事件的文件描述符的集合 其他的文件描述符被丢弃
//所以每返回一次 都要把最全的集合给他
//参数1 fd数量 比如最大文件描述符为6 则轮询0-6 7个文件描述符 一旦select返回 rset会变成已经产生可读事件的文件描述符的集合
//如果两个文件描述符产生事件 就变成两个对应的文件描述符的集合
int n = select(maxfd + 1, &rset