https://stackoverflow.com/questions/15219858/how-to-store-a-complex-object-in-redis-using-redis-py obj = ExampleObject() pickled_object = pickle.dumps(obj) r.set('some_key', pickled_object) unpacked_object = pickle.loads(r.get('some_key')) obj == unpacked_object typing.Dict[key_type, value_type] from typing import List, Dict from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI() class ConnectionManager: def __init__(self): # 存放激活的链接 self.active_connections: List[Dict[str, WebSocket]] = [] async def connect(self, user: str, ws: WebSocket): await ws.accept() self.active_connections.append({"user": user, "ws": ws}) def disconnect(self,user: str, ws: WebSocket): # 关闭时 移除ws对象 self.active_connections.remove({"user": user, "ws": ws}) @staticmethod async def send_personal_message(message: dict, ws: WebSocket): # 发送个人消息 await ws.send_json(message) async def send_other_message(self, message: dict, user: str): # 发送个人消息 for connection in self.active_connections: if connection["user"] == user: await connection['ws'].send_json(message) async def broadcast(self, data: dict): # 广播消息 for connection in self.active_connections: await connection['ws'].send_json(data) manager = ConnectionManager() @app.websocket("/ws/{user}") async def websocket_endpoint(ws: WebSocket, user: str): await manager.connect(user, ws) await manager.broadcast({"user": user, "message": "进入聊天"}) while True: data = await ws.receive_json() print(data, type(data)) send_user = data.get("send_user") if send_user: await manager.send_personal_message(data, ws) await manager.send_other_message(data, send_user) else: await manager.broadcast({"user": user, "message": data['message']}) except WebSocketDisconnect: manager.disconnect(user, ws) await manager.broadcast({"user": user, "message": "离开"}) if __name__ == "__main__": import uvicorn # 官方推荐是用命令后启动 uvicorn main:app --host=127.0.0.1 --port=8010 --reload uvicorn.run(app='main:app', host="127.0.0.1", port=8010, reload=True, debug=True)

客户端代码

由于只是demo, 所以代码都是固定的,有三份固定写的身份信息, 到时候客户端会有登录

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>聊天1</title>
</head>
<h1>User1 Chat</h1>
<form action="" onsubmit="sendMessage(event)">
    <input type="text" id="messageText" autocomplete="off"/>
    <button>Send</button>
</form>
<form action="" onsubmit="sendOtherMessage(event)">
    <input type="text" id="messageOther" autocomplete="off"/>
    <button>Send Other</button>
</form>
<ul id='messages'>
<script>
    let ws = new WebSocket("ws://127.0.0.1:8010/ws/user1");
    ws.onmessage = function(event) {
        let messages = document.getElementById('messages')
        let message = document.createElement('li');
        console.log(event.data, typeof (event.data), 2222)
        let receiveJson = JSON.parse(event.data);
        console.log(receiveJson, typeof (receiveJson), 333);
        let content = document.createTextNode(`${receiveJson.user}-${receiveJson.message}`);
        message.appendChild(content);
        messages.appendChild(message)
    function sendMessage(event) {
        let input = document.getElementById("messageText");
        let message = {message: input.value, user: "user1"};
        let messageJson = JSON.stringify(message);
        ws.send(messageJson);
        input.value = '';
        event.preventDefault()
    function sendOtherMessage(event) {
        let input = document.getElementById("messageOther");
        let message = {message: input.value, user: "user1", send_user: "user2"};
        let messageJson = JSON.stringify(message);
        ws.send(messageJson);
        input.value = '';
        event.preventDefault()
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>聊天2</title>
</head>
<h1>User2 Chat</h1>
<form action="" onsubmit="sendMessage(event)">
    <input type="text" id="messageText" autocomplete="off"/>
    <button>Send</button>
</form>
<form action="" onsubmit="sendOtherMessage(event)">
    <input type="text" id="messageOther" autocomplete="off"/>
    <button>Send Other</button>
</form>
<ul id='messages'>
<script>
    let ws = new WebSocket("ws://127.0.0.1:8010/ws/user2");
    ws.onmessage = function(event) {
        let messages = document.getElementById('messages')
        let message = document.createElement('li');
        console.log(event.data, typeof (event.data), 2222)
        let receiveJson = JSON.parse(event.data);
        console.log(receiveJson, typeof (receiveJson), 333);
        let content = document.createTextNode(`${receiveJson.user}-${receiveJson.message}`);
        message.appendChild(content);
        messages.appendChild(message)
    function sendMessage(event) {
        let input = document.getElementById("messageText")
        let message = {message: input.value, user: "user2"}
        let messageJson = JSON.stringify(message);
        ws.send(messageJson);
        input.value = '';
        event.preventDefault()
    function sendOtherMessage(event) {
        let input = document.getElementById("messageOther");
        let message = {message: input.value, user: "user2", send_user: "user1"};
        let messageJson = JSON.stringify(message);
        ws.send(messageJson);
        input.value = '';
        event.preventDefault()
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>聊天3</title>
</head>
<h1>User3 Chat</h1>
<form action="" onsubmit="sendMessage(event)">
    <input type="text" id="messageText" autocomplete="off"/>
    <button>Send</button>
</form>
<ul id='messages'>
<script>
    let ws = new WebSocket("ws://127.0.0.1:8010/ws/user3");
    ws.onmessage = function(event) {
        let messages = document.getElementById('messages')
        let message = document.createElement('li');
        console.log(event.data, typeof (event.data), 2222)
        let receiveJson = JSON.parse(event.data);
        console.log(receiveJson, typeof (receiveJson), 333);
        let content = document.createTextNode(`${receiveJson.user}-${receiveJson.message}`);
        message.appendChild(content);
        messages.appendChild(message)
    function sendMessage(event) {
        let input = document.getElementById("messageText")
        let message = {message: input.value, user: "user3"}
        let messageJson = JSON.stringify(message);
        ws.send(messageJson);
        input.value = '';
        event.preventDefault()
</script>
</body>
</html>

一些扩展知识

  • 关于websocket的链接异常捕获
  • 以下代码catch是捕获不到异常的。

    try {
            let ws = new WebSocket("ws://127.0.0.1:8010/ws/user1");
            ws.onerror = function (error) {
                console.log(error, 111);
        }catch (e) {
            console.log(e, 222)
    

    关于解释:

    https://stackoverflow.com/questions/31002592/javascript-doesnt-catch-error-in-websocket-instantiation

  • websocket 和 socket.io对比
  • https://stackoverflow.com/questions/10112178/differences-between-socket-io-and-websockets

    websocket 的基本使用原理就是这样了, 全双工的传输协议真的很方便。