select多路复用学习(1)

前言:

之前的文章里面,已经学习过了c/s框架模型,但是这个模型有一个缺点,就是服务端处理不了多个客户端的请求,所以今天我们开始来学习select多路复用!

一、一切皆文件:

Linux内核管理的一切东西,都可以看成是文件!那内核来管理什么呢?举简单例子来看-管理硬件,比如管理硬盘、网卡、内存等!在这样的设计理念下,所有的这些硬件都可以被看成文件了。

1、Linux中的文件是什么?

  • 狭义:文件系统中物理意义上的文件(逻辑上关联的数据集合)

  • 广义:设备、管道、内存,Linux管理的一切对象

2、理解文件描述符(File Descriptor)fd:

  • 文件描述符是一个非负整数值,本质上是一个句柄(handle)
  • 一切对用户透明的资源标识都可以看作句柄
  • 用户使用文件描述符(句柄)与内核交互
  • 内核通过文件描述符操作对应资源的数据结构

一般操作文件的操作方式有:

  • open
  • read
  • write
  • close

IO设备的文件操作方式:

#include <stdio.h>
#include <unistd.h>
int main()
{
    
    
	int iofd =0;
	char s[] = "mytest\n";
	int len =0;
	write(0, s, sizeof(s));
	
	len = read(0, s , 2);
	s[len] = 0;
	printf("%s\n",s);
	return 0;
}

3、阻塞、回调、轮询:

  • 事件相关函数的分类:
    - 阻塞式函数:函数调用后需要等待某个事件发生后才会返回,比如函数:scanf,read,accept
    - 非阻塞式函数:函数调用后能够及时返回(仅标记等待的事件);事件发生后以回调方式传递;比如说,在淘宝上买东西,你下单了,不会说一直在那里等待买的东西到来吧,肯定这个时候去干别的事情了,只有快递信息到了,你才会去拿买的东西!这就是所谓的标记!

  • 阻塞与轮询:

    • 轮询指依序询问每一个相关设备是否需要服务的方式
    • 轮询可用用于解决阻塞函数导致程序无法继续执行的问题
    • 这里还是以刚才的买东西为例,我们每隔3个小时去看看快递是否到了,没有到的话,就干别的事情!

所有解决阻塞函数导致的效率问题,有两种方法:

  • 回调的方式

  • 轮询的方式

4、神奇的select函数:

  • 1、select()函数用于监视指定的文件描述符是否产生事件
  • 2、可通过轮询的方式检测目标事件(事件产生则标记发生变化)
  • 3、根据事件类型做出具体处理(如:读取数据)
int select(int maxfd,fd_set *readset, fd_set *writeset, fd_set *exceptset,
 const struct timeval *timeout);

下面是select()函数的使用步骤流程:
在这里插入图片描述
select()相关数据类型及操作:

FD_ZERO(fd_set *fdset);//讲fd_set变量的所有位设置位0

FD_SET(int fd,fd_set *fdset);//讲fd_set中指定需要监听的fd

FD_CLR(int fd , fd_set *fdset); //在fd_set中剔除fd,不再监听

FD_ISSET(int fd, fd_set *fdset); //在fd_set 查看是否包含fd

下面是多路复用实战案例:

#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unisted.h>

int main()
{
    
    
	int iofd = 0;
	char s[] = "linux\n";
	fd_set reads = {
    
    0};
	fd_set temps = {
    
    0};
	
	struct timeval timeout = {
    
    0};
	FD_ZERO(&reads);//将fd_set变量的所有位设置位0
	FD_SET(iofd, &reads);//将fd_set中指定需要监听的fd
	
	while(1)
	{
    
    
		int ret = -1;
		temps = reads;//这里为什么这样做,主要是为了避免之前设置的reads标记被select函数覆盖了
		timeout.tv_sec = 0;
		timeout.tv_usec = 50000;
		ret = select(1,&temps,0,0,&timeout);
	
		if(ret >0) //轮询的结果有事情发生
		{
    
    
			len = read(iofd, s ,sizeof(s) - 1);//都输入输出设备中的数据
			s[len] = 0;
			printf("%s\n",s);
		}
		else if(ret ==0)//轮询的结果没有事件发生,这里可以体现出轮询来,因为没有事件,所以走这里
		{
    
    
			static int count = 0;
			usleep(10000);
			count++;
			if(count >100)
			{
    
    
				printf("do something else\n");
				count = 0;
			}
		}
		else//发生了错误
		{
    
    
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Dada_ping/article/details/128336278