高并发说明
在这个示例代码中,创建了一个长度为
NUM_SHARDS
的列表shards
,每个元素都是一个哈希表。哈希表中存储了相应分片的客户端连接。当有新的客户端连接时,通过取模运算将其分配给对应的分片。客户端连接的分片索引
shard_index
是通过将客户端的唯一标识符(使用id()
函数生成)与分片数量NUM_SHARDS
取模得到的。然后,将客户端连接添加到对应的分片的哈希表中。当客户端断开连接时,从相应的分片中移除对应的客户端。使用分片来管理客户端连接可以有效地分散负载和提高性能。每个分片只负责一部分客户端连接,可以更好地扩展到大量连接的情况下。请注意,在分片技术中,需要确保客户端在断开连接时能够正确地被添加到和移除出相应的分片。
业务逻辑
1 在async def server 函数中通过哈希决定客户端分到哪个分片中并且create_task 传入receive函数名
2 在receive函数中循环获取消息并且将消息传递给handle_message函数进行处理,在finally中当客户端链接关闭时候从分片中删除客户端
3 在handle_message中根据不同逻辑回复不同消息,逻辑还可以是判断敏感词等,随后调用send_message函数返回消息
4 在send_message函数中将需要返回的消息直接发送给客户端
import websockets
import asyncio
NUM_SHARDS = 10
shards = [{} for _ in range(NUM_SHARDS)]
async def handle_message(websocket, message):
if message == "hello":
await send_message(websocket, "你好,欢迎!")
else:
await send_message(websocket, "收到你的消息啦!")
async def receive(websocket, shard_index):
try:
async for message in websocket:
print("收到消息:", message)
await handle_message(websocket, message)
except websockets.exceptions.ConnectionClosedOK:
print("连接已关闭")
finally:
client_id = id(websocket)
if client_id in shards[shard_index]:
del shards[shard_index][client_id] # 从分片中移除客户端
print(str(client_id) + "连接已关闭")
await websocket.close() # 关闭 WebSocket 连接
async def send_message(websocket,message):
try:
# while True:
await websocket.send(message)
# await asyncio.sleep(2)
except websockets.exceptions.ConnectionClosedOK:
print("连接已关闭")
async def server(websocket, path):
client_id = id(websocket)
shard_index = client_id % NUM_SHARDS # 使用哈希算法决定客户端应该存储在哪个分片中
shards[shard_index][client_id] = websocket # 将客户端添加到对应的分片中
receive_task = asyncio.create_task(receive(websocket, shard_index))
await receive_task
# connected_clients.add(websocket) # 将客户端添加到连接列表
# receive_task = asyncio.create_task(receive(websocket, path))
# await receive_task
# send_task = asyncio.create_task(send(websocket))
# await asyncio.gather(receive_task, send_task)
# 启动 WebSocket 服务器
start_server = websockets.serve(server, 'localhost', 8765)
# 运行事件循环以保持服务器运行
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input id="box" type="text">
<button onclick="ps()">发送</button>
<script>
// 与服务器约定的连接 以及端口 本机的 hosts文件 localhost www.ps.com
const websocket = new WebSocket('ws://127.0.0.1:8765/')
//连接发生错误的回调方法
websocket.onerror = ()=> {
console.log("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function () {
console.log("WebSocket连接成功");
}
//接收到消息的回调方法 接收服务器的数据
websocket.onmessage = function (event) {
console.log(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
console.log("WebSocket连接关闭");
}
function ps(){
// jquery -> val JS -> value
var text = document.getElementById('box').value
// 客户端发信息发服务器
websocket.send(text)
}
</script>
</body>
</html>
可以在方框内发送不同消息得到不同的回复