Created
October 10, 2018 06:30
-
-
Save fpagyu/4cf5c5df9c3af78e727d4b7e49bac573 to your computer and use it in GitHub Desktop.
python 中select,poll, epoll 使用例子
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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