python的epoll及EPOLLLT

本文介绍了一个使用 Python 的 epoll 进行双向通信的例子。通过客户端和服务端的代码展示如何利用 epoll 处理输入输出事件,避免 LT 模式下未清空缓冲区导致的重复触发问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天没事练习python的epoll,一开始写了个客户端:

#! /usr/python

import socket,sys,select

c=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = '127.0.0.1'
port=57777
c.connect((host,port))

epoll_fd = select.epoll()

epoll_fd.register(c.fileno(),select.EPOLLIN)
epoll_fd.register(sys.stdin.fileno(), select.EPOLLIN)
str=""
while True:
    e_list = epoll_fd.poll()
    for fd,events in e_list:
      if fd == c.fileno() and events&select.EPOLLIN:
        buf =  c.recv(1024)
        if not len(buf):
           break
        print "ser:",buf
      if fd == c.fileno() and events & select.EPOLLOUT:
        #print 'send msg to ser.'
        c.send(str)
        epoll_fd.modify(c.fileno(), select.EPOLLIN)
      if fd == sys.stdin.fileno() and events & select.EPOLLIN:
        str="ssf"
        epoll_fd.modify(c.fileno(), select.EPOLLOUT)

c.close()

发现服务端总是进入死循环收信息,甚是迷惑。后来修改了 str="ssf"处,修改为raw_input,发现程序正常运行,恍然醒悟,epoll默认

是LT模式,缓冲里的数据没读走,是每次都会触发的,因此,上面的代码修改epoll_fd.register(sys.stdin.fileno(), select.EPOLLIN)

epoll_fd.register(sys.stdin.fileno(), select.EPOLLIN|select.EPOLLOUT) 也是能正常工作的。

附上最终代码:

client.py

 

#! /usr/python

import socket,sys,select

c=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = '127.0.0.1'
port=57777
c.connect((host,port))

epoll_fd = select.epoll()

epoll_fd.register(c.fileno(),select.EPOLLIN)
epoll_fd.register(sys.stdin.fileno(), select.EPOLLIN)
str=""
while True:
    e_list = epoll_fd.poll()
    for fd,events in e_list:
      if fd == c.fileno() and events&select.EPOLLIN:
        buf =  c.recv(1024)
        if not len(buf):
           break
        print "ser:",buf
      if fd == c.fileno() and events & select.EPOLLOUT:
        #print 'send msg to ser.'
        c.send(str)
        epoll_fd.modify(c.fileno(), select.EPOLLIN)
      if fd == sys.stdin.fileno() and events & select.EPOLLIN:
        str=raw_input("me: ")
        epoll_fd.modify(c.fileno(), select.EPOLLOUT)

c.close()

 

简单的server和client相似

import socket, os,select,sys

host='127.0.0.1'
port=57777

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(10)

epoll_obj=select.epoll()

epoll_obj.register(sys.stdin.fileno(), select.EPOLLIN)

print 'wait for connect'

cs,caddr=s.accept()
epoll_obj.register(cs.fileno(), select.EPOLLIN)
str=""
while 1:
    readylist = epoll_obj.poll()
    for fd,event in readylist:
        if fd == cs.fileno() and event & select.EPOLLIN:
            buf = cs.recv(128)
            if not len(buf):
                cs.close()
                break
            print "cli: ", buf

        if fd == cs.fileno() and event & select.EPOLLOUT:
            cs.send(str)
            epoll_obj.modify(cs.fileno(), select.EPOLLIN)

        if fd == sys.stdin.fileno() and event&select.EPOLLIN:
            str=raw_input("me:")
            epoll_obj.modify(cs.fileno(), select.EPOLLOUT)

 

转载于:https://www.cnblogs.com/lijinping/p/5946190.html

### epoll与select、poll的主要区别 #### 1. 文件描述符管理方式 - **select** 和 **poll** 需要轮询所有注册的文件描述符来查找已准备好的操作,这在高并发环境下效率低下。相比之下,**epoll** 使用红黑树结构存储感兴趣的文件描述符,并利用事件驱动的方式仅关注状态变化的文件描述符[^3]。 #### 2. 性能表现 - 对于大量的监听套接字来说,每次调用 `select` 或者 `poll` 函数都会扫描整个集合中的每一个成员以判断是否有可读写的数据流;然而,在Linux下的 **epoll** 中引入了更高效的机制——它不会每次都去遍历全部项而是直接获取到那些确实发生了改变的对象列表[^4]。 #### 3. 并发处理能力 - **select** 存在一个硬性的最大文件句柄数限制(通常为1024),而 **poll** 和 **epoll** 则不存在这样的约束条件,能够很好地适应现代互联网应用对于海量连接的需求。 #### 4. 工作模式支持 - 不同于其他两种方法只提供水平触发(Level Triggered, LT),即只要满足条件就会一直触发直到被消费掉为止;**epoll** 还额外提供了边缘触发(Edge Triggered, ET)这种更为先进的工作机制,允许应用程序更加精细地控制何时以及如何响应特定类型的I/O活动[^5]。 ### 应用场景分析 针对不同的网络编程需求: - 当面对较小规模的同时在线用户量级时可以选择较为简单的 **select** 来实现基本的功能; - 如果项目涉及到较多但又不是极其庞大的客户端数目,则可以考虑采用灵活性较好的 **poll** 方案来进行开发; - 对于那种需要支撑极高密度通信流量的服务端程序而言,显然基于高性能特性和良好扩展性的 **epoll** 将成为首选解决方案之一,尤其是在Linux平台上运行的应用中更是如此。 ```python import selectors sel = selectors.DefaultSelector() def accept(sock, mask): conn, addr = sock.accept() # Should be ready to read print('accepted', conn, 'from', addr) sel.register(conn, selectors.EVENT_READ, read) def read(conn, mask): data = conn.recv(1000) # Should be ready to read if data: print('echoing', repr(data), 'to', conn) conn.send(data) # Hope it won't block else: print('closing', conn) sel.unregister(conn) conn.close() sock.bind(('localhost', 1234)) sock.listen(100) sock.setblocking(False) sel.register(sock, selectors.EVENT_READ, accept) while True: events = sel.select() for key, mask in events: callback = key.data callback(key.fileobj, mask) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值