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

Python Socket并行收发问题:客户端无法正确匹配CPU与内存使用率数据

问题分析与解决方案

你的问题本质上是TCP字节流特性加上无请求的盲目推送导致的数据匹配混乱。咱们拆解一下原因:

  1. TCP是字节流协议:它没有内置的消息边界,服务器两个线程同时调用send()时,数据可能会被操作系统合并发送,客户端的recv()根本分不清哪段是CPU数据、哪段是内存数据。
  2. 服务器逻辑错误:你的服务器完全忽略了客户端发送的"cpu"/"ram"请求,只是在两个线程里自顾自地循环发送数据,相当于服务器在乱泼数据,客户端两个线程随机接,自然会串。

要实现你想要的「服务器只发原始数据,客户端负责匹配区分」的需求,核心是改成请求-响应模式:客户端明确请求某类数据,服务器只返回对应的数据,这样每个响应都能精准匹配请求。

修改后的服务器代码

import socket
import psutil

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 6767))
server.listen()
print("Waiting for client connection...")
client, address = server.accept()
print(f"Connected to {address}")

try:
    while True:
        # 接收客户端的请求指令,去掉多余空白字符
        request = client.recv(1024).decode("ascii").strip()
        if not request:
            break  # 客户端断开连接
        
        # 根据请求返回对应原始数据
        if request == "cpu":
            # cpu_percent(1)会阻塞1秒采样,确保数据准确
            cpu_usage = str(psutil.cpu_percent(1))
            client.send(cpu_usage.encode("ascii"))
        elif request == "ram":
            ram_usage = str(psutil.virtual_memory()[2])
            client.send(ram_usage.encode("ascii"))
        else:
            client.send("Invalid request".encode("ascii"))
except Exception as e:
    print(f"Connection error: {e}")
finally:
    client.close()
    server.close()

修改后的客户端代码

import socket
import threading
import time

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 6767))

def fetch_cpu():
    while True:
        # 发送CPU请求
        client.send("cpu".encode("ascii"))
        # 接收对应的CPU数据
        cpu_usage = client.recv(1024).decode("ascii")
        print(f"cpu usage is {cpu_usage}")
        time.sleep(1)

def fetch_ram():
    while True:
        # 发送内存请求
        client.send("ram".encode("ascii"))
        # 接收对应的内存数据
        ram_usage = client.recv(1024).decode("ascii")
        print(f"ram usage is {ram_usage}")
        time.sleep(1)

# 启动两个线程分别获取数据
threading.Thread(target=fetch_cpu).start()
threading.Thread(target=fetch_ram).start()

额外优化:解决潜在的粘包问题

虽然上面的代码在大多数情况下能正常工作,但如果客户端请求频率很高,TCP可能会把多个响应粘在一起发送。可以给每个数据加个消息边界(比如换行符),确保客户端能准确拆分数据:

服务器端修改发送逻辑

把client.send(...)改成:

client.send(f"{cpu_usage}\n".encode("ascii"))  # CPU数据加换行
# 内存数据同理
client.send(f"{ram_usage}\n".encode("ascii"))

客户端新增按行读取的函数

def recv_line(sock):
    buffer = b""
    while True:
        chunk = sock.recv(1)
        if not chunk or chunk == b"\n":
            break
        buffer += chunk
    return buffer.decode("ascii")

然后在fetch_cpu和fetch_ram里用这个函数替代recv(1024):

cpu_usage = recv_line(client)

这样无论数据是否粘包,都能准确读取到完整的单个指标数据。


内容的提问来源于stack exchange,提问作者Morteza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 13:24:05