并发服务器、多路IO复用

目录

服务器模型:IO多路复用

常见的IO操作模型

[阻塞IO:scanf(); getchar(); fgets();](#阻塞IO:scanf(); getchar(); fgets();)

[非阻塞IO :](#非阻塞IO :)

信号驱动IO

[int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);](#int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);)

select使用流程

epoll

[① int epoll_create(int size);](#① int epoll_create(int size);)

epoll_ctl

epoll_wait


显卡

声卡

网卡:能让你上网的

URL的一般形式

<协议>://<主机 ip> : <端口>/

strstr --> char *strcasestr(const char *haystack, const char *needle);

功能:从中找字符串

参数:

返回值:返回找到的子字符串的起始位置

客户端:并发服务器------支持多个用户同时访问

循环服务器(迭代服务器)

while(1)

{

//连接

accept(); //问题1:阻塞操作------在等待队列中没有连接请求时会阻塞

while(1) //问题2:通信过程可能是一个耗时操作

{

//通信recv();send();}}

实现简单。可以处理多个客户端,但是只能是串行

并发服务器

while(1)

{connfd = accept();

fork() 或 pthread_create()

}

多进程:资源开销大,进程的退出要考虑僵尸态资源的回收

多线程:线程的创建和调度开销小,线程共享资源方便,线程之间竞争和同步问题

服务器模型:IO多路复用

核心目的 ------ 提高并发的程度

多路IO ------ 当前进程有多处输入输出的操作

复用 ------ 服复用的是当前进程或线程

应用:在一个进程中有多个线程要执行

系统开销小,也不用创建线程和进程,不用维护,减少系统的开销

常见的IO操作模型

阻塞IO:scanf(); getchar(); fgets();

  • 常见的主要是读取、写入、管道(64kb大小空间)
  • 当读取数据时,内核没有数据,读取操作会一直阻塞,直到内核获得数据
  • 特点:实现简单,效率不高

非阻塞IO :

特点:当去内核读取数据时,如果内核没有数据,他不阻塞等待,而是立即返回,所以非阻塞方式想要获得数据,需要配合轮询操作

while(1)

{

recvfrom(); //非阻塞一直要轮询到等读到数据

}//很耗CPU

信号驱动IO

  • 1 设置好对SIGIO的信号处理函数,等有数据来了,内核会给进程发信号,进程收到信号后,再去做读取操作,不需要一直等也不需要轮询
  • 使用流程:
  • 为内核发送的通知信号安装一个信号处理例程,默认情况下,这个通知信号为SIGIO
  • //signal 或 sigaction
  • signal(SIGIO,handler);
  • 2 设定文件描述符的属主,也就是当文件描述符上可执行IO时会接收到通知信的进程或进程组,通常我们让调用进程成为属主,设定属主可通过fcntl();的F_SETOWN操作来完成
  • //owner
  • fcntl();
  • 异步的效率高,但是只能处理一路IO
  • 3 设置标志:通过设定O_NONBLOCK标志使能非阻塞IO;通过打开O_ASYNC标志使能信号驱动IO;这可以一个操作,因为它们都需要用到fcntl()的F_SETFL操作

IO多路复用

int select(int nfds, fd_set *readfds, fd_set *writefds,

fd_set *exceptfds, struct timeval *timeout);

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);

select使用流程

  1. 准备监控文件描述符表:fd_set readfds;FD_ZERO(&readfds);
  2. 添加要监控的文件描述符:FD_SET(fd,&readfds);FD_SET(0,&readfds);
  3. 准备nfsd:nfds = n+1;
  4. 调用select函数:select(nfsd,&readfds,NULL,NULL,NULL);
cpp 复制代码
select 实现并发:
1.listenfd=socket
2.bind
3.listen

//1.准备表
    fd_set readfds;
	//清空
	FD_ZERO(&readfds);
//2.添加要监控的文件描述符到表中
	//listenfd
	FD_SET(listenfd,readfds);
//3.调用select函数进行监控
//1.nfds --> 最大的文件描述符+1
	int nfds = listenfd + 1; //注意: 是三个集合中最大的文件描述符加1
	int ret = 0;
	int i = 0;
	fd_set bakfds = readfds;
while (1)
{
    bakfds = readfds;
    ret = select(nfds,&bakfds,NULL,NULL,NULL); 
    
	if (ret > 0) 
	{ //表示有就绪的文件描述符
        //寻找具体是哪个文件描述符就绪
        for (i = 0; i < nfds; i++) 
		{
            if (FD_ISSET(i,&bakfds)) 
			{ //只能判断出 i 是否在bakfds中
               if (i == listenfd)  //意味着有客户端发起连接请求 
			   {
                    connfd = accpet();
                    //实现并发,添加对新连接的套接字的监控
                   
 				    //1. 添加到要监控的表中,进行监控
                    FD_SET(connfd,&readfds);
                    //2.更新maxfd
                    if (connfd + 1> nfds)
                        nfds = connfd+1;
                } 
				else   //创建 --- 子进程 或 线程
				{  //此时肯定是某个客户端对应的connfd的值
                    read(i,buf,sizeof(buf)); //从i中读值,
                                              //因为i表示的是当前就绪的文件描述符
					printf("buf == %s\n",buf);  
                }
            }
        }
    }
}

epoll

1.创建监控的epoll对象

epoll_create

① int epoll_create(int size);

功能:创建epoll对象,返回文件描述符

参数:@size 并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。

返回值:是Epoll描述符

epoll_ctl

  1. 所谓边沿触发,指的是对应fd从无数据到有数据这一瞬间的变化,而水平触发是指对应的fd中只要有数据就认为是就绪状态,直到数据处理完
  2. epoll如果监听ET事件,fd必须是非阻塞套接口(高性能场合)比如:监听可读事件,当ET上报可读后,需要一直读Fd直到遇到EAGATN错误为止,以免遗留数据在缓冲区中,如果FD是阻塞的,则会读到阻塞了(不建议做太多的耗时操作)
  3. 现在很多的高性能并发服务器:epoll+et+线程池

epoll_wait

相关推荐
Yvonne爱编码1 小时前
二叉树高频题精讲 | 从入门到熟练掌握二叉树操作
java·开发语言·数据结构·链表·二叉树
wuqingshun3141592 小时前
说说java中实现多线程有几种方法
java·开发语言·jvm
于眠牧北2 小时前
重写RedisTemplate后在lua脚本中传递参数不需要二次转换
java·junit·lua
煜3642 小时前
Linux初识与基本指令
linux·运维·服务器
深蓝轨迹2 小时前
SQL优化及实战分享
java·数据库·sql
hashiqimiya2 小时前
尝试其他项目使用本地仓库的jar包时报错没找到类的原因并下载到本地仓库
java·jar
佑白雪乐2 小时前
<Linux基础第14集>总结前面知识点,不含Linux命令
linux·运维·服务器
常利兵2 小时前
Spring Boot + MyBatis,给数据穿上“隐形盔甲”
java·spring boot·mybatis
xiaoye37082 小时前
动态代理的使用场景与适用时机
java·数据库·sql