用Python做一个websocket服务端

时间:2024-11-19 11:39:19

我对websocket服务端的功能定义是:

1.能将client端的软硬件信息关联(如client_name和对应ip:port),且不支持重复关联;

2.可以判断接收自client端的消息属于哪种任务,并对应执行(如关联、发消息);

3.根据接收自client端的消息判断是点对点发送,还是广播发送,并执行。

参考其他大神们写的代码,我用python实现了上述功能需求:

import asyncio
import websockets
import json
import threading

# 存储所有的客户端
Clients = []

# 服务端
class WS_Server():
    def __init__(self):
        self.ip = "127.0.0.1"
        self.port = 9090

    # 发送消息
    async def sendMsg(self, websocket, msg):
        if websocket != None:
           await websocket.send(msg)
        else:
            self.broadcast(msg)
        await asyncio.sleep(0.2)


    # 群发消息
    async def broadcast(self, msg):
        for user in Clients:
           await user['socket'].send(msg)


    # 连接一个客户端,起一个循环监听
    async def echo(self, websocket):
        # 握手
        client_ip, client_port = websocket.remote_address
        print(f"连接到:{client_ip}:{client_port}")
        await websocket.send(json.dumps({"stat": "success"}))
        # 循环监听
        while True:
            try:
                recv_text = await websocket.recv()
                message = "收到消息: {}".format(recv_text)
                await websocket.send(message)
                data = json.loads(recv_text)
                receiver = data['to']
                content = data['content']
                sender = data['from']
                stat = data['stat']
                if stat == "link":
                    checked = False
                    if len(Clients) > 0 :
                        for usr in Clients:
                            if usr['name'] == sender:
                                checked = True
                                break
                        if checked:
                            print(f"{client_ip}:{client_port}不能被重复关联")
                        else:
                            Clients.append({"socket": websocket, "name": sender})
                            print(f"{sender} 已关联 {client_ip}:{client_port}")
                    else:
                        Clients.append({"socket": websocket, "name": sender})
                        print(f"{sender} 已关联 {client_ip}:{client_port}")
                else:
                    msg = json.dumps({"stat": stat, "to": receiver, "content": content, "from": sender})
                    if receiver == "":
                        await self.broadcast(msg)
                        print('消息已群发')
                    else:
                        checked1 = False
                        for usr in Clients:
                            if usr['name'] == receiver:
                                socket = usr['socket']
                                await self.sendMsg(socket, msg)
                                checked1 = True
                                break
                        if checked1:
                            print(f"已给{receiver}发送消息")
                        else:
                            print(f"发送失败,未找到{receiver}")

            except websockets.ConnectionClosed:
                print(f"从{client_ip}:{client_port}断开连接")
                break
            except websockets.InvalidState:
                print("无效状态")
                break
            except Exception as e:
                print("ws连接报错", e)
                break

    # 启动服务器
    async def runServer(self):
        async with websockets.serve(self.echo, self.ip, self.port):
            await asyncio.Future()  # run forever

	# 多协程模式,防止阻塞主线程无法做其他事情
    def WebSocketServer(self):
        asyncio.run(self.runServer())

    # 多线程启动
    def startServer(self):
        # 多线程启动,否则会堵塞
        thread = threading.Thread(target=self.WebSocketServer)
        thread.start()
        # thread.join()


if __name__=='__main__':
    s = WS_Server()
    s.startServer()
    print("ws服务已启动")

启动WS服务后,客户端需要按照如下数据格式发消息:

{"stat":"","to": "", "content": "", "from":""}

其中,stat包括link和send两种状态,to是消息接者者(receiver),from是消息发送者(sender)。若to为空,则表示该消息是广播消息;若to不为空,但对象不存在,则该消息不会被执行发送。

最后,附上我参考的两篇****文章:

Python中websockets服务端从客户端接收消息并发送给多线程_python websocket 多线程-****博客

python的websocket方法教程_python websocket-****博客