引子

在介绍libevent之前,首先抛出一个问题,如果让你设计一个高性能的服务架构,要求服务端能够处理多个客户端连接并响应客户端的请求,如图1所示,你会如何设计?
一个比较直观的想法是在服务端,每来一个客户端连接,即开启一个线程去处理并响应,这种设计的优点是简单易懂,缺点也很明显,如果客户端连接比较多,需要开启多个线程去处理,而操作系统开启线程是需要一定代价的,服务端在多个线程间切换也是比较消耗资源的;另外,多个线程操作临界资源时会带来锁竞争问题,当连接数比较多时竞争会非常激烈。那么接下来,我将介绍一种比较经典的处理方式,学习完之后,也许对于这个系统的设计会有不同的答案。
前置知识
在介绍之前,首先说明几个概念。
-
I/O多路复用
进程需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪(也就是说输入已准备好,或者描述符已经承接更多的输出),它就通知进程,这种能力称为I/O复用。IO多路复用是一种同步IO模型,实现一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪时会阻塞应用程序,交出cpu。多路是指网络连接,复用指的是同一个线程。 -
用户空间和内核空间
现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间,如图2所示。这里还有一个比较重要的概念,叫DMA(Direct Memory Access直接存储器访问),它的作用是处理各种I/O,包括网络I/O和磁盘I/O。CPU是不会直接处理I/O的,这是因为CPU非常宝贵,而I/O是比较耗时的,如果CPU一直等待某一次I/O事件完成,会带来极大的浪费,且性能会急剧下降,因此需要一种机制能够完成I/O,并通知CPU,DMA即是这个角色。

从图2中可以看到,对于一次I/O访问,数据会先被拷贝到内核空间中,然后才会拷贝到用户空间中供应用程序使用,所以在这个过程中会经历两个阶段(对应图2中的1,2两个步骤):
- 等待数据准备
- 将数据从内核空间拷贝到进程中
正是因为这两个阶段,linux系统中产生了两大类网络模式
- 同步I/O
- 阻塞I/O
- 非阻塞IO
- I/O多路复用
- 信号驱动I/O(使用较少)
- 异步I/O
同步I/O和异步I/O主要区别在于:
用户进程在发起I/O操作之后可以立刻去做其他事情,数据拷贝由硬件拷贝到内核空间、从内核空间拷贝到用户空间都不阻塞,这种就是异步I/O;两个步骤中有任何一步发生阻塞,就是同步I/O。
同步I/O又细分了很多模式,它们的区别是:
| 同步I/O模式 | 详细说明 |
|---|---|
| 阻塞I/O | 在步骤1即阻塞 |
| 非阻塞I/O | 步骤1不阻塞,需轮询;步骤2阻塞 |
| I/O多路复用 | 与阻塞I/O一样,优点是可以处理多个连接 |
阻塞I/O典型代码(大部分socket接口都是阻塞型的,当然可以设置为非阻塞,以python语言为例,主要是代码简单清晰,其他语言类似)
## 客户端
import socket
sk = socket.socket()
sk.connect(('0.0.0.0', 9600))
while True:
msg = input('>>>>')
sk.send(msg.encode())
if msg.lower() == 'quit':
break
ret = sk.recv(1024)
if ret.lower() == 'quit':
break
print(ret.decode())
sk.close()
#########################################################################
## 服务端
import socket
# 默认TCP,参数可以不写
sk = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
sk.bind(('0.0.0.0', 9600))
sk.listen(1)
while True:
conn, ip_addr =</

最低0.47元/天 解锁文章
8438

被折叠的 条评论
为什么被折叠?



