#!/usr/bin/env python3 # -*- coding: utf-8 -*- import base64 import json import socket import time class ZhidaClient: def __init__(self, host='192.168.1.47', port=5792, timeout=10.0): self.host = host self.port = port self.timeout = timeout self.sock = None def connect(self): """建立 TCP 连接,并设置超时用于后续 recv/send。""" self.sock = socket.create_connection((self.host, self.port), timeout=self.timeout) # 确保后续 recv/send 都会在 timeout 秒后抛 socket.timeout self.sock.settimeout(self.timeout) def close(self): """关闭连接。""" if self.sock: self.sock.close() self.sock = None def _send_command(self, cmd: dict) -> dict: """ 发送一条命令,接收 raw bytes,直到能成功 json.loads。 """ if not self.sock: raise ConnectionError("Not connected") # 1) 发送 JSON 命令 payload = json.dumps(cmd, ensure_ascii=False).encode('utf-8') # 如果服务端需要换行分隔,也可以加上: payload += b'\n' self.sock.sendall(payload) # 2) 循环 recv,直到能成功解析完整 JSON buffer = bytearray() start = time.time() while True: try: chunk = self.sock.recv(4096) if not chunk: # 对端关闭 break buffer.extend(chunk) # 尝试解码、解析 text = buffer.decode('utf-8', errors='strict') try: return json.loads(text) except json.JSONDecodeError: # 继续 recv pass except socket.timeout: raise TimeoutError("recv() timed out after {:.1f}s".format(self.timeout)) # 可选:防止死循环,整个循环时长超过 2×timeout 就报错 if time.time() - start > self.timeout * 2: raise TimeoutError("No complete JSON received after {:.1f}s".format(time.time() - start)) raise ConnectionError("Connection closed before JSON could be parsed") # @property # def xxx() -> 类型: # return xxxxxx # def send_command(self, ): # self.xxx = dict[xxx] # 示例响应回复: # { # "result": "RUN", # "message": "AcqTime:3.321049min Vial:1" # } @property def status(self) -> dict: return self._send_command({"command": "getstatus"})["result"] # def get_status(self) -> dict: # print(self._send_command({"command": "getstatus"})) # return self._send_command({"command": "getstatus"}) def get_methods(self) -> dict: return self._send_command({"command": "getmethods"}) def start(self, text) -> dict: b64 = base64.b64encode(text.encode('utf-8')).decode('ascii') return self._send_command({"command": "start", "message": b64}) def abort(self) -> dict: return self._send_command({"command": "abort"}) if __name__ == "__main__": """ a,b,c 1,2,4 2,4,5 """ client = ZhidaClient() # 连接 client.connect() # 获取状态 print(client.status) # 命令格式:python zhida.py [options]