Skip to content

Instantly share code, notes, and snippets.

@fpagyu
Created October 10, 2018 06:30
Show Gist options
  • Save fpagyu/4cf5c5df9c3af78e727d4b7e49bac573 to your computer and use it in GitHub Desktop.
Save fpagyu/4cf5c5df9c3af78e727d4b7e49bac573 to your computer and use it in GitHub Desktop.
python 中select,poll, epoll 使用例子
# coding: utf-8
import select
import socket
import queue
def select_demo():
server = socket.socket()
server.bind(('127.0.0.1', 9000))
server.listen(5)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.setblocking(False) # 设置为非阻塞
msg_dict = {} # 定义一个队列字典
inputs = [server]
outputs = []
while True:
readable, writeable, exceptional = select.select(inputs, outputs, inputs)
for r in readable:
if r is server:
# 如果这个socket是server, 说明有新的客户端连接
conn, addr = r.accept()
print(f'new connection: {addr}')
# 为了不阻塞整个程序, 不会立即在这里开始接收客户端发送的数据
inputs.append(conn)
# 初始化一个队列, 后面要存储返回该客户端的数据
msg_dict[conn] = queue.Queue()
else:
# 如果不是server, 就说明是之前建立的客户端来数据了
data = r.recv(1024)
print(f'receive data: {data.decode()}')
# 收到的数据先放到queue中, 一会返回给客户端
msg_dict[r].put(data)
outputs.append(r)
for w in writeable:
data_to_client = msg_dict[w].get()
print(f'send data: {data_to_client.decode()}')
w.send(data_to_client)
outputs.remove(w)
for e in exceptional:
if e in outputs:
outputs.remove(e)
inputs.remove(e)
del msg_dict[e]
def poll_demo():
response = b'hello world'
server = socket.socket()
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('127.0.0.1', 9008))
server.listen(5)
server.setblocking(0)
poll = select.poll()
poll.register(server.fileno(), select.POLLIN)
connections = {}
try:
while True:
for fd, event in poll.poll():
if event & select.POLLIN:
if fd == server.fileno():
conn, addr = server.accept()
poll.register(conn, select.POLLIN)
connections[conn.fileno()] = conn
else:
conn = connections[fd]
data = conn.recv(1024)
if data:
poll.modify(fd, select.POLLOUT)
elif event & select.POLLOUT:
conn = connections[fd]
conn.send(response)
poll.unregister(fd)
conn.close()
finally:
server.close()
def epoll_demo:
EOL1 = b'\r\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!'
server = socket.socket()
server.bind(('127.0.0.1', 9000))
server.listen(5)
server.setblocking(0)
epoll = select.epoll()
epoll.register(server.fileno(), select.EPOLLIN)
try:
connections = {}
requests = {}
responses = {}
while True:
events = epoll.poll(1)
for fd, event in events:
if fd == server.fileno():
conn, addr = server.accept()
conn.setblocking(0)
epoll.register(conn.fileno(), select.EPOLLIN)
connections[conn.fileno()] = conn
requests[conn.fileno()] = b''
responses[conn.fileno()] = response
elif event & select.EPOLLIN:
requests[fd] += connections[fd].recv(1024)
if EOL1 in requests[fd] or EOL2 in requests[fd]:
epoll.modify(fd, select.EPOLLOUT)
print('-'*40 + '\n' + requests[fd].decode()[:-2])
elif event & select.EPOLLOUT:
byteswritten = connections[fd].send(responses[fd])
responses[fd] = responses[fd][byteswritten:]
if len(responses[fd]) == 0:
epoll.modify(fd, 0)
connections[fd].shutdown(socket.SHUT_RDWR)
elif event & select.EPOLLHUP:
epoll.unregister(fd)
connections[fd].close()
del connections[fd]
finally:
epoll.unregister(server.fileno())
epoll.close()
server.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment