IO多路复用之select、poll、epoll之间的区别总结

news2025/2/28 6:25:09

一、IO多路复用基本概念

select、poll、epoll都是IO多路复用的机制。IO多路复用就是通过一种机制,让一个进程/线程可以监视多个描述符,一旦某个描述符就绪(一般是读写就绪),能够通知应用程序进行相应的读写操作。

I/O多路复用在英文叫 I/O multiplexing,这里面的 multiplexing 指的其实是在单个进程/线程通过记录跟踪每一个文件描述符的状态来同时管理多个I/O流。发明它的原因,是尽可能地提高服务器的吞吐能力。

I/O复用虽然能同时监听多个文件描述符,当其本质上还是同步IO模型,因为需要在读写事件就绪后程序自己负责进行读写事件的处理,而这个读写过程是阻塞的。如果要实现并发,只能使用多进程/多线程等编程手段了。与多进程/多线程技术相比,I/O多路复用技术最大的优势就是系统开销小,系统不必创建大量进程/线程,也不必维护这些进程/线程,从而大大减少了系统的开销。

IO多路复用使用场景

1)当客户处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用。

2)当一个客户同时处理多个套接口时,这种情况是可能的,但很少出现。

3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。

4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。

5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。

二、三组 I/O 多路复用函数的比较

这三组I/O多路复用系统调用都能同时监听多个文件描述符。它们将等待由timeout参数指定的超时时间,直到一个或多个文件描述符上有事件发生时返回,返回值是就绪的文件描述符的数量,如果返回0,则表示没有事件发生。

下面我们主要从事件集合、最大支持文件描述符数量、工作模式和底层实现原理等4个方面进一步比较它们的异同。

事件集合

这3组函数都通过某种结构体变量来告诉内核监听哪些文件描述符上的哪些事件,并使用该结构体类型的参数来获取内核的处理结果。

select:使用 fd_set 结构体来存放被监听的文件描述符的,本质上是使用一个位图结构来存放这些被监听的文件描述符的,因此select能够监听的文件描述符数量是有限制的。同时,fd_set 没有将文件描述符和事件进行绑定,它仅仅是一个文件描述符集合,因此,select需要提供3个fd_set类型的参数来分别传入和传出可读、可写及异常事件。一方面,使得select不能处理更多类型的事件,另一方面,由于内核对fd_set集合的在线修改,使得下次再调用select()函数前不得不重置这3个fd_set集合,这使得编程变成很麻烦,并且容易出错。

poll:使用 struct pollfd结构体来存放被监听的文件描述符,它比select“聪明”的地方就在于它把文件描述符和与其关联的事件都定义在这个结构体中了,从而使得编程接口变得简洁很多,同时内核每次修改的都是pollfd结构体的revents成员,而events成员保持不变,因此下次调用poll()函数时应用程序无须重置pollfd类型的事件集参数。

由于每次select 和 poll 调用都是返回整个用户监听的事件集合(其中包括就绪的和未就绪的),所以应用程序索引就绪文件描述符的时间复杂度为O(n)。

epoll:采用与select 和 poll 完全不同的方式来管理用户注册的事件。它在内核中维护一个事件表,并提供了一个独立的系统调用函数 epoll_ctl来控制往该内核事件表中添加、删除、修改事件。这样,每次调用epoll_wait()函数时,都是直接从内核事件表中取得用户注册的事件,而无须反复从用户空间将这些注册事件读入到内核区中,节省了复制的系统开销。epoll_wait 系统调用中的 events 指针参数仅用来返回就绪的事件,这使得应用程序索引就绪文件描述符的时间复杂度为O(1)。需要注意的是,epoll 和 poll一样,也是将文件描述符和与其关联的事件是绑定在一起的,这样做的好处是,编程接口变得简洁,不像select那样复杂。

最大支持文件描述符数量

poll 和 epoll 分别用 nfds 和 maxevents 参数指定最多监听多少个文件描述符。这两个数值都能达到系统允许打开的最大文件描述符数目,即 65 535(cat /proc/sys/fs/file-max)。而select允许监听的最大文件描述符数量通常是有限的。虽然用户可以修改这个限制,但是这可能会导致不可预期的后果。

工作模式

select 和 poll 都只能工作在相对低效的LT(水平触发)模式,而epoll 虽然默认也是工作在LT模式下,但是它还可以工作在更高效的ET(边缘触发)模式下。并且 epoll 还支持 EPOLLONESHOT事件。该事件能进一步减少可读、可写和异常事件被触发的次数。

底层实现原理

select 和 poll 都是采用轮询的方式,即每次调用都要扫描整个注册的文件描述符,并将其中就绪文件描述符的数量返回给应用程序,因此它们检测就绪文件描述符的事件复杂度为O(n)。

而epoll则不同,它采用的是回调的方式,内核检测到就绪的文件描述符时,将触发回调函数,回调函数就将该文件描述符上对应的事件插入到内核就绪事件队列。当调用epoll_wait 系统调用时,无须轮询整个内核事件表中的文件描述符,而只需检测就绪事件队列是否有内容,如有,内核则将该就绪队列中的内容拷贝到用户空间,因此epoll检测就绪文件描述符的时间复杂度为O(1)。

相关视频推荐

6种epoll的设计方法(单线程epoll、多线程epoll、多进程epoll)

epoll实战揭秘-支撑亿级IO的底层基石

网络原理tcp/udp,网络编程epoll/reactor,面试中正经“八股文”

学习地址:c/c++ linux服务器开发/后台架构师

需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

 

三、三组 I/O 多路复用的优缺点

3.1 select

【优点】

1、select的可移植性好,因为在某些Unix系统上并不支持poll 和 epoll(极少)。

2、select 对于超时时间提供了更好的精度:微秒,而 poll 和 epoll 都是毫秒级。

【缺点】

1、select 支持监听的文件描述符fd的数量有限制,默认是1024个。(最大数量限制)

2、select 需要维护一个用来存放文件描述符fd的数据结构(fd_set),每次调用select都需要把fd集合从用户区拷贝到内核区,而select系统调用结束后,又需要把fd集合从内核区拷贝到用户区,这个系统开销在fd数量很多时会很大。(内存复制开销)

3、每次调用select系统调用时,都需要在内核遍历传入的整个文件描述符集合,逐个检测,查看是否有就绪的文件描述符,然后返回就绪文件描述符的个数。也就是说,select对文件描述符是线性扫描的,当注册的文件描述符fd的数量很多时,效率会较低,时间复杂度为O(n)。(时间复杂度)

3.2 poll

poll的实现原理和select非常相似,但是相比select,它做了一些改进的地方。首先是存放文件描述符的数据结构(pollfd),它将文件描述符和与其对应的事件关联起来了,使得编程接口变得简洁了;其次,它没有了最大文件描述符的限制,原因是它是基于链表结构来存储的。

【优点】(对比select而言)

1、没有最大文件描述符数量的限制(相对select而言)。(基于链表存储)poll 主要是解决了这个最大文件描述符数量的限制问题。

当然,它还是有上限的,这个上限是操作系统所支持的能开启的最大文件描述符数量(cat /proc/sys/fs/file-max)。

2、优化了编程接口。select()函数有5个参数,而poll()减少到了3个参数。并且每次调用select函数前,都必须重置该函数中的3个fd_set类型的参数值,而poll不需要重置。

【缺点】

1、poll 同样需要维护一个用来存放文件描述符的数据结构(pollfd),当注册的文件描述符无数量很多时,会使得用户区和内核区之间传递该数据结构的复制开销很大。(内存复制开销)

每次调用poll系统调用时,都需要把文件描述符fd集合从用户区拷贝到内核区,然后poll系统调用返回前,又需要把文件描述符fd集合从内核区拷贝到用户区,这个内存拷贝的系统开销在fd数量很多的时候会很大。

<说明> 系统调用函数的执行是发生在内核区的,而用户程序的执行是发生在用户区的,所以会存在内核区与用户区之间的内存复制的系统开销。

2、与select一样,每次poll系统调用时,需要在内核遍历传入的整个文件描述符集合,逐个检测,查看是否有就绪的文件描述符,然后返回就绪文件描述符的个数。也就是说,poll也是线性扫描的方式,当注册的文件描述符fd的数量很多时,效率会较低,时间复杂度为O(n)。(时间复杂度)

3、poll 只能工作在水平触发(LT)模式下。(工作模式)

水平触发模式下,当描述符处于就绪状态下,内核通知了应用程序,但是应用程序没有进行处理,那么下次调用poll时仍会向应用程序发出通知。

<注意> select 和 poll 都需要在返回后,通过遍历整个文件描述符集合来获取就绪的文件描述符。事实上,在网络连接中,同时连接的大量客户端在某一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的递增,其效率也会线性递减。

3.3 epoll

epoll 是在Linux 2.6内核版本中提出的,是之前select和poll的增强版本。

epoll使用一个epoll文件描述符管理多个被监听的文件描述符,将用户关心的文件描述符的事件存放到内核的一个事件表中,这样在用户区和内核区只需要拷贝一次被监听的文件描述符的数据结构(epoll_event)即可。

epoll 既解决了select的最大文件描述符数量限制的问题,又解决了poll的内存复制开销大、时间复杂度大的问题(前提条件:文件描述符数量很大的情况下)。

【优点】(对比select和poll)

1、和poll一样,没有最大文件描述符数量的限制(相对select而言)。

2、epoll 虽然也需要维护用来存放文件描述符的数据结构(epoll_event),但是它只需要将该数据结构拷贝进内核区一次,不需要重复拷贝。

epoll只在调用 epoll_ctl 系统调用时拷贝一次要监听的文件描述符数据结构到内核区,在调用 epoll_wait系统调用时不需要再把所有要监听的文件描述符fd重复拷贝进内核区。而select和poll每次调用都需要把所有要监听的fd重新拷贝到内核区。这就解决了内存复制开销的问题。

3、epoll 采用回调方式来检测就绪文件描述符。

epoll 通过epoll_ctl系统调用注册一个文件描述符,一旦该文件描述符就绪,内核就会采用callback回调机制来进行通知,并将该就绪描述符放入就绪事件链表中。然后在epoll_wait系统调用中,当接收到有通知信号到来时,就会去检测就绪事件链表是否有内容,如果有内容,就将就绪事件链表的内容从内核区拷贝到用户区,最后epoll_wait系统调用返回就绪描述符的个数。也就是说,epoll只会对活跃的文件描述符进行管理,而不需要像select和poll那样,每次调用都要线性扫描全部的文件描述符,导致效率呈现线性下降。

【缺点】

目前只有Linux操作系统支持epoll,不支持跨平台使用。而Unix操作系统上是使用kqueue。

四、几个需要注意的问题

4.1 用户态将文件描述符参传入内核的方式

  • select:创建3个文件描述符集的数据结构(fd_set)并拷贝到内核中,分别监听读、写、异常事件。受单个进程/线程可以打开的文件描述符数量限制,默认是1024个文件描述符。
  • poll:将传入的文件描述符数据结构(struct pollfd结构体数组)拷贝到内核中进行监听。
  • epoll:执行epoll_create系统调用时会在内核的缓冲区中建立一颗红黑树以及就绪链表(该链表用于存储已就绪的文件描述符)。接着用户执行的epoll_ctl系统调用添加文件描述符,即在红黑树上增加相应的结点。

4.2 内核态检测文件描述符就绪状态的方式

  • select:采用轮询方式,线性扫描所有用户关注的文件描述符,如果检测到某个文件描述符已就绪,就修改用户传进来的数据结构fd_set的值。
  • poll:同样采用轮询方式,线性扫描所有用户关注的文件描述符,如果检测到某个文件描述符就绪,内核就修改文件描述符fd对应的revents的值,并将其加入到内核的等待队列中。
  • epll:采用回调方式。在执行epoll_ctl的ADD操作时,不仅将文件描述符放入红黑树上,并且还注册了回调函数,如果某个文件描述符已就绪,它会主动调用回调函数,该回调函数将文件描述符放入到就绪链表中。

4.3 找到就绪文件描述符并传递给用户态的方式

  • select:将之前传入到内核态的数据结构(fd_set)重新拷贝传出到用户态,并返回就绪的文件描述符数量。但是用户程序并不知道哪些文件描述符是处于就绪态,因此需要在用户程序中对所有的文件描述符再一次进行遍历来判断。
  • poll:将之前传入到内核态的数据结构(pollfd数组)重新拷贝传出到用户态,并返回就绪的文件描述符数量。用户程序同样不知道哪些文件描述符是处于就绪态,需要遍历判断。
  • epoll:epoll只需要检测就绪事件链表中有无数据即可,如有,则只需将就绪链表的数据拷贝传出到用户态,并返回就绪的文件描述符数量。由于返回的就是就绪态的文件描述符,因此用户程序不需要通过遍历来判断,而是直接处理即可。

4.4 重复监听文件描述符的处理方式

  • select:将新的监听文件描述符集合拷贝传入内核中,继续以上步骤。
  • poll:将新的struct pollfd结构体数组拷贝传入内核中,继续以上步骤。
  • epoll:无需重新构建红黑树,直接沿用已存在的即可。

4.5 三种IO多路复用的适用场景

select、poll:适合在连接数少并且连接都十分活跃的情况下。

epoll:适用在连接数很多,活跃连接较少的情况下。

表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll要好,毕竟epoll的通知机制需要调用很多的函数回调,这也是一笔不小的系统开销。
select、poll的低效是因为每次它们都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善。

五、总结

  • select,poll,epoll都是IO多路复用的实现机制。它们本质上还是同步IO,而不是异步IO,因为它们都需要在读写事件就绪后自己负责进行读写操作,而这个读写过程是阻塞的;而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核空间拷贝到用户空间。
  • select、poll的底层实现中需要自己不断地轮询所有fd集合,直到文件描述符就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait 不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是当某个文件描述符就绪时,主动调用回调函数,把就绪的文件描述符放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只须判断一下就绪链表是否为空就行了,这就节省了大量的CPU时间,这就是回调机制带来的性能提升。
  • select、poll每次调用(调用select()、poll()函数)都要把所有文件描述符fd集合从用户态拷贝到内核态,而epoll是在初始调用epoll_create时在内核区先开辟好缓存区,然后在调用epoll_ctl时,将待注册的文件描述符从用户态拷贝到内核态,并且只需要拷贝这一次,在每次调用epoll_wait时,不再需要重复拷贝,这就节省了内存复制带来的系统开销。

为了便于阅读,我们将这3组I/O多路复用的系统调用的区别总结成一个图表,如下图所示:

 select、poll 和 epoll的区别

六、面试题

1、在epoll IO多路复用中,某个socket读到一半,在这个socket上又有读事件来了怎么办?

答:为了避免在同一个socket上再次监听到同一个可读事件,可以在对应的描述符中添加 EPOLL_ONESHOT事件,其效果是监听到一次事件后就将对应的描述符从监听集合中移除,也就不会再被追踪到了。读操作完成后再把对应的文件描述符重新加入监听集合。

2、LT和ET模式下的阻塞与非阻塞?

答:在ET(水平触发)模式下,也是epoll的默认模式,epoll_wait返回可读事件,表明socket一定收到了数据,我们可以使用read函数来读取数据。如果指定读取的数据大于缓冲区数据,无论socket是阻塞还是非阻塞,read函数不会阻塞,会返回实际读取到的数据大小。在read之后再次调用read,如果socket是阻塞的,read将阻塞,直到接收到数据才返回。此时,如果指定读取的数据小于缓冲区中数据,epoll_wait 会继续被触发,因为还有读缓冲区中还有数据没有被读取完。

在ET(边缘触发)模式下,只有新的数据到来时才会触发。如果指定读取的数据小于缓冲区中的数据,epoll_wait 不会被继续触发。因此,使用ET模式时,有数据到来时,必须循环读取读缓冲区中的数据,直到read返回-1,并且errno错误码为EAGAIN,才算读取完了全部缓冲区中的内容。

  • 对于监听的listen_fd,最好使用LT模式,如果使用ET模式会导致高并发情况下,有的客户端会连接不上。如果非要使用ET模式,可以在while循环中调用accept()函数。
  • 对于读写的conn_fd,LT模式下,阻塞和非阻塞效果都一样,因为在阻塞模式下,如果数据读取不完全则返回继续触发,反之读取完则返回继续等待。建议将文件描述符设置为非阻塞。
  • 对于读写的conn_fd,ET模式下,必须使用非阻塞IO,并要求一次性地完整读写完全部数据。因为如果不一次性读取完缓冲区中的全部数据,缓冲区剩余数据不会被 epoll_wait 再次触发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/155545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

并网逆变器学习笔记5---三电平DPWM

参考文献&#xff1a;《中压三电平全功率风电变流器关键技术研究---任康乐》 1、调制策略分析 DPWM由于其在任意时刻均有一相钳位在某个电平&#xff0c;使得该相的功率器件不发生开关动作&#xff0c;因而可以大大降低开关损耗&#xff08;平均降低1/3&#xff09;&#xff…

Java多线程案例——定时器

一&#xff0c;定时器1.定时器的概念定时器是Java开发中一个重要的组件&#xff08;功能类似于闹钟&#xff09;&#xff0c;可以指定一个任务在多长时间后执行&#xff08;尤其在网络编程的时候&#xff0c;如果网络卡顿很长时间没有响应用户的需求&#xff0c;此时可以使用定…

分享|UWB使用频段大幅收窄,新标准对于行业发展是好是坏?

近日&#xff0c;工信部无线电管理局发布了《超宽带&#xff08;UWB&#xff09;设备无线电管理规定&#xff08;征求意见稿&#xff09;》&#xff08;以下简称“新版《规定》”&#xff09;。 根据新版《规定》&#xff0c;未来国内UWB技术的使用频段为&#xff1a;7235-875…

seo的基本知识(概述网站内部优化和外部优化)

了解网站外部优化的4大重点 网站优化的时候都会重视网站的外部优化&#xff0c;所以网站外部优化的4大重点&#xff01;今天就来和大家说一说&#xff01; 1.高质量的内容和外链 未来的SEO道路高质量的有价值的内容是非常重要的&#xff0c;还有就是高质量的外链也是重要之…

北大硕士LeetCode算法专题课-查找相关问题

黑马算法面试专题 北大硕士LeetCode算法专题课-字符串相关问题 北大硕士LeetCode算法专题课-数组相关问题_​​​​​​ 北大硕士LeetCode算法专题课-基础算法查找_ 北大硕士LeetCode算法专题课-基础算法之排序_客 北大硕士LeetCode算法专题课---算法复杂度介绍_…

Neo4j框架学习之一安装和使用

文章目录1、何为Neo4j2、安装和使用2.1 安装2.2 基础概念1、何为Neo4j ​ Neo4j是一个高性能的NOSQL图形数据库&#xff0c;是一个嵌入式的、基于磁盘的&#xff0c;数据结果为网格(图)、具备完全的事务特性的Java持久化引擎。 数据结构 ​ 在一个图中包含两种基本的数据类型…

从浏览器里输入URL构建你的前端知识体系

嗨&#xff01;我是团子&#xff0c;好久不见~ 记得22年寒假复习八股的时候&#xff0c;一直在苦恼怎样才能把八股的内容真正的转换为自己的知识。毕竟光靠死记硬背每个知识点&#xff0c;是不能在面试中给面试官留下不错的印象的。后面在整理《浏览器里输入URL后发生了什么》…

Stellarium 1.2 正式发布

导读Stellarium 1.2 已发布。Stellarium 是一款免费开源 GPL&#xff08;自由软件基金会 GNU 通用公共许可证&#xff09;软件&#xff0c;它使用 OpenGL 图形接口对星空进行实时渲染。 软件可以模拟肉眼、双筒望远镜和小型天文等观察天空&#xff0c;根据观测者所处时间和位置…

项目管理:项目经理如何创建项目日程计划表

当项目经理接手项目后&#xff0c;要做好项目的日程安排&#xff0c;这是决定项目是否成功完成的最重要任务之一。 项目经理都希望项目按照制定好的进度计划完工&#xff0c;但在实际的情况中&#xff0c;总会有那么一两个项目会出现进度延迟的情况&#xff0c;管理者可以使用…

忆享科技戟星安全实验室|OSS的STS模式授权案例

戟星安全实验室忆享科技旗下高端的网络安全攻防服务团队.安服内容包括渗透测试、代码审计、应急响应、漏洞研究、威胁情报、安全运维、攻防演练等。本文约957字&#xff0c;阅读约需3分钟。前言《漏洞挖掘系列》将作为一个期刊持续更新&#xff0c;我们会将项目中所遇到的觉得有…

图像编辑Photoshop 2023中文新

Photoshop2023从照片编辑和合成到数字绘画、动画和图形设计-只要能想到&#xff0c;就能在Photoshop中创作出来。相信大家都有在用之前的版本&#xff0c;这款软件功能丰富&#xff0c;实用性很强&#xff0c;有着大量的功能用户都可以用上&#xff0c;不管是美化还是滤镜&…

基于冲突搜索(CBS)的多智能体路径寻优(MAPF)

1 背景 1.1 问题描述 多智能体路径寻优( Multi-Agent Path Finding&#xff0c;MAPF )问题由一个无向无权图G ( V &#xff0c;E )和一组k个智能体组成&#xff0c;其中智能体有起始点和目标点。时间被离散化为时间步。在连续的时间步之间&#xff0c;每个智能体既可以移动到…

Kafka生产者——消息发送流程,同步、异步发送API

生产者消息发送流程 发送原理 Kafka的Producer发送消息采用的是异步发送的方式。 在消息发送的过程中&#xff0c;涉及到了两个线程:main线程和Sender线程&#xff0c;以及一个线程共享变量:RecordAccumulator。 ①main线程中创建了一个双端队列RecordAccumulator&#xff0c…

Spring Boot 创建和使用

Spring Boot 创建和使用一、什么是 Spring Boot二、Spring Boot 优点三、Spring Boot 项目创建3.1 使用 Idea 创建验证3.2 网页版创建四、项目目录介绍五、约定大于配置 (重要)5.1 启动类5.2 自定义类在目录中的位置一、什么是 Spring Boot Spring 的诞⽣是为了简化 Java 程序…

《架构300讲》学习笔记(51-100)

前言 内容来自B站IT老齐架构300讲内容。 053动静分离 静态数据&#xff1a;无个性化的数据&#xff0c;静态文件&#xff0c;低频变动的数据。 动态数据&#xff1a;个性化推荐&#xff0c;高频写。 有效的区分页面中的动静数据是优化的关键前提。 页面伪静态化技术&#x…

【Leetcode】308. 二维区域和检索 - 可变

一、题目 1、题目描述 给你一个 2D 矩阵 matrix&#xff0c;请计算出从左上角 (row1, col1) 到右下角 (row2, col2) 组成的矩形中所有元素的和。 实现 NumMatrix 类&#xff1a; NumMatrix(int[][] matrix) 用整数矩阵 matrix 初始化对象。void update(int row, int col, i…

OpenCv相机标定——圆形标定板标定

提取角点时与黑白棋盘格差别主要在于寻找角点的函数&#xff0c;只需将第一章内第二段代码 ret, corners1 cv.findChessboardCorners(img_gray, (w, h)) # 寻找内角点改为 ret, corners1 cv.findCirclesGrid(img_gray, (w, h)) # 寻找内角点&#xff0c;更详细的内容参考第一…

盘点| 能够实现小程序开发提效的框架/工具有这些

近年来&#xff0c;为了研发效率的提升&#xff0c;技术高频革新&#xff0c;开发者们纷纷表示&#xff1a;“好是好&#xff0c;就是快学不动了&#xff01;”。开发者们在不断学习新语言、框架、工具等内容的同时&#xff0c;也在担心所学是否真正有用。而小程序其实能够帮助…

9、Javaweb_http响应概念Response+验证码案例ServletContext+文件下载

HTTP协议&#xff1a; 1. 请求消息&#xff1a;客户端发送给服务器端的数据 * 数据格式&#xff1a; 1. 请求行 2. 请求头 3. 请求空行 4. 请求体 2. 响应消息&#xff1a;服务器端发送给客户端的数据 * 数据格式&#xff1a; …

Nginx 常用配置、操作详解

学习每个技术都要有目标&#xff0c;比如说要源码精通gRPC实现原理&#xff0c;要熟练应用Prometheus、Gin&#xff0c;以及Nginx&#xff0c;Nginx个人定位目标是不需要深入了解技术原理、更不要阅读源码&#xff0c;只需要在自己使用的时候能通过本文章快速检索就够了。 在看…