WebSocket

Prerequisite

背景:我有个微信机器人,源码主体采用的是 WebSocket 库,群友有个需求,就是需要机器人在重要的日期之前提醒,我的方案是让它在重要的日期前一天早上 8 点和晚上 10 点进行提醒。实现过程比较简单,采用多进程(两个就够了),一个负责接收群友的消息并传递对应信息,另一个负责日期提醒

简单来说,WebSocket 是一个持久化的协议(如下图所示),先基于 HTTP 协议建立连接,再进行信息传递,此时信息传递是双向的,即客户端 ⇄ 服务器

参考文章:看完让你彻底搞懂Websocket原理
参考视频:WebSocket打造在线聊天室【第一集】
参考视频:How to Create a WebSocket Server in Python - Fun with WebSockets
参考文章:websocket-client(websocket)和websockets区别

python 库

python 的 WebSocket 有两个库,分别是 websocket-client 和 websockets。websocket-client 是一个 websocket 服务的 client 端模块,websockets 是一个模块有 server 端和 client 端,一般来前者(websocket-client)是同步的,后者(websockets)是异步的,因此后者常与协程(asyncio)一起用

下载方法分别是 pip install websocket-clientpip install websockets

websocket-client

我的微信机器人使用的 websocket-client 大致如下:

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import websocket
import time
websocket._logging._logger.level = -99

ip = '127.0.0.1'
port = 5555
SERVER = f'ws://{ip}:{port}'

def output(msg):
    now = time.strftime("%Y-%m-%d %X")
    print(f'[{now}]:{msg}')

def on_open(ws):
    ws.send("Hello")

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    output(f'on_error:{error}')

def on_close(ws):
    output("closed")

if __name__ == '__main__':
    ws = websocket.WebSocketApp(SERVER, on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close)

此时只有一个进程,用于接收群友的消息并传递对应信息,于是我加了第二个进程后代码如下:

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import websocket
import time
from multiprocessing import Process
websocket._logging._logger.level = -99

ip = '127.0.0.1'
port = 5555
SERVER = f'ws://{ip}:{port}'

def output(msg):
    now = time.strftime("%Y-%m-%d %X")
    print(f'[{now}]:{msg}')

def on_open(ws):
    ws.send("Hello")

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    output(f'on_error:{error}')

def on_close(ws):
    output("closed")

def reminder():
    pass

if __name__ == '__main__':
    ws = websocket.WebSocketApp(SERVER, on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close)
    # ws.run_forever()
    p1 = Process(target=reminder)
    p2 = Process(target=ws.run_forever)
    p1.start()
    p2.start()

相比于之前的代码只是多出了 reminder 函数,且改成了多进程,这样就能同时实现两个功能(reminder 和 run_forever),且互不干扰 ~

websockets

参考代码:python-websockets(By ParametricCamp)

服务端代码

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import websockets
import asyncio

PORT = 7890
print("Server listening on Port " + str(PORT))

# 接收 clients,且不重复
connected = set()

async def echo(websocket, path):
    print("A client just connected")
    # 一个 client 加入
    connected.add(websocket)
    # 处理接收的消息
    try:
        async for message in websocket:
            print("Received message from client: " + message)
            # 向发送消息的 client 发送同样的消息
            for conn in connected:
                if conn == websocket:
                    await conn.send("Someone said: " + message)
    # 处理取消连接的 client
    except websockets.exceptions.ConnectionClosed as e:
        print("A client just disconnected")
    finally:
        connected.remove(websocket)

# 开始工作
start_server = websockets.serve(echo, "localhost", PORT)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

客户端代码

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import websockets
import asyncio

async def listen():
    url = "ws://127.0.0.1:7890"
    # 连接服务器
    async with websockets.connect(url) as ws:
        # 发送消息
        await ws.send("Hello Server!")
        # 等待接收服务端消息
        while True:
            msg = await ws.recv()
            print(msg)

# 开始连接
asyncio.get_event_loop().run_until_complete(listen())

示例图如下:

posted @ 2022-09-21 16:30  筱团  阅读(271)  评论(0编辑  收藏  举报