Skip to content

Instantly share code, notes, and snippets.

@Hanaasagi
Created March 20, 2017 07:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hanaasagi/4b8384196e12eb7525a07369c7f1d971 to your computer and use it in GitHub Desktop.
Save Hanaasagi/4b8384196e12eb7525a07369c7f1d971 to your computer and use it in GitHub Desktop.
epoll server
import socket
import select
import argparse
'''
epoll 水平触发模式demo
'''
SERVER_HOST = '127.0.0.1'
EOL1 = b'\n\n'
EOL2 = b'\n\r\n'
SERVER_RESPONSE = b'''HTTP/1.1 200 OK\r\nContent-Tyep: text/plain\r\nContent-Length: 25\r\n\r\nHello from Epoll Server'''
class EpollServer(object):
def __init__(self, host=SERVER_HOST, port=0):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((host, port))
self.sock.listen(5)
self.sock.setblocking(0)
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
print 'Start Epoll server'
self.epoll = select.epoll()
# sock.fileno()返回监听的文件描述符
# 在服务端socket上面注册对读event的关注
self.epoll.register(self.sock.fileno(), select.EPOLLIN)
def run(self):
try:
# 字典存储映射文件描述符到其相应的网络连接对象
connections = {}
requests = {}
responses = {}
while True:
# 查询epoll对象,看是否有任何关注的event被触发。参数“1”表示,我们会等待1秒来看是否有event发生
events = self.epoll.poll(1)
# event作为一个序列(fileno,event code)的元组返回。
for fileno, event in events:
if fileno == self.sock.fileno():
connection, address = self.sock.accept()
connection.setblocking(0)
self.epoll.register(connection.fileno(), select.EPOLLIN)
connections[connection.fileno()] = connection
requests[connection.fileno()] = b''
responses[connection.fileno()] = SERVER_RESPONSE
# 读事件
elif event & select.EPOLLIN:
# 将请求数据保存在 requests[fileno]中
requests[fileno] += connections[fileno].recv(1024)
# 判断http请求是否接收完成
if EOL1 in requests[fileno] or EOL2 in requests[fileno]:
# 一旦完成请求已收到,就注销对读event的关注,注册对写(EPOLLOUT)event的关注。写event发生的时候,会回复数据给客户端
self.epoll.modify(fileno, select.EPOLLOUT)
# 打印请求头 requests[fileno].decode()[:-2]
print( '-'*40 +'\n'+requests[fileno].decode()[:-2])
# 写事件
elif event & select.EPOLLOUT:
byteswritten = connections[fileno].send(responses[fileno])
responses[fileno] = responses[fileno][byteswritten:]
if len(responses[fileno]) == 0:
# 不关注任何事件
self.epoll.modify(fileno, 0)
# 关闭连接
connections[fileno].shutdown(socket.SHUT_RDWR)
# HUP(挂起)event表明客户端socket已经断开(即关闭),所以服务端也需要关闭。没有必要注册对HUP event的关注。在socket上面,它们总是会被epoll对象注册。
elif event & select.EPOLLHUP:
self.epoll.unregister(fileno)
connections[fileno].close()
del connections[fileno]
except KeyboardInterrupt:
print 'server stopping...'
except socket.error, e:
print e
finally:
self.epoll.unregister(self.sock.fileno())
self.epoll.close()
self.sock.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Scoket Server Example with Epoll')
parser.add_argument('--port', action='store', dest='port', type=int, required=True)
given_args = parser.parse_args()
port = given_args.port
server = EpollServer(host=SERVER_HOST, port=port)
server.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment