基于select的IO多路复用实现的回写服务
客户端用线程池模拟了多个客户端同时请求时场景
代码比较简单,直接上代码
- 服务端代码
# -*- coding:utf-8 -*-
"""
File Name: select_svr
Author: 82405
Data: 2022/6/2 13:27
-----------------------
Info:
基于select实现的回写服务
-----------------------
Change Activity:
2022/6/2: create
"""
import socket
import select
import queue
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 1234))
sock.listen(100)
sock.setblocking(False) # 非阻塞模式
r_list = [sock]
w_list = []
x_list = []
sock_que = {} # 登记新的socket对象的消息队列
while True:
r_fds, w_fds, x_fds = select.select(r_list, w_list, x_list)
for sk_fd in r_fds:
if sk_fd is sock: # 判断是否是新的读写套接字
conn, addr = sk_fd.accept() # 生成新的读写套接字对象和 客户端地址
conn.setblocking(False) # 非阻塞
print('accepted', conn, 'from', addr)
r_list.append(conn)
sock_que[conn] = queue.Queue() # 在 sock_que 注册新的套接字的消息队列
else:
data = sk_fd.recv(1024)
if data:
print(f'data:{data}')
sock_que[sk_fd].put(data) # socket 读取的消息 存放到 在对应套接字对象的消息队列
if sk_fd not in w_list:
w_list.append(sk_fd) # 注册该 socket对象到 socket写的列表
else:
print('关闭')
if sk_fd in w_list:
w_list.remove(sk_fd)
if sk_fd in w_fds:
w_fds.remove(sk_fd)
r_list.remove(sk_fd)
sk_fd.close()
for sk_w_fd in w_fds:
# 写套接字
try:
next_msg = sock_que[sk_w_fd].get_nowait()
print(f'回写消息: {next_msg}')
sk_w_fd.send(next_msg)
except queue.Empty:
print('消息为空')
w_list.remove(sk_w_fd)
for sk_x_fd in x_fds:
print('异常套接字')
r_list.remove(sk_x_fd)
if sk_x_fd in w_list:
w_list.remove(sk_x_fd)
sk_x_fd.close()
del sock_que[sk_x_fd]
- 客户端代码
# -*- coding:utf-8 -*-
"""
File Name: socket_client
Author: 82405
Data: 2022/6/2 14:21
-----------------------
Info:
-----------------------
Change Activity:
2022/6/2: create
"""
import socket
from concurrent.futures import ThreadPoolExecutor
messages = ['hello', 'hello', 'ok', '1+1=2']
svr_addr = ('localhost', 1234)
def echo_client(num):
"""
:param num:
:return:
"""
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.connect(svr_addr)
for msg in messages:
sk.send(f'{num}-send:{msg}'.encode('utf8'))
data = sk.recv(1000)
print(f'{num}-recv:{data}')
sk.close()
print(f'{num} 客户端退出')
if __name__ == '__main__':
pool = ThreadPoolExecutor(128)
for i in range(100):
pool.submit(echo_client, i)
print('线程执行完毕')
# echo_client(1)