参考文章地址:http://www.cnblogs.com/yuanchenqi/articles/5722574.html
两个步骤:
recvfrom 系统调用 ; 拷贝数据 从kernel到数据
- 阻塞IO:在IO执行两个阶段进程都被阻塞(1. kernel 准备数据,等待数据到来 2. kernel 将数据拷贝到用户态)
- 非阻塞IO:第一步不阻塞,第二部拷贝数据阻塞(弊端:1. 多次询问 2. 数据不能及时同步)
- IO 多路复用(IO multiplexing):
又叫 ‘事件驱动IO’
select、epoll 的好处是单个 process 可以同时处理多个网络连接的IO。它的基本原理是select、epoll这个function会不断地轮询所有的socket,当某个socket有数据到达了,就通知用户进程。
select 是一个函数,进行数据监听。当调用这个函数时,他会发一个系统调用,监听数据是否到达。(进程会被阻塞,这个过程是 select 这个函数阻塞的)
当 select 告诉进程数据到达之后,进程需要多做一件事情,仍然要使用 recvfrom 进行 system call:告诉内核将数据拷贝到进程(此过程进程也会被阻塞)
好处:select 可以监听多个描述符,完成并发的效果。 跨平台
4. 异步IO:
完全没有阻塞,用户进程发起read 操作之后,kernel如果还没有将数据准备好,会立即返回。这个时候进程可以去做其他的事情,当数据准备好并且kernel将数据拷贝到内存时,kernal会给进程发一个singal信号,告诉他read操作已经完成。
select、poll、epoll IO多路复用:
epoll 真正解决了 select 的轮询问题,但它是同步IO
server:
# _author: lily # _date: 2019/2/1 import socket import time sk = socket.socket() adress = ('127.0.0.1', 8080) sk.bind(adress) sk.listen(3) sk.setblocking(False) while 1: try: conn, addr = sk.accept() while 1: data = conn.recv(1024) print(data.decode('utf8')) conn.sendall(data) conn.close() except Exception as e: print(' no data: ', e) time.sleep(3)
client:
# _author: lily # _date: 2019/2/1 import socket sk = socket.socket() adress = ('127.0.0.1', 8080) sk.connect(adress) while 1: # inp = input('>>') sk.sendall('hello'.encode('utf8')) data = sk.recv(1024) print(data.decode('utf8')) sk.close()