当前位置:天才代写 > tutorial > Python教程 > python网络编程——IO多路复用之epoll

python网络编程——IO多路复用之epoll

2017-11-02 08:00 星期四 所属: Python教程 浏览:1130

什么是epoll

epoll是什么?在linux的网络编程中,很长的时间都在利用select来干事件触发。在linux新的内核中,有了一种替换它的机制,就是epoll。虽然,这不是2.6内核才有的,它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44),它险些具备了之前所说的一切利益,被公认为Linux2.6下机能最好的多路复用I/O停当通知要领。

对比于select,epoll最大的长处在于它不会跟着监听fd数目标增长而低落效率。因为在内核中的select实现中,它是回收轮询来处理惩罚的,轮询的fd数目越多,自然耗时越多。

epoll事情道理

epoll同样只奉告那些停当的文件描写符,并且当我们挪用epoll_wait()得到停当文件描写符时,返回的不是实际的描写符,而是一个代表停当描写符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描写符即可,这里也利用了内存映射(mmap)技能,这样便彻底省掉了这些文件描写符在系统挪用时复制的开销。

 

另一个本质的改造在于epoll回收基于事件的停当通知方法。在select/poll中,历程只有在挪用必然的要领后,内核才对所有监督的文件描写符举办扫描,而epoll事先通过epoll_ctl()来注册一个文件描写符,一旦基于某个文件描写符停那时,内核会回收雷同callback的回调机制,迅速激活这个文件描写符,当历程挪用epoll_wait()时便获得通知。

从以上可知,epoll是对select、poll模子的改造,提高了网络编程的机能,遍及应用于大局限并发请求的C/S架构中。

python中的epoll

1、触发方法:

     边沿触发/程度触发,只合用于Unix/Linux操纵系统

2、道理图

python网络编程——IO多路复用之epoll

3、一般步调

Create an epoll object——建设1个epoll工具

Tell the epoll object to monitor specific events on specific sockets——汇报epoll工具,在指定的socket上监听指定的事件

Ask the epoll object which sockets may have had the specified event since the last query——询问epoll工具,从上次查询以来,哪些socket产生了哪些指定的事件

Perform some action on those sockets——在这些socket上执行一些操纵

Tell the epoll object to modify the list of sockets and/or events to monitor——汇报epoll工具,修改socket列表和(或)事件,并监控

Repeat steps 3 through 5 until finished——反复步调3-5,直到完成

Destroy the epoll object——销毁epoll工具

4、相关用法

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的节制文件描写符(Return the epoll control file descriptor)

epoll.modfiy(fineno,event)fineno为文件描写符 event为事件范例  浸染是修改文件描写符所对应的事件

epoll.fromfd(fileno)从1个指定的文件描写符建设1个epoll工具

epoll.close()   封锁epoll工具的节制文件描写符

5 实例:客户端发送数据 处事端将吸收的数据返回给客户端

处事端代码

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket
import select
import Queue
#建设socket工具
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#配置IP地点复用
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#ip地点和端标语
server_address = ("127.0.0.1", 8888)
#绑定IP地点
serversocket.bind(server_address)
#监听,并配置最大毗连数
serversocket.listen(10)
print  "处事器启动乐成,监听IP:" , server_address
#处事端配置非阻塞
serversocket.setblocking(False)  
#超时时间
timeout = 10
#建设epoll事件工具,后续要监控的事件添加到个中
epoll = select.epoll()
#注册处事器监听fd到期待读事件荟萃
epoll.register(serversocket.fileno(), select.EPOLLIN)
#生存毗连客户端动静的字典,名目为{}
message_queues = {}
#文件句柄到所对应工具的字典,名目为{句柄:工具}
fd_to_socket = {serversocket.fileno():serversocket,}
while True:
  print "期待勾当毗连......"
  #轮询注册的事件荟萃,返回值为[(文件句柄,对应的事件),(...),....]
  events = epoll.poll(timeout)
  if not events:
     print "epoll超时无勾当毗连,从头轮询......"
     continue
  print "有" , len(events), "个新事件,开始处理惩罚......"
  
  for fd, event in events:
     socket = fd_to_socket[fd]
     #假如勾当socket为当前处事器socket,暗示有新毗连
     if socket == serversocket:
            connection, address = serversocket.accept()
            print "新毗连:" , address
            #新毗连socket配置为非阻塞
            connection.setblocking(False)
            #注册新毗连fd到待读事件荟萃
            epoll.register(connection.fileno(), select.EPOLLIN)
            #把新毗连的文件句柄以及工具生存到字典
            fd_to_socket[connection.fileno()] = connection
            #以新毗连的工具为键值,值存储在行列中,生存每个毗连的信息
            message_queues[connection]  = Queue.Queue()
     #封锁事件
     elif event & select.EPOLLHUP:
        print 'client close'
        #在epoll中注销客户端的文件句柄
        epoll.unregister(fd)
        #封锁客户端的文件句柄
        fd_to_socket[fd].close()
        #在字典中删除与已封锁客户端相关的信息
        del fd_to_socket[fd]
     #可读事件
     elif event & select.EPOLLIN:
        #吸收数据
        data = socket.recv(1024)
        if data:
           print "收到数据:" , data , "客户端:" , socket.getpeername()
           #将数据放入对应客户端的字典
           message_queues[socket].put(data)
           #修改读取到动静的毗连到期待写事件荟萃(即对应客户端收到动静后,再将其fd修改并插手写事件荟萃)
           epoll.modify(fd, select.EPOLLOUT)
     #可写事件
     elif event & select.EPOLLOUT:
        try:
           #从字典中获取对应客户端的信息
           msg = message_queues[socket].get_nowait()
        except Queue.Empty:
           print socket.getpeername() , " queue empty"
           #修改文件句柄为读事件
           epoll.modify(fd, select.EPOLLIN)
        else :
           print "发送数据:" , data , "客户端:" , socket.getpeername()
           #发送数据
           socket.send(msg)
#在epoll中注销处事端文件句柄
epoll.unregister(serversocket.fileno())
#封锁epoll
epoll.close()
#封锁处事器socket
serversocket.close()

#p#分页标题#e#

客户端代码:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket
#建设客户端socket工具
clientsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#处事端IP地点和端标语元组
server_address = ('127.0.0.1',8888)
#客户端毗连指定的IP地点和端标语
clientsocket.connect(server_address)
while True:
    #输入数据
    data = raw_input('please input:')
    #客户端发送数据
    clientsocket.sendall(data)
    #客户端吸收数据
    server_data = clientsocket.recv(1024)
    print '客户端收到的数据:'server_data
    #封锁客户端socket
    clientsocket.close()

 

    关键字:

天才代写-代写联系方式