IO多路复用(linux epoll)

epoll必须在linux系统下才能使用!!!

1.非阻塞套接字的弊端

虽然非阻塞套接字解决了多个客户端连接的问题,但仍存在着不完美之处

  • 任何python都是要花费cpu资源的
  • 如果数据还没有到达,那么accept、recv和send(在connect没有完成之前),一直在无效的浪费cpu资源
  • 对应BlockingIOError的异常处理也是无效的cpu花费

2.epoll才是真正的完美的交互方式

IO多路复用技术

在这里socket则交给了操作系统去监控。以往的版本中,用户进程一直等待操作系统查询是否有数据到来,未到达则一直查询,用户进程一直等待。而epoll则是操作系统监控socket,用户进程处理自己的事务,定期去询问操作系统是否有数据到来,若未到,继续处理自己的事务,到达便接收。

epoll是惰性的事件回调

事件回调:函数中传入函数名和判断条件,若满足条件则调用函数,否则不调用

惰性:操作系统判断事件是否回调,但不会执行回调操作,提醒用户进程执行,只起通知作用

流程:用户进程创建套接字和回调函数,并通知操作系统在套接字上注册回调函数,于是操作系统开始监控提交上来的套接字

           用户进程会定期查询已准备好资源的套接字(有数据传输的套接字),操作系统返回回调函数与已准备好资源的套接字

           用户进程进行事件回调

epoll是目前Linux上效率最高的IO多路复用 技术!

IO多路复用选择器(epoll选择器)

只有使用epoll选择器才能实现事件回调

import selectors

epoller = selectors.EpollSelector() #实例化一个epoll选择器

注册惰性回调事件

事件回调

完整代码

服务端

import selectors
import socket

epoller = selectors.EpollSelector() #实例化一个epoll选择器
sever = socket.socket() #创建套接字
sever.bind(('',8800)) #绑定
sever.listen(100) #监听
def creat_connection(sever):
    print("已连接",sever)
    conn,addr=sever.accept()
    epoller.register(conn, selectors.EVENT_READ, read_data) #注册到数据接收回调函数
    return conn
epoller.register(sever,selectors.EVENT_READ,creat_connection) #epoll选择器注册到连接回调函数
def read_data(conn):
    data=conn.recv(1024)
    if data:
      print(data)
      conn.send(data)
    else:
      print("已断开",conn)
      epoller.unregister(conn)
      conn.close()
while True:
    event = epoller.select() #查询,返回已准备好资源的打包对象
    for key,mask in event: #多个客户端,多个对象
        sock = key.fileobj #事件
        callback = key.data #回调函数
        callback(sock)




客户端

import socket

client = socket.socket()

client.connect(('127.0.0.1',8800))

while True:
    data = input('please write the message:')
    client.send(data.encode())
    print(client.recv(1024))
    if data == 'Q' or data == 'q':
        break

client.close()

运行结果

猜你喜欢

转载自blog.csdn.net/weixin_42089175/article/details/81624043