You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
4.8 KiB
Python

import pika
import uuid
import json
import threading
class RpcClient:
def __init__(self, clientName, rabbitHost='localhost', protocolManager=None):
"""
初始化RPC客户端
:param clientName: 客户端名称
:param rabbitHost: RabbitMQ服务器地址
:param protocolManager: 协议管理器实例用于处理读写操作
"""
self.clientName = clientName
self.protocolManager = protocolManager
self.variables = {}
# self.variables = {
# "temp": {"type": "AI", "min": 0, "max": 100, "value": 25.5},
# "status": {"type": DO", "min": None, "max": None, "value": "OK"},
# }
self.credentials = pika.PlainCredentials('dcs', '123456')
self.connection = pika.BlockingConnection(
pika.ConnectionParameters(host=rabbitHost, credentials=self.credentials)
)
self.channel = self.connection.channel()
self.queueName = f"rpc_queue_{self.clientName}"
self.channel.queue_declare(queue=self.queueName)
print(f"[{self.clientName}] 等待服务端指令...")
def onRequest(self, ch, method, props, body):
request = json.loads(body)
cmd = request.get("cmd")
response = {}
if cmd == "ping":
# 响应ping命令
response = {"client": self.clientName, "result": "pong"}
elif cmd == "read":
response = {"client": self.clientName, "variables": self.variables}
elif cmd == "write":
# 使用协议管理器处理写入操作
response = self.handleWriteRequest(request)
else:
# 未知命令的响应
response = {"client": self.clientName, "result": "fail", "reason": "unknown command"}
ch.basic_publish(
exchange='',
routing_key=props.reply_to,
properties=pika.BasicProperties(correlation_id=props.correlation_id),
body=json.dumps(response)
)
ch.basic_ack(delivery_tag=method.delivery_tag)
def handleWriteRequest(self, request):
"""
处理写入请求
:param request: 请求数据
:return: 响应数据
"""
varName = request.get("varName")
value = request.get("value")
# 如果有协议管理器,使用它来处理写入
if self.protocolManager:
try:
success = self.protocolManager.writeVariableValue(varName, value)
if success:
return {
"client": self.clientName,
"result": "success",
"varName": varName,
"value": value
}
else:
return {
"client": self.clientName,
"result": "fail",
"reason": "write failed"
}
except Exception as e:
return {
"client": self.clientName,
"result": "fail",
"reason": f"write error: {str(e)}"
}
def setVarContent(self, variableName, value, min, max, type):
if type in ['DI', 'DO']:
min = 0
max = 1
self.variables[variableName] = {}
self.variables[variableName]["value"] = value
self.variables[variableName]["min"] = min
self.variables[variableName]["max"] = max
self.variables[variableName]["type"] = type
def start(self):
"""启动客户端监听(阻塞方法)"""
self.channel.basic_qos(prefetch_count=1)
self.channel.basic_consume(queue=self.queueName, on_message_callback=self.onRequest)
self.channel.start_consuming()
def startNonBlocking(self):
"""非阻塞启动客户端(在后台线程中运行)"""
import threading
self.client_thread = threading.Thread(target=self.start, daemon=True)
self.client_thread.start()
print(f"[{self.clientName}] RPC客户端已在后台线程启动")
def isRunning(self):
"""检查客户端是否正在运行"""
return hasattr(self, 'client_thread') and self.client_thread.is_alive()
def close(self):
"""关闭RPC连接"""
try:
if self.channel and not self.channel.is_closed:
self.channel.close()
if self.connection and not self.connection.is_closed:
self.connection.close()
print(f"[{self.clientName}] 连接已关闭")
except Exception as e:
print(f"[{self.clientName}] 关闭连接时出错: {e}")
if __name__ == "__main__":
import sys
clientName = sys.argv[1] if len(sys.argv) > 1 else "Client1"
client = RpcClient(clientName)
client.start()