epoll 的使用
admin
2023-07-31 01:53:22
0

#

epoll的应用很多,nginx,tornado,乃至携程,都跟它又关系.所以趁着失业的无聊的事件,从基础学起,了解下epoll的用法

epoll 在python的api

Python包含了访问Linux epoll库的API。这篇文章用几个简单的例子来展示下这个API

常用api

select.epoll() #返回创建epoll对象
epoll.register(fd[, eventmask]) #将fd的事件注册到epoll对象中
epoll.unregister(fd) #去除fd
epoll.poll([timeout=-1[, maxevents=-1]]) #等待事件
epoll.modify(fd, eventmask) #更改fd关注的事件

更多api文档,可以在dash中查看

常用事件常量

EPOLLIN     可读事件
EPOLLOUT    可写事件
EPOLLERR    错误事件
EPOLLHUP    挂起事件

示例代码

以下是简单的helloword 程序,运行程序后,浏览器访问localhost:8080/ 输出helloword

# coding: utf-8
import socket, select
from ipdb import set_trace
EOL1 = b\'\\n\\n\'
EOL2 = b\'\\n\\r\\n\'
response  = b\'HTTP/1.0 200 OK\\r\\nDate: Mon, 1 Jan 1996 01:01:01 GMT\\r\\n\'
response += b\'Content-Type: text/plain\\r\\nContent-Length: 13\\r\\n\\r\\n\'
response += b\'Hello, world!\'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.bind((\'0.0.0.0\', 8080))
serversocket.listen(10240)
serversocket.setblocking(0)
serversocket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

#创建epoll对象,epoll对象是个存储\"fd-事件\"的容器,把关注的\"fd-事件\"注册到容器中,
#接下来就可以监听到fd的事件
epoll = select.epoll()

#将server的sockect注册到epoll中,因为此示例程序功能是浏览器显示helloword,
#所以关注接入的客户端fd,当有客户端连接时,出发的一定是server sockect的EPOLLIN
epoll.register(serversocket.fileno(), select.EPOLLIN)

try:
   connections = {}; requests = {}; responses = {}
   while True:
      events = epoll.poll(10)
      # print \'==\'*10
      for fileno, event in events:
         #客户端接入时,注册客户端fd到epoll,第一步需要读取客户端发送到服务端的信息,所以用EPOLLIN
         if fileno == serversocket.fileno():
            connection, address = serversocket.accept()
            connection.setblocking(0)
            epoll.register(connection.fileno(), select.EPOLLIN)
            connections[connection.fileno()] = connection
            requests[connection.fileno()] = b\'\'
            responses[connection.fileno()] = response
         #读取客户端信息
         elif event & select.EPOLLIN:
            data=connections[fileno].recv(1024)

            requests[fileno] += data
            #判断客户端信息是否读取完毕
            if EOL1 in requests[fileno] or EOL2 in requests[fileno]:
               epoll.modify(fileno, select.EPOLLOUT)
               print(\'-\'*40 + str(fileno) + \'\\n\' + requests[fileno].decode()[:-2])
            #处理客户端关闭请求时的信息,防止服务端程序出现close_wait
            #使用telnet测试后发现,客户端主动关闭时会发送个空信息到客户端,不处理的话,会出现close_wait,
            #并且循环中每次都会出现该事件,会严重影响程序处理效率,因此需要把它从epoll重移除
            if data == b\'\':
               print \"receiv client close : %s \"% str(fileno)
               epoll.unregister(fileno)
               try :
                  connections[fileno].close()
               except Exception, e:
                  print \' connection was allready closed.....\'+e
         #将此接入返回给客户端
         elif event & select.EPOLLOUT:
            byteswritten = connections[fileno].send(responses[fileno])
            responses[fileno] = responses[fileno][byteswritten:]
            if len(responses[fileno]) == 0:
               epoll.modify(fileno, 0)
               try:
                  connections[fileno].shutdown(socket.SHUT_RDWR)
               except Exception, e:
                  print \' connection was allready closed.....\' + e
         #服务端主动关闭连接时的逻辑处理
         elif event & select.EPOLLHUP:
            print \"close fd : %s \"% str(fileno)
            epoll.unregister(fileno)
            connections[fileno].close()
            del connections[fileno]
         else :
            print \'=\'*10
            print fileno,event
finally:
   # set_trace()
   epoll.unregister(serversocket.fileno())
   epoll.close()
   serversocket.close()

总结

这段程序大部分摘抄自http://scotdoyle.com/python-epoll-howto.html
但经过测试发现他的程序有些bug.
使用telnet测试后发现,客户端主动关闭时会发送个空信息到客户端,不处理的话,会出现close_wait.
并且循环中每次都会出现该事件,会严重影响程序处理效率,因此需要把它从epoll重移除.
原因发生tcp协议中四次握手时,客户端的关闭消息没有被处理

理解这些bug对epoll使用很有帮助

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...