解决:recv() failed (104: Connection reset by peer) while proxying upgraded connection,问题是连接websocket失败

文章描述了一个Python脚本,通过WebSocket服务器代理解决recv()失败的问题,当连接升级时,实现客户端重连机制,包括连接主备WebSocket服务器、获取客户端IP地址和地区信息,并记录日志。
摘要由CSDN通过智能技术生成

解决recv() failed (104: Connection reset by peer) while proxying upgraded connection,问题是连接websocket失败


这段Python脚本是一个WebSocket服务器代理,

解决 while proxying upgraded connection
1、引入所需的模块:
    requests:用于发送HTTP请求。
	websockets:用于处理WebSocket连接。
	logging:用于记录日志信息。
	json, asyncio, socket:Python标准库中的模块。
	datetime:用于处理日期和时间。
2、定义获取IP地址的函数get_country_from_ip(ip):通过向百度接口发送请求来获取客户端IP地址对应的地区信息。
3、定义两个异步函数forward_messages和proxy_client:分别用于消息转发和客户端重连机制。
4、定义handle_connection(client, path)函数:用于处理客户端和服务器的连接。在函数内部实现了主要的逻辑,包括IP地址获取、连接主要和备用WebSocket服务器、客户端重连等。
5、配置日志记录器logger:设置日志级别为INFO,指定文件名格式和路径,并创建TimedRotatingFileHandler对象进行日志记录。
6、启动WebSocket服务器并监听本地地址和端口8079:调用websockets.serve()函数启动WebSocket服务,并在事件循环中运行服务器。

我这里是配置了一个是将nginx转成python来做一个中转代理,

服务端重连机制

1、单客服端连接中转服务的时候,中转服务端就直接连接websocket服务端

async def handle_connection(client, path):
    client_ip = client.remote_address[0]
    country = get_country_from_ip(client_ip)
    # 主WebSocket服务器
    main_server = 'ws://localhost:8013/websocket'
    # 备用WebSocket服务器
    backup_server = 'ws://localhost:8014/websocket'
    try:
        client_ip = socket.gethostbyname(client_ip)
        logger.info(f'----------接收到来自{country}的IP地址 {client_ip} 的连接-------时间:{datetime.now()}---')
    except socket.gaierror:
        logger.warning(f'无法解析客户端IP地址: {client_ip}')

    while True:
        try:
            server = await asyncio.wait_for(websockets.connect(main_server), timeout=1)
            logger.info(f'-------已连接到主WebSocket服务器------地区:{country}--IP地址{client_ip}----')
            break
        except (websockets.exceptions.WebSocketException, ConnectionRefusedError, asyncio.TimeoutError):
            logger.warning(f'无法连接到主WebSocket服务器,尝试备用WebSocket服务器...地区:{country}--IP地址{client_ip}----')
            try:
                server = await asyncio.wait_for(websockets.connect(backup_server), timeout=1)
                logger.info(f'-----已连接到备用WebSocket服务器-----地区:{country}--IP地址{client_ip}----')

                break
            except (websockets.exceptions.WebSocketException, ConnectionRefusedError, asyncio.TimeoutError):
                logger.warning(f'无法连接到备用WebSocket服务器,请检查网络连接---地区:{country}--IP地址{client_ip}----')
                await asyncio.sleep(0.001)  # 等待1毫秒后重连
    await proxy_client(client, server, client_ip)
    await server.close()

客户端机制

async def proxy_client(client, server, client_ip):
    country = get_country_from_ip(client_ip)
    try:
        await asyncio.gather(
            forward_messages(client, server, client_ip),
            forward_messages(server, client, client_ip)
        )
    except websockets.exceptions.ConnectionClosedError:
        logger.info(f'---客户端正常连接关闭--{client_ip}---,停止接收和转发消息---IP地址:{client_ip}---{country}---时间:{datetime.now()}---')
    except Exception as e:

将接收到的数据转发给后端,返回给客户端

async def forward_messages(source, destination, client_ip):
    country = get_country_from_ip(client_ip)
    async for message in source:
        data = json.loads(message)
        userId = data['userId']
        if data['cmd'] == 5013 and data['userId'] == int(userId):
            logger.info(
                f'-------接收到后端发送给-IOS客服端心跳---用户ID:{userId}--IP地址:{client_ip}--地区信息:{country}--时间:{datetime.now()}---------')
        elif data['cmd'] == '5013' and data['userId'] == str(userId):
            logger.info(
                f'-------接收到后端发送给-安卓客服端心跳---用户ID:{userId}--IP地址:{client_ip}--地区信息:{country}--时间:{datetime.now()}---------')
        elif data['cmd'] == 1001 and data['userId'] == int(userId):
            logger.info(f'-------接收到后端发送给-IOS客服端心跳---用户ID:{userId}--IP地址:{client_ip}--时间:{datetime.now()}---------')
        else:
            pass

        await destination.send(message)  # 将消息转发给目标方
current_time = datetime.now().strftime("%Y-%m-%d_%H")
# 创建logger对象
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# 打印日志路径
log_out = f'log/game-websocket'

# 创建TimedRotatingFileHandler对象,设置文件名格式为每个小时一个
handler = TimedRotatingFileHandler(log_out, encoding='UTF-8', when='H', interval=1, backupCount=1)
handler.suffix = "-%Y-%m-%d_%H.log"  # 设置文件后缀格式
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# 关闭处理程序和logger
for h in logger.handlers:
    h.close()
    logger.removeHandler(h)
# 将handler添加到logger对象中
logger.addHandler(handler)

start_server = websockets.serve(handle_connection, '0.0.0.0', 8079)  # 监听本地地址和端口
logger.info(f'中转WebSocket服务器代理已启动......')
# 运行事件循环
asyncio.get_event_loop().run_until_complete(start_server)

在这里插入图片描述

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zero16800

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值