• day34-2 多路复用之epoll


    epoll

    select存在的问题

      1. select,需要遍历socket列表,频繁的对等待队列进行添加移除操作
      1. 数据到达后还需要遍历所有的socket才能获知哪些socket有数据

    两个操作消耗的时间随着要监控的socket的数量增加而大大增加,所以最大只能监视1024个socket。

    于是就推出了epoll,epoll对问题一方案是把等待队列的维护与阻塞进程这两个操作分开了

    对问题2是自己维护了一个等待队列,避免了遍历所有的socket。需要注意:epoll仅能在linux中使用

    epoll相关函数

    import select  # 导入select模块
    epoll = select.epoll()  # 创建一个epoll对象
    
    epoll.register(文件句柄,事件类型)  # 注册要监视的文件句柄和事件
    # 事件类型:
    	select.EPOLLIN  # 可读事件
        select.EPOLLOUT  # 可写事件
        select.EPOLLERR  # 错误事件
        select.EPOLLHUP  # 客户端断开事件
        
    epoll.unregister(文件句柄)  # 销毁文件句柄
    
    epoll.poll(timeout)  # 当文件句柄发生变化,则会以列表的形式主动报告给用户进程,timeout为超时时间,默认为-1,即一直等待直到文件句柄发生变化,如果指定为1,那么epoll每1秒汇报一次当前文件句柄的变化情况,如果无变化则返回空
    
    epoll.fileno()  # 返回epoll的控制文件描述符
    epoll.modify(fineno, event)  # 修改文件描述符所对应的事件
    epoll.fromfd(filena)  # 从1个指定的文件描述符创建1个epoll对象
    epoll.close()  # 关闭epoll对象的控制文件描述符
    

    案例

    import select
    from socket import *
    
    server = socket()
    server.bind(('127.0.0.1', 8000))
    server.listen(5)
    
    # 创建一个epoll对象
    epoll = select.epoll()
    
    # 注册读就绪事件(有数据可以读取了)
    # s.fileno()用于获取文件描述符
    epoll.register(server.fileno(), select.EPOLLIN)
    
    # 存储文件描述符与socket的对应关系
    fd_socket = {server.fileno(): server}
    
    msgs = []
    
    while True:
        # 会阻塞,直到你关注的事件发生
        for fd, event in epoll.poll():
            sock = fd_socket[fd]
            print(fd, event)
            # 返回的是文件描述符,需要获取对用socket
            if sock == server:
                client, addr = server.accept()
                # 注册客户端写就绪
                epoll.register(client.fileno(), select.EPOLLIN)
                # 添加对应关系
                fd_socket[client.fileno()] = client
    
            # 读就绪
            elif event == select.EPOLLIN:
                data = sock.recv(1024)
                if not data:
                    # 注销事件
                    epoll.unregister(fd)
                    # 关闭socket
                    socket.close()
                    # 删除socket对应关系
                    del fd_socket[fd]
                    print("somebody ....")
                    continue
                print(data.decode('utf8'))
                # 读完数据,需要把数据发回去。所以接下来更改为写就绪事件
                epoll.modify(fd, select.EPOLLOUT)
                # 记录数据
                msgs.append((sock, data.upper()))
            elif event == select.EPOLLOUT:
                for item in msgs[:]:
                    if item[0] == sock:
                        sock.send(item[1])
                        msgs.remove(item)
                # 切换关注事件为写就绪
                epoll.modify(fd, select.EPOLLIN)
    
  • 相关阅读:
    6.素数和(素数的判断)
    6.素数和(素数的判断)
    5.明明的随机数(桶排序经典例题)
    5.明明的随机数(桶排序经典例题)
    5.明明的随机数(桶排序经典例题)
    5.明明的随机数(桶排序经典例题)
    Algs4-1.2.11根据Date的API实现一个SmartDate类型
    Algs4-1.2.10编写一个类VisualCounter
    Algs4-1.2.9使用Counter统计BinarySearch检查的key个数
    Algs4-1.2.8引用型变量赋值-数组复制
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11166025.html
Copyright © 2020-2023  润新知