IO操作主要包括两类:

  • 本地IO

  • 网络IO

本地IO:本地IO是指本地的文件读取等操作,本地IO的优化主要是在操作系统中进行,我们对于本地IO的优化作用十分有限

网络IO:网络IO指的是在进行网络操作时需要等待用户的输入及传输的等待等,网络IO的优化需要我们自己进行,而我们对于网络IO的优化主要在等待用户输入时程序可以继续运行

1、IO阻塞模型

什么是IO阻塞模型

在我们使用socket创建客户端、服务端时,如果不对 他们执行其他操作,那么客户端的recv、send和服务器端的accept、send、recv等都是阻塞的,只有等到有数据传输过来或者有客户端连接过来时才会操作,否则就会进入等待状态,这种模型就是IO阻塞模型

IO阻塞模型的缺点

使用IO阻塞模型时,客户端的影响较小,但是对于服务器端,由于要处理多个客户端的请求,所以如果使用阻塞模型,那么同一时间只能有一个客户端进行连接,效率十分低,不能进行并发

2、IO非阻塞模型

什么是IO非阻塞模型

由于在使用网络IO时,在不进行任何处理的情况下默认是会阻塞的,但是如果不想程序进行阻塞,此时可以通过设置setblocking来实现,这样在进行原本会阻塞的操作时,如果有数据就会对数据进行处理,如果没有数据则会直接报错,只要进行异常的捕捉就能使程序进行后续代码的执行,这样可以实现IO非阻塞

示例代码:

客户端

import socket

client = socket.socket()
client.connect(("127.0.0.1",1688))

while True:
msg = input("msg:").strip()
if not msg:
continue
try:
client.send(msg.encode("utf-8"))
recv_msg = client.recv(2048)
print(recv_msg.decode("utf-8"))
except ConnectionResetError:
print("客户端意外关闭")
break

服务器

import socket

server = socket.socket()
server.bind(("127.0.0.1",1688))
server.listen()
server.setblocking(False)

conn_list = []
msg_list = []

while True:
try:
conn,addr = server.accept()
conn_list.append(conn)
except BlockingIOError:
print("还没有客户端连接")
for conn in conn_list:
try:
msg = conn.recv(1024)
msg_list.append((conn,msg))
except BlockingIOError:
print("该用户没有数据传输过来")
for msg_t in msg_list:
conn,msg = msg_t
try:
conn.send(msg.upper())
msg_list.remove(msg_t)
except ConnectionResetError:
print("信息无法发送")
conn.close()
conn_list.remove(conn)
                

IO非阻塞模型的缺点

使用IO非阻塞模型,我们解决了不能实现并发的缺点,在一个线程中实现了并发,但是IO非阻塞模型存在一些问题,最主要的问题是,在使用非阻塞模型时,由于需要不停的进行询问,所以会持续的消耗系统的CPU资源,造成不必要的CPU占用

3、多路复用IO模型

在使用非阻塞IO模型处理问题时,虽然解决了不能在单个线程中实现并发的问题,但是由于需要不停的进行询问,所以就会造成CPU的不必要占用,造成CPU占用过高的问题

什么是多路复用IO模型

多路复用IO模型指的是多个TCP连接使用一个或者少量的线程来实现通信的IO模型,在IO非阻塞模型中,我们是通过自己不停的使用send()或者recv()来不停的询问是否有数据需要进行操作,在多路复用IO模型中,我们使用select统一的来进行询问,并将可以进行操作的对象放到一个列表中进行统一管理,并且select还可以区分那些是可以发送数据的对象,哪些是可以接收数据的对象,并放在不同的列表中进行统一管理

示例代码:

客户端

import socket

client = socket.socket()
client.connect(("127.0.0.1",1688))

while True:
try:
msg = input("msg:").strip()
if not msg:
continue
client.send(msg.encode("utf-8"))
recv_msg = client.recv(1024).decode("utf-8")
print(recv_msg)
except ConnectionResetError:
print("服务器已关闭")
break

服务器端

import socket
import select

server = socket.socket()
server.bind(("127.0.0.1",1688))
server.listen()

r_list = [server,]
w_list = []
msg_list = []
while True:
readable_list,writeable_list,_ = select.select(r_list,w_list,[])
for conn in readable_list:
if conn == server:
conn,addr = conn.accept()
r_list.append(conn)
else:
try:
msg = conn.recv(1024)
if not msg:
raise ConnectionResetError
msg_list.append((conn,msg))
w_list.append(conn)
except ConnectionResetError:
print("%s客户端正常关闭" %conn)
r_list.remove(conn)
if conn in w_list:
w_list.remove(conn)
conn.close()
for conn in w_list:
for msg_t in msg_lis[:]:
connection,msg = msg_t
if conn == connection:
try:
connection.send(msg.upper())
            msg_list.remove(msg_t)
except ConnectionResetError:
msg_list.remove(msg_t)
w_list.remove(conn)

msg_list.remove(msg_t)
w_list.remove(conn)
 

多路复用的缺点:

使用多路复用解决了在非阻塞IO中出现的CPU占用过高的问题,但是在多路复用中也出现了几个问题:

  • 使用select时最多只能处理1024个客户端,如果数量多与此值,那么就会直接就会报错

  • 如果发送的数据量特别大的情况下只能处理一个客户端,其它的客户端只能进行等待

最新文章

  1. React Native开发之npm start加速
  2. 我的Eclipse快捷键.
  3. string类find函数返回值判定
  4. JavaScript数组API
  5. android 自定义弹出框AlertDialog ,很炫的哦
  6. 修改RMAN list命令输出的时间格式
  7. Unity3D 5.1烘培 操作
  8. Map的遍历
  9. HDU4519
  10. 玩转Android之二维码生成与识别
  11. jdk1.8中的for循环
  12. 休息,归类一下CSS初级的东西
  13. linux PMBus总线及设备驱动分析
  14. ip地址扫描
  15. JavaWeb开发SSM框架搭建详解
  16. FL studio钢琴卷工具简介
  17. FJUT3703 这还是一道数论题(二分 + hash + manacher 或者 STL + hash 或者 后缀数组 + hash)题解
  18. python django day 5 database 1
  19. JS获取整个网页html代码
  20. Android 沉浸式顶部

热门文章

  1. 19、属性赋值-@PropertySource加载外部配置文件
  2. scrapy 4 学习 crawl spider
  3. appium测试android环境搭建(win7)
  4. D. AB-string ( 思维 )
  5. 【csp模拟赛6】树上统计-启发式合并,线段树合并
  6. open, create, close
  7. kubernets安装rabbitmq集群.
  8. 2016"百度之星" - 初赛(Astar Round2A)1001 All X(HDU5690)——找循环节|快速幂
  9. 解决tomcat7控制台中文乱码问题
  10. 异步机制 - ReadFileEx(WriteFileEx)