IO的模型:
了解概念:
阻塞I/O:应用程序执行I/O操作后,如果没有获得响应,就会阻塞当 前线程,自然就不能执行其他任务
非阻塞I/O:应用程序执行I/O操作后,不会阻塞当前的线程,可以继续执 行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果
同步I/O:应用程序执行I/O操作后,要一直等到整个I/O完成后,才能获 得I/O响应
异步I/O:应用程序执行I/O操作后,不用等待完成和完成后的响应,而是 继续执行就可以
阻塞IO(blocking IO)
在Linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:
当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的udp包),这个时候kernel就要等待足够的数据到来
而在用户进程这边,整个进程会被阻塞,当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存
然后kernel返回结果,用户进程才解除block的状态,重新运行起来
所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了
实际上,除非特别指定,几乎所有的IO接口(包括socket接口)都是阻塞型的。这给网络编程带来了一个很大的问题。如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。
下面使用python代码来演示:
服务端:
from socket import *
from threading import Thread
def communicate(conn):
while True:
try:
data = conn.recv(1024)
if not data:
break
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
print('starting...')
conn,addr = server.accept()
print(addr)
t = Thread(target=communicate, args=(conn,))
t.start()
server.close()
客户端:
from socket import *
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
msg = input("请输入数据:").strip()
if not msg:
continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
client.close()
打开多个客户端,进行发送消息,多发送几次就会出现堵塞的情况:
客户端发送的信息,服务器没有及时返回结果
欢迎来到testingpai.com!
注册 关于