写了python脚本测试,发现正常的selectors、socketserver方式的服务器,在WINDOS下最多同时连接512个客户端,linux服务器下据说最多同时连接1024个客户端。想连接更多客户端只能采用gevet协程模式。
原理是操作系统底层就支持这么多。
以select写的聊天服务器为例:
select服务器:
select_server.py代码:
# coding=utf-8
import select
import socket
import threading
from logic.c_msg import CMsg
from logic.c_send import CSend
class CSelect(threading.Thread):
def __init__(self, lock, users):
threading.Thread.__init__(self)
self.mLock = lock
self.mUsers = users
def run(self):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)
host = socket.gethostname()
print("host = {}".format(host))
server.bind(("0.0.0.0", 9090))
server.listen(5) #最多五人等待
inputs = [server]
outputs = []
uid = 0
while True:
rlist, wlist, elist = select.select(inputs, outputs, inputs)
#NOTE: 没有客户端连接时,一直锁定在此。一旦有客户端连接上了,就一直循环检测,不停打印下面的语句
# print("len(rlist)={}, len(wlist)={}, len(elist)={}".format(len(rlist), len(wlist), len(elist)))
# 遍历可读
for r in rlist:
if r is server:
conn, addr = r.accept()
conn.setblocking(False)
inputs.append(conn)
outputs.append(conn)
uid += 1
self.mUsers[conn] = CMsg(conn, addr, uid)
print("accept: {},{}".format(uid, conn))
else:
try:
data = r.recv(1024)
if (data):
self.mLock.acquire()
txt = data.decode("utf-8")
print("recv: txt={}, r={} ".format(txt, r))
user = self.mUsers[r]
content = "[用户({})]:{}".format(user.mUid, txt)
user.addContent(content)
self.mLock.release()
else: # 数据为空,则是客户端断开
print("断开 {}".format(r))
if r in outputs:
outputs.remove(r)
inputs.remove(r)
r.close()
self.mLock.acquire()
self.mUsers[r].reset()
del self.mUsers[r]
self.mLock.release()
except ConnectionResetError as e:
print("用户断开:r={}, e={}".format(r, e))
if r in outputs:
outputs.remove(r)
inputs.remove(r)
r.close()
self.mLock.acquire()
self.mUsers[r].reset()
del self.mUsers[r]
self.mLock.release()
finally:
pass
self.mLock.acquire()
# 遍历可写
for conn, msg in self.mUsers.items():
msg.mIsConnected = False
for w in wlist:
if w in self.mUsers:
self.mUsers[w].mIsConnected = True
for s in elist:
if (s in self.mUsers):
self.mUsers[s].reset()
del self.mUsers[s]
(s in inputs) and inputs.remove(s)
(s in outputs) and outputs.remove(s)
s.close()
self.mLock.release()
if __name__ == "__main__":
lock = threading.Lock()
users = {}
sel = CSelect(lock, users)
sel.start()
send = CSend(lock, users)
send.start()
while True:
line = input("输入:")
if line == 'q':
break
c_msg.py代码:
# coding=utf-8
from queue import Queue
class CMsg():
def __init__(self, so, addr, uid=0):
self.mSock = so
self.mAddr = addr
self.mContentQu = Queue()
self.mUid = uid
self.mIsConnected = True
def addContent(self, content):
self.mContentQu.put(content)
def reset(self):
self.mContentQu.queue.clear()
self.mUid = 0
self.mIsConnected = True
c_send.py代码:<