python epoll多路复用_Python异步非阻塞IO多路复用Select/Poll/Epoll使用

下面记录下分别基于Select/Poll/Epoll的echo server实现。

Python Select Server,可监控事件数量有限制:

#!/usr/bin/python

# -*- coding: utf-8 -*-

importselect

importsocket

importQueue

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

server.setblocking(False)

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR , 1)

server_address=('192.168.1.5',8080)

server.bind(server_address)

server.listen(10)

#select轮询等待读socket集合

inputs=[server]

#select轮询等待写socket集合

outputs=[]

message_queues={}

#select超时时间

timeout=20

whileTrue:

print"等待活动连接......"

readable , writable , exceptional =select.select(inputs, outputs, inputs, timeout)

ifnot (readable orwritable orexceptional) :

print"select超时无活动连接,重新select...... "

continue;

#循环可读事件

fors inreadable :

#如果是server监听的socket

ifs isserver:

#同意连接

connection, client_address =s.accept()

print"新连接: ", client_address

connection.setblocking(0)

#将连接加入到select可读事件队列

inputs.append(connection)

#新建连接为key的字典,写回读取到的消息

message_queues[connection]=Queue.Queue()

else:

#不是本机监听就是客户端发来的消息

data=s.recv(1024)

ifdata :

print"收到数据:" , data , "客户端:",s.getpeername()

message_queues[s].put(data)

ifs notin outputs:

#将读取到的socket加入到可写事件队列

outputs.append(s)

else:

#空白消息,关闭连接

print"关闭连接:", client_address

ifs inoutputs :

outputs.remove(s)

inputs.remove(s)

s.close()

delmessage_queues[s]

fors inwritable:

try:

msg=message_queues[s].get_nowait()

exceptQueue.Empty:

print"连接:" , s.getpeername() , '消息队列为空'

outputs.remove(s)

else:

print"发送数据:" , msg , "到", s.getpeername()

s.send(msg)

fors inexceptional:

print"异常连接:", s.getpeername()

inputs.remove(s)

ifs inoutputs:

outputs.remove(s)

s.close()

delmessage_queues[s]

Python Poll Server,Select升级版,无可监控事件数量限制,还是要轮询所有事件:

#!/usr/bin/python

# -*- coding: utf-8 -*-

importsocket

importselect

importQueue

server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.setblocking(False)

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server_address=("192.168.1.5",8080)

server.bind(server_address)

server.listen(5)

print "服务器启动成功,监听IP:" , server_address

message_queues={}

#超时,毫秒

timeout=5000

#监听哪些事件

READ_ONLY=( select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR)

READ_WRITE=(READ_ONLY|select.POLLOUT)

#新建轮询事件对象

poller=select.poll()

#注册本机监听socket到等待可读事件事件集合

poller.register(server,READ_ONLY)

#文件描述符到socket映射

fd_to_socket={server.fileno():server,}

whileTrue:

print"等待活动连接......"

#轮询注册的事件集合

events=poller.poll(timeout)

ifnot events:

print"poll超时,无活动连接,重新poll......"

continue

print"有" , len(events),"个新事件,开始处理......"

forfd ,flag inevents:

s=fd_to_socket[fd]

#可读事件

ifflag & (select.POLLIN | select.POLLPRI) :

ifs isserver :

#如果socket是监听的server代表有新连接

connection , client_address =s.accept()

print"新连接:" , client_address

connection.setblocking(False)

fd_to_socket[connection.fileno()]=connection

#加入到等待读事件集合

poller.register(connection,READ_ONLY)

message_queues[connection] =Queue.Queue()

else:

#接收客户端发送的数据

data=s.recv(1024)

ifdata:

print"收到数据:" , data , "客户端:", s.getpeername()

message_queues[s].put(data)

#修改读取到消息的连接到等待写事件集合

poller.modify(s,READ_WRITE)

else:

# Close the connection

print" closing" , s.getpeername()

# Stop listening for input on the connection

poller.unregister(s)

s.close()

delmessage_queues[s]

#连接关闭事件

elifflag & select.POLLHUP :

print" Closing ", s.getpeername() ,"(HUP)"

poller.unregister(s)

s.close()

#可写事件

elifflag & select.POLLOUT :

try:

msg=message_queues[s].get_nowait()

exceptQueue.Empty:

prints.getpeername() , " queue empty"

poller.modify(s,READ_ONLY)

else:

print"发送数据:" , data , "客户端:", s.getpeername()

s.send(msg)

#异常事件

elifflag & select.POLLERR:

print" exception on" , s.getpeername()

poller.unregister(s)

s.close()

delmessage_queues[s]

Python Epoll Server,基于回调的事件通知模式,轻松管理大量连接:

#!/usr/bin/python

# -*- coding: utf-8 -*-

importsocket, select

importQueue

serversocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server_address=("192.168.1.5",8080)

serversocket.bind(server_address)

serversocket.listen(1)

print "服务器启动成功,监听IP:" , server_address

serversocket.setblocking(0)

timeout=10

#新建epoll事件对象,后续要监控的事件添加到其中

epoll=select.epoll()

#添加服务器监听fd到等待读事件集合

epoll.register(serversocket.fileno(), select.EPOLLIN)

message_queues={}

fd_to_socket={serversocket.fileno():serversocket,}

whileTrue:

print"等待活动连接......"

#轮询注册的事件集合

events=epoll.poll(timeout)

ifnot events:

print"epoll超时无活动连接,重新轮询......"

continue

print"有" , len(events),"个新事件,开始处理......"

forfd, event inevents:

socket=fd_to_socket[fd]

#可读事件

ifevent & select.EPOLLIN:

#如果活动socket为服务器所监听,有新连接

ifsocket ==serversocket:

connection, address =serversocket.accept()

print"新连接:" , address

connection.setblocking(0)

#注册新连接fd到待读事件集合

epoll.register(connection.fileno(), select.EPOLLIN)

fd_to_socket[connection.fileno()]=connection

message_queues[connection] =Queue.Queue()

#否则为客户端发送的数据

else:

data=socket.recv(1024)

ifdata:

print"收到数据:" , data , "客户端:", socket.getpeername()

message_queues[socket].put(data)

#修改读取到消息的连接到等待写事件集合

epoll.modify(fd, select.EPOLLOUT)

#可写事件

elifevent & select.EPOLLOUT:

try:

msg=message_queues[socket].get_nowait()

exceptQueue.Empty:

printsocket.getpeername() , " queue empty"

epoll.modify(fd, select.EPOLLIN)

else:

print"发送数据:" , data , "客户端:", socket.getpeername()

socket.send(msg)

#关闭事件

elifevent & select.EPOLLHUP:

epoll.unregister(fd)

fd_to_socket[fd].close()

delfd_to_socket[fd]

epoll.unregister(serversocket.fileno())

epoll.close()

serversocket.close()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值