You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python AsyncIO服务器与双客户端通信问题求助

问题分析与解决方案

你的核心问题在于服务端将完成通知发送给了上传文件的client.py,而非监听通知的receiver.py,同时服务端没有维护接收者客户端的连接列表,无法主动向receiver推送消息。以下是具体问题拆解和修复方案:

关键问题点

  1. 服务端逻辑错误:handle_client中的writer属于client.py的连接,发送的响应只会回到client.py,而非receiver.py。
  2. client.py连接关闭过早:写入文件内容后直接关闭连接,未等待服务端响应或确保数据完全发送。
  3. receiver.py未标识身份:服务端无法区分上传客户端和接收客户端,不知道该把通知发给谁。

修复后的代码实现

1. 修改server.py:维护接收者连接并推送通知

import asyncio
from asyncio import StreamWriter

# 存储所有接收者的writer对象
receivers: set[StreamWriter] = set()

async def handle_client(reader, writer):
    try:
        data = await reader.read(1024)
        if not data:
            return
        
        # 判断是否为接收者客户端
        client_type = data.decode().strip()
        if client_type == "RECEIVER":
            receivers.add(writer)
            print("New receiver connected")
            # 保持连接,等待通知
            await reader.read()  # 阻塞直到连接关闭
            receivers.remove(writer)
            return
        
        # 处理文件上传客户端
        filename = client_type
        print(f"Receiving file: {filename}")
        with open(filename, 'wb') as file:
            while True:
                data = await reader.read(1024)
                if not data:
                    break
                file.write(data)
        print(f"Received file: {filename}")
        
        # 向所有接收者发送完成通知
        response = "Server has written data from client.py"
        for receiver_writer in receivers:
            try:
                receiver_writer.write(response.encode())
                await receiver_writer.drain()
            except Exception:
                # 移除失效的连接
                receivers.discard(receiver_writer)
        
        # 向上传客户端发送确认
        writer.write("File uploaded successfully".encode())
        await writer.drain()
        
    except asyncio.CancelledError:
        pass
    finally:
        writer.close()
        await writer.wait_closed()

async def main():
    server = await asyncio.start_server(
        handle_client, '127.0.0.1', 8888)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()

if __name__ == '__main__':
    asyncio.run(main())

2. 修改client.py:正确处理连接关闭

import asyncio

async def send_file(filename, server_host, server_port):
    reader, writer = await asyncio.open_connection(server_host, server_port)
    # 发送文件名
    writer.write(filename.encode())
    await writer.drain()
    
    with open(filename, 'rb') as file:
        while True:
            data = file.read(1024)
            if not data:
                break
            writer.write(data)
            await writer.drain()  # 确保数据发送完成
    
    # 等待服务端确认
    response = await reader.read(1024)
    print(f"Server response: {response.decode()}")
    
    writer.close()
    await writer.wait_closed()

if __name__ == '__main__':
    server_host = '127.0.0.1'
    server_port = 8888
    filename = 'temp.txt'
    asyncio.run(send_file(filename, server_host, server_port))

3. 修改receiver.py:标识身份并持续监听

import asyncio

async def receive_data():
    reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
    
    # 发送身份标识,告诉服务端自己是接收者
    writer.write("RECEIVER".encode())
    await writer.drain()
    
    print("Waiting for server notifications...")
    while True:
        response = await reader.read(1024)
        if not response:
            break
        message = response.decode()
        print(f"Received: {message}")
    
    print("Connection closed by server")
    writer.close()
    await writer.wait_closed()
    
async def main():
    await receive_data()

if __name__ == '__main__':
    asyncio.run(main())

使用步骤

  1. 先启动server.py
  2. 启动receiver.py(可启动多个)
  3. 运行client.py上传文件,此时所有运行的receiver都会收到完成通知

内容的提问来源于stack exchange,提问作者ysingh-1636

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:20:57