内容纲要

[python]
import socket
import select

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(1)
serversocket.setblocking(0)

# 创建epoll对象,并注册socket对象的 epoll可读事件
epoll = select.epoll()
epoll.register(serversocket.fileno(), select.EPOLLIN)

try:
connections = {}
requests = {}
responses = {}
while True:
# 主循环,epoll的系统调用,一旦有网络IO事件发生,poll调用返回。这是和select系统调用的关键区别
events = epoll.poll(1)
# 通过事件通知获得监听的文件描述符,进而处理
for fileno, event in events:
# 注册监听的socket对象可读,获取连接,并注册连接的可读事件
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:
# 连接对象可读,处理客户端发生的信息,并注册连接对象可写
requests[fileno] += connections[fileno].recv(1024)
if EOL1 in requests[fileno] or EOL2 in requests[fileno]:
epoll.modify(fileno, select.EPOLLOUT)
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:
epoll.modify(fileno, 0)
connections[fileno].shutdown(socket.SHUT_RDWR)
elif event & select.EPOLLHUP:
epoll.unregister(fileno)
connections[fileno].close()
del connections[fileno]
finally:
epoll.unregister(serversocket.fileno())
epoll.close()
serversocket.close()
[/python]

tornado 下的 epoll

[python]
import errno
import functools
import tornado.ioloop
import socket

def handle_connection(connection, address):
"""处理请求,返回数据给客户端"""
data = connection.recv(2014)
print data
connection.send(data)

def connection_ready(sock, fd, events):
"""事件回调函数,主要用于 socket 可读事件,用于获取 socket 的链接"""
while True:
try:
connection, address = sock.accept()
except socket.error as e:
if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
raise
return
connection.setblocking(0)
handle_connection(connection, address)

if __name__ == ‘__main__’:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind(("", 5000))
sock.listen(128)
# 使用 tornado 封装好的 epoll 接口,即 IOLoop 对象
io_loop = tornado.ioloop.IOLoop.current()
callback = functools.partial(connection_ready, sock)
# io_loop 对象注册网络 io 文件描述符和回调函数与 io 事件的绑定
io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
io_loop.start()
[/python]

发表评论

电子邮件地址不会被公开。 必填项已用*标注