1
This commit is contained in:
295
README.md
Normal file
295
README.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# UPC Resent - 自动化控制设备指令转发系统
|
||||
|
||||
基于配置驱动的代码生成系统,支持 TCP 和 UDP 协议,监听端口接收外部指令,转换为 Modbus TCP/UDP 协议发送到控制设备(继电器/PLC等)。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
upc_resent/
|
||||
├── config/
|
||||
│ └── devices.json # 设备配置文件(唯一需要修改的文件)
|
||||
├── templates/ # 代码模板目录
|
||||
│ ├── listener_tcp.py.tpl # TCP监听服务模板
|
||||
│ ├── listener_udp.py.tpl # UDP监听服务模板
|
||||
│ ├── crond_tcp.py.tpl # TCP保活检查模板
|
||||
│ ├── crond_udp.py.tpl # UDP保活检查模板
|
||||
│ ├── sender_tcp.py.tpl # TCP发送模块模板
|
||||
│ └── sender_udp.py.tpl # UDP发送模块模板
|
||||
├── scripts/
|
||||
│ └── generate.py # 代码生成器
|
||||
├── bin/ # 生成的监听服务文件(自动生成)
|
||||
│ ├── sender_tcp.py # TCP发送模块
|
||||
│ ├── sender_udp.py # UDP发送模块
|
||||
│ └── {device_id}.py # 各设备监听服务
|
||||
├── crond/ # 生成的保活检查文件(自动生成)
|
||||
├── log/ # 日志目录
|
||||
├── start.sh # 启动脚本(自动生成)
|
||||
├── crontab.txt # 定时任务配置(自动生成)
|
||||
└── cutlog.sh # 日志清理脚本
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 配置设备
|
||||
|
||||
编辑 `config/devices.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"global": {
|
||||
"tms_server_ip": "192.168.8.9",
|
||||
"python_path": "/usr/bin/python3",
|
||||
"base_dir": "/opt/upc_resent"
|
||||
},
|
||||
"devices": [
|
||||
{
|
||||
"id": "dev1",
|
||||
"name": "设备1-TCP",
|
||||
"protocol": "tcp", // 协议类型: tcp 或 udp
|
||||
"upc_ip": "192.168.8.73",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10079,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "dev2",
|
||||
"name": "设备2-UDP",
|
||||
"protocol": "udp", // 使用UDP协议
|
||||
"upc_ip": "192.168.8.200",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10080,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 生成代码
|
||||
|
||||
```bash
|
||||
# 检查配置是否正确
|
||||
python3 scripts/generate.py --check
|
||||
|
||||
# 生成代码
|
||||
python3 scripts/generate.py
|
||||
```
|
||||
|
||||
### 3. 部署与启动
|
||||
|
||||
```bash
|
||||
# 启动所有服务
|
||||
./start.sh
|
||||
|
||||
# 配置定时任务(保活)
|
||||
crontab crontab.txt
|
||||
```
|
||||
|
||||
## 配置文件详解
|
||||
|
||||
### `config/devices.json`
|
||||
|
||||
#### 全局配置 (global)
|
||||
|
||||
| 参数 | 说明 | 示例 |
|
||||
|-----|------|-----|
|
||||
| `tms_server_ip` | 本机监听IP,接收外部指令 | `"192.168.8.9"` |
|
||||
| `python_path` | Python3 解释器路径 | `"/usr/bin/python3"` |
|
||||
| `base_dir` | 项目部署路径 | `"/opt/upc_resent"` |
|
||||
|
||||
#### 设备配置 (devices)
|
||||
|
||||
| 参数 | 说明 | 示例 |
|
||||
|-----|------|-----|
|
||||
| `id` | 设备唯一标识(用于文件名) | `"dev1"` |
|
||||
| `name` | 设备名称(用于日志显示) | `"设备1-TCP"` |
|
||||
| `protocol` | 协议类型:`tcp` 或 `udp` | `"tcp"` / `"udp"` |
|
||||
| `upc_ip` | 控制设备的IP地址 | `"192.168.8.73"` |
|
||||
| `upc_port` | 控制设备的端口(Modbus默认502) | `502` |
|
||||
| `listen_port` | 本机监听端口(每个设备需不同) | `10079` |
|
||||
| `enabled` | 是否启用该设备 | `true` / `false` |
|
||||
|
||||
#### 指令定义 (commands)
|
||||
|
||||
```json
|
||||
{
|
||||
"commands": {
|
||||
"open1": "000100000008010F006400010001",
|
||||
"close1": "000100000008010F006400010000",
|
||||
"openall4": "000100000008010F00640004000F",
|
||||
"closeall4": "000100000008010F006400040000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
格式:指令名 -> 16进制字符串
|
||||
|
||||
#### 指令映射 (mappings)
|
||||
|
||||
```json
|
||||
{
|
||||
"mappings": {
|
||||
"open": "openall4",
|
||||
"close": "closeall4",
|
||||
"guanggao-guan": "closeall4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## TCP vs UDP 差异
|
||||
|
||||
| 特性 | TCP | UDP |
|
||||
|-----|-----|-----|
|
||||
| 连接方式 | 面向连接 | 无连接 |
|
||||
| 可靠性 | 可靠传输 | 尽力传输 |
|
||||
| 响应 | 有确认响应 | 可选响应(可能超时) |
|
||||
| 适用场景 | 可靠性要求高 | 实时性要求高 |
|
||||
| 保活检查 | 端口连通性检查 | 进程状态检查 |
|
||||
|
||||
## 如何适配自己的设备
|
||||
|
||||
### 场景1:添加 TCP 设备
|
||||
|
||||
```json
|
||||
{
|
||||
"devices": [
|
||||
{
|
||||
"id": "dev_tcp",
|
||||
"name": "TCP设备",
|
||||
"protocol": "tcp",
|
||||
"upc_ip": "192.168.1.100",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10081,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 场景2:添加 UDP 设备
|
||||
|
||||
```json
|
||||
{
|
||||
"devices": [
|
||||
{
|
||||
"id": "dev_udp",
|
||||
"name": "UDP设备",
|
||||
"protocol": "udp",
|
||||
"upc_ip": "192.168.1.200",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10082,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 场景3:添加新的控制指令
|
||||
|
||||
```json
|
||||
{
|
||||
"commands": {
|
||||
"open9": "000100000008010F006C00010001",
|
||||
"close9": "000100000008010F006C00010000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 场景4:禁用某个设备
|
||||
|
||||
```json
|
||||
{
|
||||
"devices": [
|
||||
{
|
||||
"id": "dev2",
|
||||
"enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 测试指令发送
|
||||
|
||||
### TCP 设备测试
|
||||
|
||||
```bash
|
||||
# 向TCP设备发送开灯指令
|
||||
echo "open1" | nc 192.168.8.9 10079
|
||||
|
||||
# 向TCP设备发送全关指令
|
||||
echo "close" | nc 192.168.8.9 10079
|
||||
```
|
||||
|
||||
### UDP 设备测试
|
||||
|
||||
```bash
|
||||
# 向UDP设备发送开灯指令
|
||||
echo "open1" | nc -u 192.168.8.9 10080
|
||||
|
||||
# 向UDP设备发送全关指令
|
||||
echo "close" | nc -u 192.168.8.9 10080
|
||||
|
||||
# 使用 socat 测试 UDP
|
||||
echo "open1" | socat - UDP:192.168.8.9:10080
|
||||
```
|
||||
|
||||
## 支持的指令列表
|
||||
|
||||
| 外部指令 | 内部指令 | 功能 |
|
||||
|---------|---------|------|
|
||||
| `open` | `openall4` | 1-4路全开 |
|
||||
| `close` | `closeall4` | 1-4路全关 |
|
||||
| `open1`~`open8` | `open1`~`open8` | 第N路开 |
|
||||
| `close1`~`close8` | `close1`~`close8` | 第N路关 |
|
||||
| `guanggao-guan` | `closeall4` | 广告关闭(全关) |
|
||||
|
||||
## Modbus 指令格式
|
||||
|
||||
本项目支持 Modbus TCP/UDP 协议,指令为16进制字符串:
|
||||
|
||||
```
|
||||
示例:000100000008010F006400010001
|
||||
│ │ │ │ │ │ │ │ │ │ │
|
||||
│ │ │ │ │ │ │ │ │ │ └── 数据值 (01=开, 00=关)
|
||||
│ │ │ │ │ │ │ │ │ └──── 寄存器数量
|
||||
│ │ │ │ │ │ │ │ └─────── 起始地址 (64=100)
|
||||
│ │ │ │ │ │ │ └────────── 功能码 (0F=写多个线圈)
|
||||
│ │ │ │ │ │ └──────────── 单元标识
|
||||
│ │ │ │ └───────────────── 协议标识
|
||||
│ │ │ └─────────────────── 长度
|
||||
│ └─────────────────────── 事务标识
|
||||
└────────────────────────── 事务标识
|
||||
```
|
||||
|
||||
## 代码生成器用法
|
||||
|
||||
```bash
|
||||
# 检查配置是否正确
|
||||
python3 scripts/generate.py --check
|
||||
|
||||
# 生成代码
|
||||
python3 scripts/generate.py
|
||||
|
||||
# 查看帮助
|
||||
python3 scripts/generate.py --help
|
||||
```
|
||||
|
||||
## 日志文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|-----|------|
|
||||
| `log/{device_id}.log` | 设备监听服务的日志 |
|
||||
| `log/crond-{device_id}.log` | 保活检查的日志 |
|
||||
|
||||
日志自动轮转:每天清理7天前的日志。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **不要直接修改** `bin/` 和 `crond/` 下的文件,这些文件是自动生成的,重新生成时会覆盖。
|
||||
|
||||
2. **修改配置后必须重新运行** `python3 scripts/generate.py` 才能生效。
|
||||
|
||||
3. 确保每个设备的 `listen_port` 不冲突,无论 TCP 还是 UDP,端口都不能重复。
|
||||
|
||||
4. UDP 是无连接协议,设备可能不会返回响应,这是正常现象。
|
||||
|
||||
5. 部署到生产环境前,请将 `base_dir` 修改为实际的部署路径(如 `/opt/upc_resent`)。
|
||||
126
bin/192.168.8.125.py
Normal file
126
bin/192.168.8.125.py
Normal file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
# reload(sys) 和 sys.setdefaultencoding('utf-8') 在 Python 3 中不再需要
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
#======修改以下参数======
|
||||
TmsServerIp='192.168.8.9' #TMS服务器IP,用于绑定服务,等待外部指令
|
||||
TmsPor='10129' #TMS服务器端口,用于绑定服务,等待外部指令
|
||||
upc_dev_ip="192.168.8.125" #自动化控制设备IP
|
||||
upc_dev_port="502" #自动化控制设备端口
|
||||
# 注意:Senderfile 指向的 sender.py 脚本也需要是 Python 3 版本!
|
||||
Senderfile='/opt/upc_resent/bin/sender.py' #发送程序位置
|
||||
Logfile='/opt/upc_resent/log/192.168.8.125.log' #日志文件位置
|
||||
pythonpath="/usr/bin/python3" # Python 3 执行文件的位置,可在操作系统中使用which python3命令获取
|
||||
#========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志,只执行一次
|
||||
logging.basicConfig(filename=Logfile,filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT='%Y-%m-%d %X'
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.bind((TmsServerIp, int(TmsPor))) #启动TMS本地服务,等待外部设备发送指令
|
||||
sock.listen(500)
|
||||
except OSError as e: # 在 Python 3 中使用 OSError 替代 socket.error
|
||||
logstr="!!!!!ERROR!!!!!"+time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )+" 无法绑定端口 %s:%s - %s" % (TmsServerIp, TmsPor, e)
|
||||
logging.error(logstr)
|
||||
print(logstr) # Python 3 print 函数
|
||||
sys.exit(1) # 绑定失败则退出
|
||||
|
||||
logging.info("服务启动,监听 %s:%s" % (TmsServerIp, TmsPor))
|
||||
|
||||
while True:
|
||||
connection,address = sock.accept()
|
||||
try:
|
||||
connection.settimeout(5) #GDC系统长连接
|
||||
# 接收到的数据是 bytes,需要解码成 str 进行比较
|
||||
buf_bytes = connection.recv(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip() # 解码成 str 并移除空白符
|
||||
|
||||
operation = "nodata" # 默认值,如果没有匹配的命令
|
||||
|
||||
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
|
||||
logstr="==="+datetime_str+"收到客户端"+ address[0]+":"+str(address[1])+"发送的指令: '" +str(buf)+"'"
|
||||
logging.info(logstr)
|
||||
|
||||
# 根据接收到的外部命令,映射到单个内部操作指令
|
||||
if buf == 'open':
|
||||
operation = 'openall4'
|
||||
elif buf == 'close':
|
||||
operation = 'closeall4'
|
||||
elif buf == 'open1':
|
||||
operation = 'open1'
|
||||
elif buf == 'close1':
|
||||
operation = 'close1'
|
||||
elif buf == 'open2':
|
||||
operation = 'open2'
|
||||
elif buf == 'close2':
|
||||
operation = 'close2'
|
||||
elif buf == 'open3':
|
||||
operation = 'open3'
|
||||
elif buf == 'close3':
|
||||
operation = 'close3'
|
||||
elif buf == 'open4':
|
||||
operation = 'open4'
|
||||
elif buf == 'close4':
|
||||
operation = 'close4'
|
||||
elif buf == 'open5': # 新增 5-8 路的命令映射
|
||||
operation = 'open5'
|
||||
elif buf == 'close5':
|
||||
operation = 'close5'
|
||||
elif buf == 'open6':
|
||||
operation = 'open6'
|
||||
elif buf == 'close6':
|
||||
operation = 'close6'
|
||||
elif buf == 'open7':
|
||||
operation = 'open7'
|
||||
elif buf == 'close7':
|
||||
operation = 'close7'
|
||||
elif buf == 'open8':
|
||||
operation = 'open8'
|
||||
elif buf == 'close8':
|
||||
operation = 'close8'
|
||||
elif buf == 'guanggao-guan': # 外部命令 'guanggao-guan' 映射到 'closeall4' (全关)
|
||||
operation = 'closeall4'
|
||||
# else: operation 保持为 "nodata"
|
||||
|
||||
if operation == "nodata":
|
||||
logstr="==="+datetime_str+" 未知指令: '" +str(buf)+"'"
|
||||
logging.warning(logstr)
|
||||
print(logstr) # Python 3 print 函数
|
||||
# 给客户端一个反馈,需要编码成 bytes
|
||||
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
|
||||
else:
|
||||
logstr="==="+datetime_str+" 映射到内部指令: '" +str(operation)+"'"
|
||||
logging.info(logstr)
|
||||
# 直接执行一次外部脚本
|
||||
os_command=str(pythonpath)+" " +Senderfile+ " " + str(upc_dev_ip)+" "+str(upc_dev_port)+" "+str(operation)+" "+str(Logfile)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command) # 执行发送指令的脚本
|
||||
# 成功处理后给客户端反馈,需要编码成 bytes
|
||||
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
|
||||
except socket.timeout:
|
||||
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
|
||||
logstr="==="+datetime_str+" 客户端连接超时: "+ address[0]+":"+str(address[1])+"==="
|
||||
logging.warning(logstr)
|
||||
print('time out') # Python 3 print 函数
|
||||
except Exception as e: # 捕获其他可能的异常
|
||||
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
|
||||
logstr="==="+datetime_str+" 处理客户端 "+ address[0]+":"+str(address[1])+" 请求时发生错误: "+str(e)+"==="
|
||||
logging.error(logstr, exc_info=True) # 记录异常详情
|
||||
print("Error processing request:", e) # Python 3 print 函数
|
||||
# 给客户端一个错误反馈,需要编码成 bytes
|
||||
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
|
||||
finally:
|
||||
connection.close() # 确保每次连接都被关闭
|
||||
|
||||
126
bin/192.168.8.73.py
Normal file
126
bin/192.168.8.73.py
Normal file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
# reload(sys) 和 sys.setdefaultencoding('utf-8') 在 Python 3 中不再需要
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
#======修改以下参数======
|
||||
TmsServerIp='192.168.8.9' #TMS服务器IP,用于绑定服务,等待外部指令
|
||||
TmsPor='10079' #TMS服务器端口,用于绑定服务,等待外部指令
|
||||
upc_dev_ip="192.168.8.73" #自动化控制设备IP
|
||||
upc_dev_port="502" #自动化控制设备端口
|
||||
# 注意:Senderfile 指向的 sender.py 脚本也需要是 Python 3 版本!
|
||||
Senderfile='/opt/upc_resent/bin/sender.py' #发送程序位置
|
||||
Logfile='/opt/upc_resent/log/192.168.8.73.log' #日志文件位置
|
||||
pythonpath="/usr/bin/python3" # Python 3 执行文件的位置,可在操作系统中使用which python3命令获取
|
||||
#========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志,只执行一次
|
||||
logging.basicConfig(filename=Logfile,filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT='%Y-%m-%d %X'
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.bind((TmsServerIp, int(TmsPor))) #启动TMS本地服务,等待外部设备发送指令
|
||||
sock.listen(500)
|
||||
except OSError as e: # 在 Python 3 中使用 OSError 替代 socket.error
|
||||
logstr="!!!!!ERROR!!!!!"+time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )+" 无法绑定端口 %s:%s - %s" % (TmsServerIp, TmsPor, e)
|
||||
logging.error(logstr)
|
||||
print(logstr) # Python 3 print 函数
|
||||
sys.exit(1) # 绑定失败则退出
|
||||
|
||||
logging.info("服务启动,监听 %s:%s" % (TmsServerIp, TmsPor))
|
||||
|
||||
while True:
|
||||
connection,address = sock.accept()
|
||||
try:
|
||||
connection.settimeout(5) #GDC系统长连接
|
||||
# 接收到的数据是 bytes,需要解码成 str 进行比较
|
||||
buf_bytes = connection.recv(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip() # 解码成 str 并移除空白符
|
||||
|
||||
operation = "nodata" # 默认值,如果没有匹配的命令
|
||||
|
||||
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
|
||||
logstr="==="+datetime_str+"收到客户端"+ address[0]+":"+str(address[1])+"发送的指令: '" +str(buf)+"'"
|
||||
logging.info(logstr)
|
||||
|
||||
# 根据接收到的外部命令,映射到单个内部操作指令
|
||||
if buf == 'open':
|
||||
operation = 'openall4'
|
||||
elif buf == 'close':
|
||||
operation = 'closeall4'
|
||||
elif buf == 'open1':
|
||||
operation = 'open1'
|
||||
elif buf == 'close1':
|
||||
operation = 'close1'
|
||||
elif buf == 'open2':
|
||||
operation = 'open2'
|
||||
elif buf == 'close2':
|
||||
operation = 'close2'
|
||||
elif buf == 'open3':
|
||||
operation = 'open3'
|
||||
elif buf == 'close3':
|
||||
operation = 'close3'
|
||||
elif buf == 'open4':
|
||||
operation = 'open4'
|
||||
elif buf == 'close4':
|
||||
operation = 'close4'
|
||||
elif buf == 'open5': # 新增 5-8 路的命令映射
|
||||
operation = 'open5'
|
||||
elif buf == 'close5':
|
||||
operation = 'close5'
|
||||
elif buf == 'open6':
|
||||
operation = 'open6'
|
||||
elif buf == 'close6':
|
||||
operation = 'close6'
|
||||
elif buf == 'open7':
|
||||
operation = 'open7'
|
||||
elif buf == 'close7':
|
||||
operation = 'close7'
|
||||
elif buf == 'open8':
|
||||
operation = 'open8'
|
||||
elif buf == 'close8':
|
||||
operation = 'close8'
|
||||
elif buf == 'guanggao-guan': # 外部命令 'guanggao-guan' 映射到 'closeall4' (全关)
|
||||
operation = 'closeall4'
|
||||
# else: operation 保持为 "nodata"
|
||||
|
||||
if operation == "nodata":
|
||||
logstr="==="+datetime_str+" 未知指令: '" +str(buf)+"'"
|
||||
logging.warning(logstr)
|
||||
print(logstr) # Python 3 print 函数
|
||||
# 给客户端一个反馈,需要编码成 bytes
|
||||
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
|
||||
else:
|
||||
logstr="==="+datetime_str+" 映射到内部指令: '" +str(operation)+"'"
|
||||
logging.info(logstr)
|
||||
# 直接执行一次外部脚本
|
||||
os_command=str(pythonpath)+" " +Senderfile+ " " + str(upc_dev_ip)+" "+str(upc_dev_port)+" "+str(operation)+" "+str(Logfile)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command) # 执行发送指令的脚本
|
||||
# 成功处理后给客户端反馈,需要编码成 bytes
|
||||
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
|
||||
except socket.timeout:
|
||||
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
|
||||
logstr="==="+datetime_str+" 客户端连接超时: "+ address[0]+":"+str(address[1])+"==="
|
||||
logging.warning(logstr)
|
||||
print('time out') # Python 3 print 函数
|
||||
except Exception as e: # 捕获其他可能的异常
|
||||
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
|
||||
logstr="==="+datetime_str+" 处理客户端 "+ address[0]+":"+str(address[1])+" 请求时发生错误: "+str(e)+"==="
|
||||
logging.error(logstr, exc_info=True) # 记录异常详情
|
||||
print("Error processing request:", e) # Python 3 print 函数
|
||||
# 给客户端一个错误反馈,需要编码成 bytes
|
||||
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
|
||||
finally:
|
||||
connection.close() # 确保每次连接都被关闭
|
||||
|
||||
124
bin/dev1.py
Executable file
124
bin/dev1.py
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: 设备73-TCP (dev1)
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TMS_SERVER_IP = '192.168.8.9'
|
||||
TMS_PORT = 10079
|
||||
UPC_DEV_IP = '192.168.8.73'
|
||||
UPC_DEV_PORT = '502'
|
||||
SENDER_FILE = '/home/smart/pythonPJ/upc_resent/bin/sender_tcp.py'
|
||||
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/dev1.log'
|
||||
PYTHON_PATH = '/usr/bin/python3'
|
||||
DEVICE_ID = 'dev1'
|
||||
# =========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 命令映射表
|
||||
COMMAND_MAPPINGS = {
|
||||
"open": "openall4",
|
||||
"close": "closeall4",
|
||||
"guanggao-guan": "closeall4",
|
||||
"open1": "open1",
|
||||
"close1": "close1",
|
||||
"open2": "open2",
|
||||
"close2": "close2",
|
||||
"open3": "open3",
|
||||
"close3": "close3",
|
||||
"open4": "open4",
|
||||
"close4": "close4",
|
||||
"open5": "open5",
|
||||
"close5": "close5",
|
||||
"open6": "open6",
|
||||
"close6": "close6",
|
||||
"open7": "open7",
|
||||
"close7": "close7",
|
||||
"open8": "open8",
|
||||
"close8": "close8",
|
||||
}
|
||||
|
||||
|
||||
def process_command(buf):
|
||||
"""处理接收到的命令,返回对应的操作指令"""
|
||||
buf = buf.strip()
|
||||
if buf in COMMAND_MAPPINGS:
|
||||
return COMMAND_MAPPINGS[buf]
|
||||
return "nodata"
|
||||
|
||||
|
||||
def main():
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
|
||||
sock.listen(500)
|
||||
except OSError as e:
|
||||
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
|
||||
" 无法绑定端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
sys.exit(1)
|
||||
|
||||
logging.info("服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
|
||||
print(f"[{DEVICE_ID}] 服务启动,监听 {TMS_SERVER_IP}:{TMS_PORT}")
|
||||
|
||||
while True:
|
||||
connection, address = sock.accept()
|
||||
try:
|
||||
connection.settimeout(5)
|
||||
buf_bytes = connection.recv(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip()
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 收到客户端 " + address[0] + ":" + str(address[1]) + \
|
||||
" 发送的指令: '" + str(buf) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
operation = process_command(buf)
|
||||
|
||||
if operation == "nodata":
|
||||
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
|
||||
else:
|
||||
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
|
||||
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
|
||||
str(operation) + " " + str(LOG_FILE)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command)
|
||||
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
|
||||
except socket.timeout:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 客户端连接超时: " + address[0] + ":" + str(address[1]) + "==="
|
||||
logging.warning(logstr)
|
||||
print('time out')
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 处理客户端 " + address[0] + ":" + str(address[1]) + \
|
||||
" 请求时发生错误: " + str(e) + "==="
|
||||
logging.error(logstr, exc_info=True)
|
||||
print("Error processing request:", e)
|
||||
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
124
bin/dev2.py
Executable file
124
bin/dev2.py
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: 设备125-TCP (dev2)
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TMS_SERVER_IP = '192.168.8.9'
|
||||
TMS_PORT = 10129
|
||||
UPC_DEV_IP = '192.168.8.125'
|
||||
UPC_DEV_PORT = '502'
|
||||
SENDER_FILE = '/home/smart/pythonPJ/upc_resent/bin/sender_tcp.py'
|
||||
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/dev2.log'
|
||||
PYTHON_PATH = '/usr/bin/python3'
|
||||
DEVICE_ID = 'dev2'
|
||||
# =========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 命令映射表
|
||||
COMMAND_MAPPINGS = {
|
||||
"open": "openall4",
|
||||
"close": "closeall4",
|
||||
"guanggao-guan": "closeall4",
|
||||
"open1": "open1",
|
||||
"close1": "close1",
|
||||
"open2": "open2",
|
||||
"close2": "close2",
|
||||
"open3": "open3",
|
||||
"close3": "close3",
|
||||
"open4": "open4",
|
||||
"close4": "close4",
|
||||
"open5": "open5",
|
||||
"close5": "close5",
|
||||
"open6": "open6",
|
||||
"close6": "close6",
|
||||
"open7": "open7",
|
||||
"close7": "close7",
|
||||
"open8": "open8",
|
||||
"close8": "close8",
|
||||
}
|
||||
|
||||
|
||||
def process_command(buf):
|
||||
"""处理接收到的命令,返回对应的操作指令"""
|
||||
buf = buf.strip()
|
||||
if buf in COMMAND_MAPPINGS:
|
||||
return COMMAND_MAPPINGS[buf]
|
||||
return "nodata"
|
||||
|
||||
|
||||
def main():
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
|
||||
sock.listen(500)
|
||||
except OSError as e:
|
||||
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
|
||||
" 无法绑定端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
sys.exit(1)
|
||||
|
||||
logging.info("服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
|
||||
print(f"[{DEVICE_ID}] 服务启动,监听 {TMS_SERVER_IP}:{TMS_PORT}")
|
||||
|
||||
while True:
|
||||
connection, address = sock.accept()
|
||||
try:
|
||||
connection.settimeout(5)
|
||||
buf_bytes = connection.recv(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip()
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 收到客户端 " + address[0] + ":" + str(address[1]) + \
|
||||
" 发送的指令: '" + str(buf) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
operation = process_command(buf)
|
||||
|
||||
if operation == "nodata":
|
||||
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
|
||||
else:
|
||||
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
|
||||
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
|
||||
str(operation) + " " + str(LOG_FILE)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command)
|
||||
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
|
||||
except socket.timeout:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 客户端连接超时: " + address[0] + ":" + str(address[1]) + "==="
|
||||
logging.warning(logstr)
|
||||
print('time out')
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 处理客户端 " + address[0] + ":" + str(address[1]) + \
|
||||
" 请求时发生错误: " + str(e) + "==="
|
||||
logging.error(logstr, exc_info=True)
|
||||
print("Error processing request:", e)
|
||||
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
118
bin/dev3.py
Executable file
118
bin/dev3.py
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: 设备UDP示例 (dev3) - UDP Protocol
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TMS_SERVER_IP = '192.168.8.9'
|
||||
TMS_PORT = 10080
|
||||
UPC_DEV_IP = '192.168.8.200'
|
||||
UPC_DEV_PORT = 502
|
||||
SENDER_FILE = '/home/smart/pythonPJ/upc_resent/bin/sender_udp.py'
|
||||
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/dev3.log'
|
||||
PYTHON_PATH = '/usr/bin/python3'
|
||||
DEVICE_ID = 'dev3'
|
||||
# =========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 命令映射表
|
||||
COMMAND_MAPPINGS = {
|
||||
"open": "openall4",
|
||||
"close": "closeall4",
|
||||
"guanggao-guan": "closeall4",
|
||||
"open1": "open1",
|
||||
"close1": "close1",
|
||||
"open2": "open2",
|
||||
"close2": "close2",
|
||||
"open3": "open3",
|
||||
"close3": "close3",
|
||||
"open4": "open4",
|
||||
"close4": "close4",
|
||||
"open5": "open5",
|
||||
"close5": "close5",
|
||||
"open6": "open6",
|
||||
"close6": "close6",
|
||||
"open7": "open7",
|
||||
"close7": "close7",
|
||||
"open8": "open8",
|
||||
"close8": "close8",
|
||||
}
|
||||
|
||||
|
||||
def process_command(buf):
|
||||
"""处理接收到的命令,返回对应的操作指令"""
|
||||
buf = buf.strip()
|
||||
if buf in COMMAND_MAPPINGS:
|
||||
return COMMAND_MAPPINGS[buf]
|
||||
return "nodata"
|
||||
|
||||
|
||||
def main():
|
||||
# 创建 UDP socket
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
|
||||
except OSError as e:
|
||||
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
|
||||
" 无法绑定UDP端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
sys.exit(1)
|
||||
|
||||
logging.info("UDP服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
|
||||
print(f"[{DEVICE_ID}] UDP服务启动,监听 {TMS_SERVER_IP}:{TMS_PORT}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
# UDP 使用 recvfrom 接收数据,同时获取客户端地址
|
||||
buf_bytes, client_addr = sock.recvfrom(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip()
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 收到UDP客户端 " + client_addr[0] + ":" + str(client_addr[1]) + \
|
||||
" 发送的指令: '" + str(buf) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
operation = process_command(buf)
|
||||
|
||||
if operation == "nodata":
|
||||
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
# 发送UDP响应
|
||||
sock.sendto(('Unknown command: %s' % buf).encode('utf-8'), client_addr)
|
||||
else:
|
||||
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
# 执行发送指令的脚本
|
||||
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
|
||||
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
|
||||
str(operation) + " " + str(LOG_FILE)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command)
|
||||
|
||||
# 发送UDP响应
|
||||
sock.sendto(('Command %s processed as %s' % (buf, operation)).encode('utf-8'), client_addr)
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 处理UDP请求时发生错误: " + str(e) + "==="
|
||||
logging.error(logstr, exc_info=True)
|
||||
print("Error processing UDP request:", e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
140
bin/sender.py
Executable file
140
bin/sender.py
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
import logging
|
||||
import telnetlib
|
||||
|
||||
|
||||
def tcp_command_send(upc_addr, upc_command, data):
|
||||
"""负责发送数据和接收一次响应"""
|
||||
timeout = 2
|
||||
socket.setdefaulttimeout(timeout)
|
||||
try:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
logging.debug(f"尝试连接到 {upc_addr[0]}:{upc_addr[1]}...")
|
||||
client.connect(upc_addr)
|
||||
logging.debug(f"成功连接到 {upc_addr[0]}:{upc_addr[1]}。")
|
||||
|
||||
logging.info(f"正在发送命令 '{upc_command}' 到 {upc_addr}: {data!r} (原始字节)")
|
||||
client.send(data)
|
||||
logging.debug(f"数据发送完成。")
|
||||
|
||||
recv_buffer_size = 1024
|
||||
response_bytes = b''
|
||||
try:
|
||||
logging.debug(f"尝试从 {upc_addr} 接收响应数据...")
|
||||
response_bytes = client.recv(recv_buffer_size)
|
||||
if response_bytes:
|
||||
logging.info(f"从 {upc_addr} 收到原始响应字节: {response_bytes!r}")
|
||||
try:
|
||||
response_str = response_bytes.decode('utf-8', errors='ignore')
|
||||
logging.info(f"从 {upc_addr} 收到解码响应字符串: '{response_str}'")
|
||||
except Exception as decode_e:
|
||||
logging.warning(f"解码从 {upc_addr} 收到的响应时发生错误: {decode_e}")
|
||||
else:
|
||||
logging.info(f"从 {upc_addr} 未收到响应数据 (连接可能已关闭或设备未发送)。")
|
||||
except socket.timeout:
|
||||
logging.warning(f"从 {upc_addr} 接收响应超时。")
|
||||
except OSError as recv_e:
|
||||
logging.error(f"从 {upc_addr} 接收响应时发生网络错误: {recv_e}")
|
||||
|
||||
client.close()
|
||||
logging.debug(f"连接关闭。")
|
||||
return True
|
||||
except OSError as e:
|
||||
logging.error(f"命令 '{upc_command}' 发送至 {upc_addr} 失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# 指令定义表(从配置文件读取)
|
||||
COMMAND_DEFINITIONS = {
|
||||
"open1": "000100000008010F006400010001",
|
||||
"close1": "000100000008010F006400010000",
|
||||
"open2": "000100000008010F006500010001",
|
||||
"close2": "000100000008010F006500010000",
|
||||
"open3": "000100000008010F006600010001",
|
||||
"close3": "000100000008010F006600010000",
|
||||
"open4": "000100000008010F006700010001",
|
||||
"close4": "000100000008010F006700010000",
|
||||
"openall4": "000100000008010F00640004000F",
|
||||
"closeall4": "000100000008010F006400040000",
|
||||
"open5": "000100000008010F006800010001",
|
||||
"close5": "000100000008010F006800010000",
|
||||
"open6": "000100000008010F006900010001",
|
||||
"close6": "000100000008010F006900010000",
|
||||
"open7": "000100000008010F006A00010001",
|
||||
"close7": "000100000008010F006A00010000",
|
||||
"open8": "000100000008010F006B00010001",
|
||||
"close8": "000100000008010F006B00010000",
|
||||
"getstat": "fe010000000429C6",
|
||||
"getstat01": "fe010100000429C6",
|
||||
}
|
||||
|
||||
|
||||
def upc_send_command(upc_addr, upc_command, log_file):
|
||||
"""将命令发送给终端设备"""
|
||||
data = None
|
||||
|
||||
# 查找指令定义
|
||||
if upc_command in COMMAND_DEFINITIONS:
|
||||
hex_str = COMMAND_DEFINITIONS[upc_command]
|
||||
data = bytes.fromhex(hex_str)
|
||||
|
||||
if data is None:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} 未知命令: {upc_command},没有对应的数据可发送。"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
else:
|
||||
i = 1
|
||||
while i <= 3: # 尝试发送3次
|
||||
if tcp_command_send(upc_addr, upc_command, data):
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令第{i}次发送成功"
|
||||
logging.info(logstr)
|
||||
return
|
||||
else:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令第{i}次发送失败,3秒后进行第{i+1}次尝试"
|
||||
logging.warning(logstr)
|
||||
time.sleep(3)
|
||||
i = i + 1
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令在3次尝试后发送均失败!"
|
||||
logging.error(logstr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
UPC_DEV_IP = sys.argv[1]
|
||||
UPC_DEV_PORT = sys.argv[2]
|
||||
upc_command = sys.argv[3]
|
||||
LOG_FILE = sys.argv[4]
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
UPC_ADDR = (UPC_DEV_IP, int(UPC_DEV_PORT))
|
||||
|
||||
# 验证端口是否能Telnet通
|
||||
try:
|
||||
logging.debug(f"尝试通过 Telnet 检查端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} 可访问性...")
|
||||
tn = telnetlib.Telnet(UPC_DEV_IP, UPC_DEV_PORT)
|
||||
tn.close()
|
||||
logging.debug(f"端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} Telnet 检查通过。")
|
||||
except OSError as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} 端口无法访问,请检查设备或网络连接: {e}!!!!!"
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} Telnet检查时发生未知错误: {e}!!!!!"
|
||||
logging.error(logstr, exc_info=True)
|
||||
print(logstr)
|
||||
else:
|
||||
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)
|
||||
140
bin/sender_tcp.py
Executable file
140
bin/sender_tcp.py
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
import logging
|
||||
import telnetlib
|
||||
|
||||
|
||||
def tcp_command_send(upc_addr, upc_command, data):
|
||||
"""负责发送数据和接收一次响应"""
|
||||
timeout = 2
|
||||
socket.setdefaulttimeout(timeout)
|
||||
try:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
logging.debug(f"尝试连接到 {upc_addr[0]}:{upc_addr[1]}...")
|
||||
client.connect(upc_addr)
|
||||
logging.debug(f"成功连接到 {upc_addr[0]}:{upc_addr[1]}。")
|
||||
|
||||
logging.info(f"正在发送命令 '{upc_command}' 到 {upc_addr}: {data!r} (原始字节)")
|
||||
client.send(data)
|
||||
logging.debug(f"数据发送完成。")
|
||||
|
||||
recv_buffer_size = 1024
|
||||
response_bytes = b''
|
||||
try:
|
||||
logging.debug(f"尝试从 {upc_addr} 接收响应数据...")
|
||||
response_bytes = client.recv(recv_buffer_size)
|
||||
if response_bytes:
|
||||
logging.info(f"从 {upc_addr} 收到原始响应字节: {response_bytes!r}")
|
||||
try:
|
||||
response_str = response_bytes.decode('utf-8', errors='ignore')
|
||||
logging.info(f"从 {upc_addr} 收到解码响应字符串: '{response_str}'")
|
||||
except Exception as decode_e:
|
||||
logging.warning(f"解码从 {upc_addr} 收到的响应时发生错误: {decode_e}")
|
||||
else:
|
||||
logging.info(f"从 {upc_addr} 未收到响应数据 (连接可能已关闭或设备未发送)。")
|
||||
except socket.timeout:
|
||||
logging.warning(f"从 {upc_addr} 接收响应超时。")
|
||||
except OSError as recv_e:
|
||||
logging.error(f"从 {upc_addr} 接收响应时发生网络错误: {recv_e}")
|
||||
|
||||
client.close()
|
||||
logging.debug(f"连接关闭。")
|
||||
return True
|
||||
except OSError as e:
|
||||
logging.error(f"命令 '{upc_command}' 发送至 {upc_addr} 失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# 指令定义表(从配置文件读取)
|
||||
COMMAND_DEFINITIONS = {
|
||||
"open1": "000100000008010F006400010001",
|
||||
"close1": "000100000008010F006400010000",
|
||||
"open2": "000100000008010F006500010001",
|
||||
"close2": "000100000008010F006500010000",
|
||||
"open3": "000100000008010F006600010001",
|
||||
"close3": "000100000008010F006600010000",
|
||||
"open4": "000100000008010F006700010001",
|
||||
"close4": "000100000008010F006700010000",
|
||||
"openall4": "000100000008010F00640004000F",
|
||||
"closeall4": "000100000008010F006400040000",
|
||||
"open5": "000100000008010F006800010001",
|
||||
"close5": "000100000008010F006800010000",
|
||||
"open6": "000100000008010F006900010001",
|
||||
"close6": "000100000008010F006900010000",
|
||||
"open7": "000100000008010F006A00010001",
|
||||
"close7": "000100000008010F006A00010000",
|
||||
"open8": "000100000008010F006B00010001",
|
||||
"close8": "000100000008010F006B00010000",
|
||||
"getstat": "fe010000000429C6",
|
||||
"getstat01": "fe010100000429C6",
|
||||
}
|
||||
|
||||
|
||||
def upc_send_command(upc_addr, upc_command, log_file):
|
||||
"""将命令发送给终端设备"""
|
||||
data = None
|
||||
|
||||
# 查找指令定义
|
||||
if upc_command in COMMAND_DEFINITIONS:
|
||||
hex_str = COMMAND_DEFINITIONS[upc_command]
|
||||
data = bytes.fromhex(hex_str)
|
||||
|
||||
if data is None:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} 未知命令: {upc_command},没有对应的数据可发送。"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
else:
|
||||
i = 1
|
||||
while i <= 3: # 尝试发送3次
|
||||
if tcp_command_send(upc_addr, upc_command, data):
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令第{i}次发送成功"
|
||||
logging.info(logstr)
|
||||
return
|
||||
else:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令第{i}次发送失败,3秒后进行第{i+1}次尝试"
|
||||
logging.warning(logstr)
|
||||
time.sleep(3)
|
||||
i = i + 1
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令在3次尝试后发送均失败!"
|
||||
logging.error(logstr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
UPC_DEV_IP = sys.argv[1]
|
||||
UPC_DEV_PORT = sys.argv[2]
|
||||
upc_command = sys.argv[3]
|
||||
LOG_FILE = sys.argv[4]
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
UPC_ADDR = (UPC_DEV_IP, int(UPC_DEV_PORT))
|
||||
|
||||
# 验证端口是否能Telnet通
|
||||
try:
|
||||
logging.debug(f"尝试通过 Telnet 检查端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} 可访问性...")
|
||||
tn = telnetlib.Telnet(UPC_DEV_IP, UPC_DEV_PORT)
|
||||
tn.close()
|
||||
logging.debug(f"端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} Telnet 检查通过。")
|
||||
except OSError as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} 端口无法访问,请检查设备或网络连接: {e}!!!!!"
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} Telnet检查时发生未知错误: {e}!!!!!"
|
||||
logging.error(logstr, exc_info=True)
|
||||
print(logstr)
|
||||
else:
|
||||
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)
|
||||
128
bin/sender_udp.py
Executable file
128
bin/sender_udp.py
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
import logging
|
||||
|
||||
|
||||
def udp_command_send(upc_addr, upc_command, data, timeout=2):
|
||||
"""通过UDP发送数据并接收响应"""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.settimeout(timeout)
|
||||
|
||||
try:
|
||||
logging.debug(f"尝试发送UDP数据到 {upc_addr[0]}:{upc_addr[1]}...")
|
||||
|
||||
logging.info(f"正在发送UDP命令 '{upc_command}' 到 {upc_addr}: {data!r} (原始字节)")
|
||||
sock.sendto(data, upc_addr)
|
||||
logging.debug(f"UDP数据发送完成。")
|
||||
|
||||
# 尝试接收响应
|
||||
recv_buffer_size = 1024
|
||||
try:
|
||||
logging.debug(f"等待从 {upc_addr} 接收UDP响应...")
|
||||
response_bytes, addr = sock.recvfrom(recv_buffer_size)
|
||||
if response_bytes:
|
||||
logging.info(f"从 {addr} 收到UDP原始响应字节: {response_bytes!r}")
|
||||
try:
|
||||
response_str = response_bytes.decode('utf-8', errors='ignore')
|
||||
logging.info(f"从 {addr} 收到UDP解码响应字符串: '{response_str}'")
|
||||
except Exception as decode_e:
|
||||
logging.warning(f"解码UDP响应时发生错误: {decode_e}")
|
||||
else:
|
||||
logging.info(f"未收到UDP响应数据。")
|
||||
except socket.timeout:
|
||||
logging.warning(f"接收UDP响应超时(设备可能不返回响应,这通常是正常的)。")
|
||||
except OSError as recv_e:
|
||||
logging.error(f"接收UDP响应时发生网络错误: {recv_e}")
|
||||
|
||||
sock.close()
|
||||
logging.debug(f"UDP socket关闭。")
|
||||
return True
|
||||
except OSError as e:
|
||||
logging.error(f"UDP命令 '{upc_command}' 发送至 {upc_addr} 失败: {e}")
|
||||
return False
|
||||
finally:
|
||||
try:
|
||||
sock.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# 指令定义表(从配置文件读取)
|
||||
COMMAND_DEFINITIONS = {
|
||||
"open1": "000100000008010F006400010001",
|
||||
"close1": "000100000008010F006400010000",
|
||||
"open2": "000100000008010F006500010001",
|
||||
"close2": "000100000008010F006500010000",
|
||||
"open3": "000100000008010F006600010001",
|
||||
"close3": "000100000008010F006600010000",
|
||||
"open4": "000100000008010F006700010001",
|
||||
"close4": "000100000008010F006700010000",
|
||||
"openall4": "000100000008010F00640004000F",
|
||||
"closeall4": "000100000008010F006400040000",
|
||||
"open5": "000100000008010F006800010001",
|
||||
"close5": "000100000008010F006800010000",
|
||||
"open6": "000100000008010F006900010001",
|
||||
"close6": "000100000008010F006900010000",
|
||||
"open7": "000100000008010F006A00010001",
|
||||
"close7": "000100000008010F006A00010000",
|
||||
"open8": "000100000008010F006B00010001",
|
||||
"close8": "000100000008010F006B00010000",
|
||||
"getstat": "fe010000000429C6",
|
||||
"getstat01": "fe010100000429C6",
|
||||
}
|
||||
|
||||
|
||||
def upc_send_command(upc_addr, upc_command, log_file):
|
||||
"""将命令发送给终端设备"""
|
||||
data = None
|
||||
|
||||
# 查找指令定义
|
||||
if upc_command in COMMAND_DEFINITIONS:
|
||||
hex_str = COMMAND_DEFINITIONS[upc_command]
|
||||
data = bytes.fromhex(hex_str)
|
||||
|
||||
if data is None:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} 未知命令: {upc_command},没有对应的数据可发送。"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
else:
|
||||
i = 1
|
||||
while i <= 3: # 尝试发送3次
|
||||
if udp_command_send(upc_addr, upc_command, data):
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令第{i}次发送成功"
|
||||
logging.info(logstr)
|
||||
return
|
||||
else:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令第{i}次发送失败,3秒后进行第{i+1}次尝试"
|
||||
logging.warning(logstr)
|
||||
time.sleep(3)
|
||||
i = i + 1
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{datetime_str} {upc_command}命令在3次尝试后发送均失败!"
|
||||
logging.error(logstr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
UPC_DEV_IP = sys.argv[1]
|
||||
UPC_DEV_PORT = int(sys.argv[2])
|
||||
upc_command = sys.argv[3]
|
||||
LOG_FILE = sys.argv[4]
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
UPC_ADDR = (UPC_DEV_IP, UPC_DEV_PORT)
|
||||
|
||||
# UDP 是无连接的,无需像TCP那样预先检查端口连通性
|
||||
# 直接发送数据
|
||||
logging.info(f"UDP模式:准备发送命令到 {UPC_ADDR}")
|
||||
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)
|
||||
63
config/devices.json
Normal file
63
config/devices.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"global": {
|
||||
"tms_server_ip": "192.168.8.9",
|
||||
"python_path": "/usr/bin/python3",
|
||||
"base_dir": "/home/smart/pythonPJ/upc_resent"
|
||||
},
|
||||
"devices": [
|
||||
{
|
||||
"id": "dev1",
|
||||
"name": "设备73-TCP",
|
||||
"protocol": "tcp",
|
||||
"upc_ip": "192.168.8.73",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10079,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "dev2",
|
||||
"name": "设备125-TCP",
|
||||
"protocol": "tcp",
|
||||
"upc_ip": "192.168.8.125",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10129,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "dev3",
|
||||
"name": "设备UDP示例",
|
||||
"protocol": "udp",
|
||||
"upc_ip": "192.168.8.200",
|
||||
"upc_port": 502,
|
||||
"listen_port": 10080,
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"commands": {
|
||||
"open1": "000100000008010F006400010001",
|
||||
"close1": "000100000008010F006400010000",
|
||||
"open2": "000100000008010F006500010001",
|
||||
"close2": "000100000008010F006500010000",
|
||||
"open3": "000100000008010F006600010001",
|
||||
"close3": "000100000008010F006600010000",
|
||||
"open4": "000100000008010F006700010001",
|
||||
"close4": "000100000008010F006700010000",
|
||||
"openall4": "000100000008010F00640004000F",
|
||||
"closeall4": "000100000008010F006400040000",
|
||||
"open5": "000100000008010F006800010001",
|
||||
"close5": "000100000008010F006800010000",
|
||||
"open6": "000100000008010F006900010001",
|
||||
"close6": "000100000008010F006900010000",
|
||||
"open7": "000100000008010F006A00010001",
|
||||
"close7": "000100000008010F006A00010000",
|
||||
"open8": "000100000008010F006B00010001",
|
||||
"close8": "000100000008010F006B00010000",
|
||||
"getstat": "fe010000000429C6",
|
||||
"getstat01": "fe010100000429C6"
|
||||
},
|
||||
"mappings": {
|
||||
"open": "openall4",
|
||||
"close": "closeall4",
|
||||
"guanggao-guan": "closeall4"
|
||||
}
|
||||
}
|
||||
69
crond/upcrond-192.168.8.125.py
Normal file
69
crond/upcrond-192.168.8.125.py
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys # sys 模块用于 sys.exit(),虽然这里没有直接使用,但通常在脚本中需要
|
||||
|
||||
# --- 配置日志 ---
|
||||
# 确保日志文件路径正确
|
||||
LOG_FILE = '/opt/upc_resent/log/upc-192.168.8.125.log'
|
||||
# 定义时间格式,将被 logging.basicConfig 的 datefmt 使用
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 配置日志,确保只执行一次
|
||||
# format 中包含了时间戳 %(asctime)s,所以不需要手动在日志字符串中添加 datetime
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
# --- 日志配置结束 ---
|
||||
|
||||
|
||||
def IsOpen(ip, port):
|
||||
"""
|
||||
检查指定IP和端口是否可达。
|
||||
如果端口不可达,则记录警告并尝试重启另一个Python脚本。
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1) # 设置连接超时为1秒,避免无限期阻塞
|
||||
try:
|
||||
logging.debug(f"尝试连接到 {ip}:{port}...")
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(socket.SHUT_RDWR) # 使用 SHUT_RDWR 代替数字 2,更具可读性
|
||||
|
||||
print(f"端口 {port} is open") # Python 3 print 函数
|
||||
logging.info(f"端口 {port} is open")
|
||||
return True
|
||||
except (OSError, socket.timeout) as e: # 捕获具体的网络错误和超时
|
||||
print(f"端口 {port} is down") # Python 3 print 函数
|
||||
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
|
||||
|
||||
# --- 重启命令 ---
|
||||
# 确保这里的 python3 路径和脚本路径正确
|
||||
# 这里的脚本名 "192.168.8.125.py" 看起来是硬编码的,请确认是否正确
|
||||
restart_command = "/usr/bin/python3 /opt/upc_resent/bin/192.168.8.125.py &"
|
||||
logging.info(f"执行重启命令: {restart_command}")
|
||||
os.system(restart_command)
|
||||
# --- 重启命令结束 ---
|
||||
|
||||
return False
|
||||
except ValueError: # 捕获 int(port) 转换失败的情况
|
||||
print(f"错误: 端口 '{port}' 不是有效的数字。")
|
||||
logging.error(f"端口 '{port}' 不是有效的数字。")
|
||||
return False
|
||||
finally:
|
||||
s.close() # 确保无论成功或失败,socket 都会被关闭
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# --- 目标设备IP和端口 ---
|
||||
# 这些值在原脚本中是硬编码的,如果需要从命令行参数获取,请修改
|
||||
target_ip = '192.168.8.9'
|
||||
target_port = 10129
|
||||
# --- 目标设备IP和端口结束 ---
|
||||
|
||||
logging.info(f"启动端口检查程序,检查 {target_ip}:{target_port}")
|
||||
IsOpen(target_ip, target_port)
|
||||
|
||||
|
||||
69
crond/upcrond-192.168.8.73.py
Normal file
69
crond/upcrond-192.168.8.73.py
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys # sys 模块用于 sys.exit(),虽然这里没有直接使用,但通常在脚本中需要
|
||||
|
||||
# --- 配置日志 ---
|
||||
# 确保日志文件路径正确
|
||||
LOG_FILE = '/opt/upc_resent/log/upc-192.168.8.73.log'
|
||||
# 定义时间格式,将被 logging.basicConfig 的 datefmt 使用
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 配置日志,确保只执行一次
|
||||
# format 中包含了时间戳 %(asctime)s,所以不需要手动在日志字符串中添加 datetime
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
# --- 日志配置结束 ---
|
||||
|
||||
|
||||
def IsOpen(ip, port):
|
||||
"""
|
||||
检查指定IP和端口是否可达。
|
||||
如果端口不可达,则记录警告并尝试重启另一个Python脚本。
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1) # 设置连接超时为1秒,避免无限期阻塞
|
||||
try:
|
||||
logging.debug(f"尝试连接到 {ip}:{port}...")
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(socket.SHUT_RDWR) # 使用 SHUT_RDWR 代替数字 2,更具可读性
|
||||
|
||||
print(f"端口 {port} is open") # Python 3 print 函数
|
||||
logging.info(f"端口 {port} is open")
|
||||
return True
|
||||
except (OSError, socket.timeout) as e: # 捕获具体的网络错误和超时
|
||||
print(f"端口 {port} is down") # Python 3 print 函数
|
||||
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
|
||||
|
||||
# --- 重启命令 ---
|
||||
# 确保这里的 python3 路径和脚本路径正确
|
||||
# 这里的脚本名 "192.168.8.125.py" 看起来是硬编码的,请确认是否正确
|
||||
restart_command = "/usr/bin/python3 /opt/upc_resent/bin/192.168.8.73.py &"
|
||||
logging.info(f"执行重启命令: {restart_command}")
|
||||
os.system(restart_command)
|
||||
# --- 重启命令结束 ---
|
||||
|
||||
return False
|
||||
except ValueError: # 捕获 int(port) 转换失败的情况
|
||||
print(f"错误: 端口 '{port}' 不是有效的数字。")
|
||||
logging.error(f"端口 '{port}' 不是有效的数字。")
|
||||
return False
|
||||
finally:
|
||||
s.close() # 确保无论成功或失败,socket 都会被关闭
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# --- 目标设备IP和端口 ---
|
||||
# 这些值在原脚本中是硬编码的,如果需要从命令行参数获取,请修改
|
||||
target_ip = '192.168.8.9'
|
||||
target_port = 10079
|
||||
# --- 目标设备IP和端口结束 ---
|
||||
|
||||
logging.info(f"启动端口检查程序,检查 {target_ip}:{target_port}")
|
||||
IsOpen(target_ip, target_port)
|
||||
|
||||
|
||||
54
crond/upcrond-dev1.py
Executable file
54
crond/upcrond-dev1.py
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: 设备73-TCP (dev1)
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TARGET_IP = '192.168.8.9'
|
||||
TARGET_PORT = 10079
|
||||
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/crond-dev1.log'
|
||||
RESTART_COMMAND = "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev1.py &"
|
||||
DEVICE_ID = 'dev1'
|
||||
# =========================
|
||||
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
|
||||
|
||||
def is_port_open(ip, port):
|
||||
"""检查指定IP和端口是否可达"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1)
|
||||
try:
|
||||
logging.debug(f"尝试连接到 {ip}:{port}...")
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
print(f"[{DEVICE_ID}] 端口 {port} is open")
|
||||
logging.info(f"端口 {port} is open")
|
||||
return True
|
||||
except (OSError, socket.timeout) as e:
|
||||
print(f"[{DEVICE_ID}] 端口 {port} is down")
|
||||
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
|
||||
logging.info(f"执行重启命令: {RESTART_COMMAND}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except ValueError:
|
||||
print(f"错误: 端口 '{port}' 不是有效的数字。")
|
||||
logging.error(f"端口 '{port}' 不是有效的数字。")
|
||||
return False
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.info(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
|
||||
print(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
|
||||
is_port_open(TARGET_IP, TARGET_PORT)
|
||||
54
crond/upcrond-dev2.py
Executable file
54
crond/upcrond-dev2.py
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: 设备125-TCP (dev2)
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TARGET_IP = '192.168.8.9'
|
||||
TARGET_PORT = 10129
|
||||
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/crond-dev2.log'
|
||||
RESTART_COMMAND = "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev2.py &"
|
||||
DEVICE_ID = 'dev2'
|
||||
# =========================
|
||||
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
|
||||
|
||||
def is_port_open(ip, port):
|
||||
"""检查指定IP和端口是否可达"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1)
|
||||
try:
|
||||
logging.debug(f"尝试连接到 {ip}:{port}...")
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
print(f"[{DEVICE_ID}] 端口 {port} is open")
|
||||
logging.info(f"端口 {port} is open")
|
||||
return True
|
||||
except (OSError, socket.timeout) as e:
|
||||
print(f"[{DEVICE_ID}] 端口 {port} is down")
|
||||
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
|
||||
logging.info(f"执行重启命令: {RESTART_COMMAND}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except ValueError:
|
||||
print(f"错误: 端口 '{port}' 不是有效的数字。")
|
||||
logging.error(f"端口 '{port}' 不是有效的数字。")
|
||||
return False
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.info(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
|
||||
print(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
|
||||
is_port_open(TARGET_IP, TARGET_PORT)
|
||||
85
crond/upcrond-dev3.py
Executable file
85
crond/upcrond-dev3.py
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: 设备UDP示例 (dev3) - UDP Protocol
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TARGET_IP = '192.168.8.9'
|
||||
TARGET_PORT = 10080
|
||||
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/crond-dev3.log'
|
||||
RESTART_COMMAND = "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev3.py &"
|
||||
DEVICE_ID = 'dev3'
|
||||
# =========================
|
||||
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
|
||||
|
||||
def is_udp_port_open(ip, port):
|
||||
"""
|
||||
检查UDP端口是否可用。
|
||||
UDP是无连接的,这里通过检查端口是否被占用或发送测试数据来判断。
|
||||
"""
|
||||
try:
|
||||
# 尝试绑定到该端口,如果成功说明端口未被占用(服务未启动)
|
||||
# 如果失败说明端口已被占用(服务正在运行)
|
||||
test_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
test_sock.settimeout(1)
|
||||
test_sock.bind((ip, int(port)))
|
||||
test_sock.close()
|
||||
|
||||
# 如果绑定成功,说明服务未启动
|
||||
print(f"[{DEVICE_ID}] UDP端口 {port} 未被占用,服务可能未运行")
|
||||
logging.warning(f"UDP端口 {port} 未被占用,服务可能未运行,尝试重启程序")
|
||||
logging.info(f"执行重启命令: {RESTART_COMMAND}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except OSError as e:
|
||||
# 绑定失败,说明端口已被占用,服务正在运行
|
||||
if "Address already in use" in str(e) or "98" in str(e):
|
||||
print(f"[{DEVICE_ID}] UDP端口 {port} is open (已被占用,服务运行中)")
|
||||
logging.info(f"UDP端口 {port} is open (服务运行中)")
|
||||
return True
|
||||
else:
|
||||
print(f"[{DEVICE_ID}] 检查UDP端口 {port} 时发生错误: {e}")
|
||||
logging.error(f"检查UDP端口 {port} 时发生错误: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def check_process_running():
|
||||
"""通过进程名检查服务是否正在运行"""
|
||||
try:
|
||||
# 检查是否有对应设备的Python进程在运行
|
||||
cmd = f"ps aux | grep '{DEVICE_ID}.py' | grep -v grep"
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
print(f"[{DEVICE_ID}] 进程检查: 服务正在运行")
|
||||
logging.info(f"进程检查: 服务正在运行")
|
||||
return True
|
||||
else:
|
||||
print(f"[{DEVICE_ID}] 进程检查: 服务未运行")
|
||||
logging.warning(f"进程检查: 服务未运行,尝试重启")
|
||||
logging.info(f"执行重启命令: {RESTART_COMMAND}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"[{DEVICE_ID}] 进程检查失败: {e}")
|
||||
logging.error(f"进程检查失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.info(f"[{DEVICE_ID}] 启动UDP端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
|
||||
print(f"[{DEVICE_ID}] 启动UDP端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
|
||||
|
||||
# 对于UDP,优先使用进程检查方式
|
||||
check_process_running()
|
||||
4
crontab.txt
Normal file
4
crontab.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
* */1 * * * /usr/bin/python3 /home/smart/pythonPJ/upc_resent/crond/upcrond-dev1.py
|
||||
* */1 * * * /usr/bin/python3 /home/smart/pythonPJ/upc_resent/crond/upcrond-dev2.py
|
||||
* */1 * * * /usr/bin/python3 /home/smart/pythonPJ/upc_resent/crond/upcrond-dev3.py
|
||||
0 0 * * * /home/smart/pythonPJ/upc_resent/cutlog.sh
|
||||
8
cutlog.sh
Normal file
8
cutlog.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
declare logs_path="/opt/upc_resent/log";
|
||||
declare need_delete_path=${logs_path}/$(date -d "7 days ago" "+%Y_%m_%d");
|
||||
declare yestoday_log_path=${logs_path}/$(date -d "yesterday" "+%Y_%m_%d");
|
||||
rm -rf ${need_delete_path}
|
||||
rm -rf ${yestoday_log_path}
|
||||
mv ${logs_path}/today ${yestoday_log_path}
|
||||
mkdir -p ${logs_path}/today
|
||||
BIN
log/192.168.8.125.log
Normal file
BIN
log/192.168.8.125.log
Normal file
Binary file not shown.
5
log/192.168.8.73.log
Normal file
5
log/192.168.8.73.log
Normal file
@@ -0,0 +1,5 @@
|
||||
INFO:root:服务启动,监听 192.168.8.9:10079
|
||||
INFO:root:===2026-03-21 20:14:40收到客户端192.168.9.71:56925发送的指令: 'close1'
|
||||
INFO:root:===2026-03-21 20:14:40 映射到内部指令: 'close1'
|
||||
INFO:root:执行外部命令: /usr/bin/python3 /opt/upc_resent/bin/sender.py 192.168.8.73 502 close1 /opt/upc_resent/log/192.168.8.73.log
|
||||
INFO:root:2026-03-21 20:14:40 close1命令第1次发送成功
|
||||
3
log/upc-192.168.8.125.log
Normal file
3
log/upc-192.168.8.125.log
Normal file
@@ -0,0 +1,3 @@
|
||||
2026-03-21 21:06:19 - INFO - 启动端口检查程序,检查 192.168.8.9:10129
|
||||
2026-03-21 21:06:19 - DEBUG - 尝试连接到 192.168.8.9:10129...
|
||||
2026-03-21 21:06:19 - INFO - 端口 10129 is open
|
||||
403
scripts/generate.py
Normal file
403
scripts/generate.py
Normal file
@@ -0,0 +1,403 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
"""
|
||||
代码生成器:根据配置文件自动生成 Python 执行文件
|
||||
支持 TCP 和 UDP 协议
|
||||
|
||||
用法: python scripts/generate.py [--check]
|
||||
--check: 仅检查配置,不生成文件
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
|
||||
def load_config(config_file='config/devices.json'):
|
||||
"""加载配置文件"""
|
||||
with open(config_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def ensure_dirs(base_dir):
|
||||
"""确保必要的目录存在"""
|
||||
dirs = [
|
||||
os.path.join(base_dir, 'bin'),
|
||||
os.path.join(base_dir, 'crond'),
|
||||
os.path.join(base_dir, 'log')
|
||||
]
|
||||
for d in dirs:
|
||||
os.makedirs(d, exist_ok=True)
|
||||
|
||||
|
||||
def dict_to_python_string(d):
|
||||
"""将字典转换为 Python 代码字符串"""
|
||||
lines = ['{']
|
||||
for k, v in d.items():
|
||||
if isinstance(v, str):
|
||||
lines.append(f' "{k}": "{v}",')
|
||||
else:
|
||||
lines.append(f' "{k}": {v},')
|
||||
lines.append('}')
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def get_template_path(protocol, template_type):
|
||||
"""
|
||||
根据协议类型和模板类型获取模板文件路径
|
||||
protocol: 'tcp' 或 'udp'
|
||||
template_type: 'listener', 'crond', 'sender'
|
||||
"""
|
||||
protocol = protocol.lower()
|
||||
if template_type == 'listener':
|
||||
return f'templates/listener_{protocol}.py.tpl'
|
||||
elif template_type == 'crond':
|
||||
return f'templates/crond_{protocol}.py.tpl'
|
||||
elif template_type == 'sender':
|
||||
return f'templates/sender_{protocol}.py.tpl'
|
||||
else:
|
||||
raise ValueError(f"未知的模板类型: {template_type}")
|
||||
|
||||
|
||||
def generate_listener(device, global_config, mappings):
|
||||
"""生成监听服务文件"""
|
||||
protocol = device.get('protocol', 'tcp').lower()
|
||||
template_file = get_template_path(protocol, 'listener')
|
||||
|
||||
# 检查模板文件是否存在
|
||||
if not os.path.exists(template_file):
|
||||
print(f"[!] 警告: 模板文件不存在: {template_file},使用TCP模板作为后备")
|
||||
template_file = 'templates/listener_tcp.py.tpl'
|
||||
|
||||
with open(template_file, 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
# 构建命令映射字典字符串
|
||||
mappings_str = "{\n"
|
||||
for cmd, op in mappings.items():
|
||||
mappings_str += f' "{cmd}": "{op}",\n'
|
||||
# 添加默认映射(open1-open8, close1-close8)
|
||||
for i in range(1, 9):
|
||||
mappings_str += f' "open{i}": "open{i}",\n'
|
||||
mappings_str += f' "close{i}": "close{i}",\n'
|
||||
mappings_str += " }"
|
||||
|
||||
# 替换模板变量
|
||||
content = template.format(
|
||||
device_id=device['id'],
|
||||
device_name=device['name'],
|
||||
tms_server_ip=global_config['tms_server_ip'],
|
||||
listen_port=device['listen_port'],
|
||||
upc_ip=device['upc_ip'],
|
||||
upc_port=device['upc_port'],
|
||||
base_dir=global_config['base_dir'],
|
||||
python_path=global_config['python_path'],
|
||||
command_mappings=mappings_str
|
||||
)
|
||||
|
||||
output_file = os.path.join(global_config['base_dir'], 'bin', f"{device['id']}.py")
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
os.chmod(output_file, 0o755)
|
||||
print(f"[生成] {output_file} ({protocol.upper()})")
|
||||
return output_file
|
||||
|
||||
|
||||
def generate_crond(device, global_config):
|
||||
"""生成保活检查文件"""
|
||||
protocol = device.get('protocol', 'tcp').lower()
|
||||
template_file = get_template_path(protocol, 'crond')
|
||||
|
||||
# 检查模板文件是否存在
|
||||
if not os.path.exists(template_file):
|
||||
print(f"[!] 警告: 模板文件不存在: {template_file},使用TCP模板作为后备")
|
||||
template_file = 'templates/crond_tcp.py.tpl'
|
||||
|
||||
with open(template_file, 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
content = template.format(
|
||||
device_id=device['id'],
|
||||
device_name=device['name'],
|
||||
tms_server_ip=global_config['tms_server_ip'],
|
||||
listen_port=device['listen_port'],
|
||||
base_dir=global_config['base_dir'],
|
||||
python_path=global_config['python_path']
|
||||
)
|
||||
|
||||
output_file = os.path.join(global_config['base_dir'], 'crond', f"upcrond-{device['id']}.py")
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
os.chmod(output_file, 0o755)
|
||||
print(f"[生成] {output_file} ({protocol.upper()})")
|
||||
return output_file
|
||||
|
||||
|
||||
def generate_sender(commands, global_config, protocol='tcp'):
|
||||
"""生成发送模块文件"""
|
||||
protocol = protocol.lower()
|
||||
template_file = get_template_path(protocol, 'sender')
|
||||
|
||||
# 检查模板文件是否存在
|
||||
if not os.path.exists(template_file):
|
||||
print(f"[!] 警告: 模板文件不存在: {template_file},使用TCP模板作为后备")
|
||||
template_file = 'templates/sender_tcp.py.tpl'
|
||||
|
||||
with open(template_file, 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
# 构建指令定义字典字符串
|
||||
cmd_defs = "{\n"
|
||||
for cmd, hex_str in commands.items():
|
||||
cmd_defs += f' "{cmd}": "{hex_str}",\n'
|
||||
cmd_defs += "}"
|
||||
|
||||
content = template.format(
|
||||
command_definitions=cmd_defs
|
||||
)
|
||||
|
||||
# 根据协议生成不同的文件名
|
||||
output_file = os.path.join(global_config['base_dir'], 'bin', f'sender_{protocol}.py')
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
os.chmod(output_file, 0o755)
|
||||
print(f"[生成] {output_file} ({protocol.upper()})")
|
||||
return output_file
|
||||
|
||||
|
||||
def generate_all_senders(config, global_config):
|
||||
"""为所有使用到的协议生成 sender 文件"""
|
||||
commands = config['commands']
|
||||
devices = config['devices']
|
||||
|
||||
# 收集所有使用的协议类型
|
||||
protocols = set()
|
||||
for device in devices:
|
||||
if device.get('enabled', True):
|
||||
protocol = device.get('protocol', 'tcp').lower()
|
||||
protocols.add(protocol)
|
||||
|
||||
generated = []
|
||||
for protocol in protocols:
|
||||
generated.append(generate_sender(commands, global_config, protocol))
|
||||
|
||||
return generated
|
||||
|
||||
|
||||
def generate_crontab(devices, global_config):
|
||||
"""生成 crontab 配置"""
|
||||
lines = []
|
||||
|
||||
for device in devices:
|
||||
if not device.get('enabled', True):
|
||||
continue
|
||||
# 每分钟执行一次保活检查
|
||||
lines.append(f"* */1 * * * {global_config['python_path']} {global_config['base_dir']}/crond/upcrond-{device['id']}.py")
|
||||
|
||||
# 添加日志清理任务
|
||||
lines.append(f"0 0 * * * {global_config['base_dir']}/cutlog.sh")
|
||||
|
||||
content = '\n'.join(lines) + '\n'
|
||||
output_file = 'crontab.txt'
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"[生成] {output_file}")
|
||||
return output_file
|
||||
|
||||
|
||||
def generate_start_script(devices, global_config):
|
||||
"""生成启动脚本"""
|
||||
lines = ['#!/bin/bash']
|
||||
lines.append('# Auto-generated start script')
|
||||
lines.append('')
|
||||
lines.append('# 启动所有监听服务')
|
||||
|
||||
for device in devices:
|
||||
if not device.get('enabled', True):
|
||||
lines.append(f"# {device['name']} ({device['id']}) - 已禁用")
|
||||
continue
|
||||
protocol = device.get('protocol', 'tcp').upper()
|
||||
script_path = f"{global_config['base_dir']}/bin/{device['id']}.py"
|
||||
lines.append(f"echo '启动 {device['name']} ({device['id']}) - {protocol}...'")
|
||||
lines.append(f"su root -c \"{global_config['python_path']} {script_path} &\"")
|
||||
|
||||
lines.append('')
|
||||
lines.append('echo "所有服务已启动"')
|
||||
|
||||
content = '\n'.join(lines) + '\n'
|
||||
output_file = 'start.sh'
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
os.chmod(output_file, 0o755)
|
||||
print(f"[生成] {output_file}")
|
||||
return output_file
|
||||
|
||||
|
||||
def check_config(config):
|
||||
"""检查配置是否合法"""
|
||||
errors = []
|
||||
warnings = []
|
||||
|
||||
global_cfg = config.get('global', {})
|
||||
devices = config.get('devices', [])
|
||||
commands = config.get('commands', {})
|
||||
mappings = config.get('mappings', {})
|
||||
|
||||
# 检查全局配置
|
||||
required_globals = ['tms_server_ip', 'python_path', 'base_dir']
|
||||
for key in required_globals:
|
||||
if key not in global_cfg:
|
||||
errors.append(f"缺少全局配置: {key}")
|
||||
|
||||
# 检查设备配置
|
||||
if not devices:
|
||||
errors.append("没有配置任何设备")
|
||||
|
||||
device_ids = []
|
||||
listen_ports = []
|
||||
|
||||
for device in devices:
|
||||
device_id = device.get('id')
|
||||
if not device_id:
|
||||
errors.append("设备缺少 id 字段")
|
||||
continue
|
||||
|
||||
if device_id in device_ids:
|
||||
errors.append(f"设备 id 重复: {device_id}")
|
||||
device_ids.append(device_id)
|
||||
|
||||
required_device_fields = ['name', 'upc_ip', 'upc_port', 'listen_port']
|
||||
for field in required_device_fields:
|
||||
if field not in device:
|
||||
errors.append(f"设备 {device_id} 缺少字段: {field}")
|
||||
|
||||
# 检查协议类型
|
||||
protocol = device.get('protocol', 'tcp').lower()
|
||||
if protocol not in ['tcp', 'udp']:
|
||||
errors.append(f"设备 {device_id} 的协议类型无效: {protocol} (必须是 tcp 或 udp)")
|
||||
|
||||
if 'listen_port' in device:
|
||||
port = device['listen_port']
|
||||
if port in listen_ports:
|
||||
errors.append(f"设备 {device_id} 的监听端口 {port} 与其他设备冲突")
|
||||
listen_ports.append(port)
|
||||
|
||||
# 检查指令定义
|
||||
if not commands:
|
||||
warnings.append("没有定义任何指令")
|
||||
|
||||
# 检查映射
|
||||
for cmd, op in mappings.items():
|
||||
if op not in commands and not any(op == f"open{i}" or op == f"close{i}" for i in range(1, 9)):
|
||||
warnings.append(f"映射 '{cmd}' -> '{op}' 的目标指令未在 commands 中定义")
|
||||
|
||||
# 检查模板文件是否存在
|
||||
protocols = set()
|
||||
for device in devices:
|
||||
if device.get('enabled', True):
|
||||
protocols.add(device.get('protocol', 'tcp').lower())
|
||||
|
||||
for protocol in protocols:
|
||||
for template_type in ['listener', 'crond', 'sender']:
|
||||
template_file = get_template_path(protocol, template_type)
|
||||
if not os.path.exists(template_file):
|
||||
warnings.append(f"模板文件不存在: {template_file}")
|
||||
|
||||
# 输出检查结果
|
||||
if errors:
|
||||
print("\n[!] 配置错误:")
|
||||
for e in errors:
|
||||
print(f" - {e}")
|
||||
|
||||
if warnings:
|
||||
print("\n[*] 配置警告:")
|
||||
for w in warnings:
|
||||
print(f" - {w}")
|
||||
|
||||
if not errors and not warnings:
|
||||
print("\n[✓] 配置检查通过")
|
||||
return True
|
||||
|
||||
return len(errors) == 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='UPC Resent 代码生成器 (支持 TCP/UDP)')
|
||||
parser.add_argument('--check', action='store_true', help='仅检查配置,不生成文件')
|
||||
args = parser.parse_args()
|
||||
|
||||
print("=" * 50)
|
||||
print("UPC Resent 代码生成器 (支持 TCP/UDP)")
|
||||
print("=" * 50)
|
||||
|
||||
# 加载配置
|
||||
try:
|
||||
config = load_config()
|
||||
print("\n[✓] 配置文件加载成功")
|
||||
except Exception as e:
|
||||
print(f"\n[!] 加载配置文件失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 检查配置
|
||||
if not check_config(config):
|
||||
print("\n[!] 配置检查失败,请修正后重试")
|
||||
sys.exit(1)
|
||||
|
||||
if args.check:
|
||||
print("\n[✓] 仅检查模式,不生成文件")
|
||||
sys.exit(0)
|
||||
|
||||
# 提取配置
|
||||
global_config = config['global']
|
||||
devices = [d for d in config['devices'] if d.get('enabled', True)]
|
||||
|
||||
# 确保目录存在
|
||||
ensure_dirs(global_config['base_dir'])
|
||||
print(f"[✓] 目录检查完成: {global_config['base_dir']}")
|
||||
|
||||
print("\n" + "-" * 50)
|
||||
print("开始生成文件...")
|
||||
print("-" * 50)
|
||||
|
||||
# 生成文件
|
||||
generated_files = []
|
||||
|
||||
# 1. 为所有使用到的协议生成 sender.py
|
||||
print("\n[生成发送模块]")
|
||||
generated_files.extend(generate_all_senders(config, global_config))
|
||||
|
||||
# 2. 为每个设备生成监听服务和保活脚本
|
||||
print("\n[生成设备服务]")
|
||||
for device in devices:
|
||||
print(f"\n处理设备: {device['name']} ({device['id']}) - {device.get('protocol', 'tcp').upper()}")
|
||||
generated_files.append(generate_listener(device, global_config, config['mappings']))
|
||||
generated_files.append(generate_crond(device, global_config))
|
||||
|
||||
# 3. 生成 crontab
|
||||
print("\n[生成配置文件]")
|
||||
generated_files.append(generate_crontab(config['devices'], global_config))
|
||||
|
||||
# 4. 生成启动脚本
|
||||
generated_files.append(generate_start_script(devices, global_config))
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print(f"[✓] 代码生成完成!共生成 {len(generated_files)} 个文件")
|
||||
print("=" * 50)
|
||||
print(f"\n部署目录: {global_config['base_dir']}")
|
||||
print("\n使用方法:")
|
||||
print(f" 1. 启动服务: ./{generated_files[-1]}")
|
||||
print(f" 2. 配置 crontab: crontab crontab.txt")
|
||||
print("\n支持的协议:")
|
||||
protocols = set(d.get('protocol', 'tcp').upper() for d in devices)
|
||||
for p in protocols:
|
||||
print(f" - {p}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
12
start.sh
Executable file
12
start.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# Auto-generated start script
|
||||
|
||||
# 启动所有监听服务
|
||||
echo '启动 设备73-TCP (dev1) - TCP...'
|
||||
su root -c "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev1.py &"
|
||||
echo '启动 设备125-TCP (dev2) - TCP...'
|
||||
su root -c "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev2.py &"
|
||||
echo '启动 设备UDP示例 (dev3) - UDP...'
|
||||
su root -c "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev3.py &"
|
||||
|
||||
echo "所有服务已启动"
|
||||
54
templates/crond_tcp.py.tpl
Normal file
54
templates/crond_tcp.py.tpl
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: {device_name} ({device_id})
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TARGET_IP = '{tms_server_ip}'
|
||||
TARGET_PORT = {listen_port}
|
||||
LOG_FILE = '{base_dir}/log/crond-{device_id}.log'
|
||||
RESTART_COMMAND = "{python_path} {base_dir}/bin/{device_id}.py &"
|
||||
DEVICE_ID = '{device_id}'
|
||||
# =========================
|
||||
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
|
||||
|
||||
def is_port_open(ip, port):
|
||||
"""检查指定IP和端口是否可达"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1)
|
||||
try:
|
||||
logging.debug(f"尝试连接到 {{ip}}:{{port}}...")
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
print(f"[{{DEVICE_ID}}] 端口 {{port}} is open")
|
||||
logging.info(f"端口 {{port}} is open")
|
||||
return True
|
||||
except (OSError, socket.timeout) as e:
|
||||
print(f"[{{DEVICE_ID}}] 端口 {{port}} is down")
|
||||
logging.warning(f"端口 {{port}} 检查失败: {{e}},尝试重启程序")
|
||||
logging.info(f"执行重启命令: {{RESTART_COMMAND}}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except ValueError:
|
||||
print(f"错误: 端口 '{{port}}' 不是有效的数字。")
|
||||
logging.error(f"端口 '{{port}}' 不是有效的数字。")
|
||||
return False
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.info(f"[{{DEVICE_ID}}] 启动端口检查程序,检查 {{TARGET_IP}}:{{TARGET_PORT}}")
|
||||
print(f"[{{DEVICE_ID}}] 启动端口检查程序,检查 {{TARGET_IP}}:{{TARGET_PORT}}")
|
||||
is_port_open(TARGET_IP, TARGET_PORT)
|
||||
85
templates/crond_udp.py.tpl
Normal file
85
templates/crond_udp.py.tpl
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: {device_name} ({device_id}) - UDP Protocol
|
||||
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TARGET_IP = '{tms_server_ip}'
|
||||
TARGET_PORT = {listen_port}
|
||||
LOG_FILE = '{base_dir}/log/crond-{device_id}.log'
|
||||
RESTART_COMMAND = "{python_path} {base_dir}/bin/{device_id}.py &"
|
||||
DEVICE_ID = '{device_id}'
|
||||
# =========================
|
||||
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
|
||||
|
||||
|
||||
def is_udp_port_open(ip, port):
|
||||
"""
|
||||
检查UDP端口是否可用。
|
||||
UDP是无连接的,这里通过检查端口是否被占用或发送测试数据来判断。
|
||||
"""
|
||||
try:
|
||||
# 尝试绑定到该端口,如果成功说明端口未被占用(服务未启动)
|
||||
# 如果失败说明端口已被占用(服务正在运行)
|
||||
test_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
test_sock.settimeout(1)
|
||||
test_sock.bind((ip, int(port)))
|
||||
test_sock.close()
|
||||
|
||||
# 如果绑定成功,说明服务未启动
|
||||
print(f"[{{DEVICE_ID}}] UDP端口 {{port}} 未被占用,服务可能未运行")
|
||||
logging.warning(f"UDP端口 {{port}} 未被占用,服务可能未运行,尝试重启程序")
|
||||
logging.info(f"执行重启命令: {{RESTART_COMMAND}}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except OSError as e:
|
||||
# 绑定失败,说明端口已被占用,服务正在运行
|
||||
if "Address already in use" in str(e) or "98" in str(e):
|
||||
print(f"[{{DEVICE_ID}}] UDP端口 {{port}} is open (已被占用,服务运行中)")
|
||||
logging.info(f"UDP端口 {{port}} is open (服务运行中)")
|
||||
return True
|
||||
else:
|
||||
print(f"[{{DEVICE_ID}}] 检查UDP端口 {{port}} 时发生错误: {{e}}")
|
||||
logging.error(f"检查UDP端口 {{port}} 时发生错误: {{e}}")
|
||||
return False
|
||||
|
||||
|
||||
def check_process_running():
|
||||
"""通过进程名检查服务是否正在运行"""
|
||||
try:
|
||||
# 检查是否有对应设备的Python进程在运行
|
||||
cmd = f"ps aux | grep '{{DEVICE_ID}}.py' | grep -v grep"
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
print(f"[{{DEVICE_ID}}] 进程检查: 服务正在运行")
|
||||
logging.info(f"进程检查: 服务正在运行")
|
||||
return True
|
||||
else:
|
||||
print(f"[{{DEVICE_ID}}] 进程检查: 服务未运行")
|
||||
logging.warning(f"进程检查: 服务未运行,尝试重启")
|
||||
logging.info(f"执行重启命令: {{RESTART_COMMAND}}")
|
||||
os.system(RESTART_COMMAND)
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"[{{DEVICE_ID}}] 进程检查失败: {{e}}")
|
||||
logging.error(f"进程检查失败: {{e}}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.info(f"[{{DEVICE_ID}}] 启动UDP端口检查程序,检查 {{TARGET_IP}}:{{TARGET_PORT}}")
|
||||
print(f"[{{DEVICE_ID}}] 启动UDP端口检查程序,检查 {{TARGET_IP}}:{{TARGET_PORT}}")
|
||||
|
||||
# 对于UDP,优先使用进程检查方式
|
||||
check_process_running()
|
||||
104
templates/listener_tcp.py.tpl
Normal file
104
templates/listener_tcp.py.tpl
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: {device_name} ({device_id})
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TMS_SERVER_IP = '{tms_server_ip}'
|
||||
TMS_PORT = {listen_port}
|
||||
UPC_DEV_IP = '{upc_ip}'
|
||||
UPC_DEV_PORT = '{upc_port}'
|
||||
SENDER_FILE = '{base_dir}/bin/sender_tcp.py'
|
||||
LOG_FILE = '{base_dir}/log/{device_id}.log'
|
||||
PYTHON_PATH = '{python_path}'
|
||||
DEVICE_ID = '{device_id}'
|
||||
# =========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 命令映射表
|
||||
COMMAND_MAPPINGS = {command_mappings}
|
||||
|
||||
|
||||
def process_command(buf):
|
||||
"""处理接收到的命令,返回对应的操作指令"""
|
||||
buf = buf.strip()
|
||||
if buf in COMMAND_MAPPINGS:
|
||||
return COMMAND_MAPPINGS[buf]
|
||||
return "nodata"
|
||||
|
||||
|
||||
def main():
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
|
||||
sock.listen(500)
|
||||
except OSError as e:
|
||||
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
|
||||
" 无法绑定端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
sys.exit(1)
|
||||
|
||||
logging.info("服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
|
||||
print(f"[{{DEVICE_ID}}] 服务启动,监听 {{TMS_SERVER_IP}}:{{TMS_PORT}}")
|
||||
|
||||
while True:
|
||||
connection, address = sock.accept()
|
||||
try:
|
||||
connection.settimeout(5)
|
||||
buf_bytes = connection.recv(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip()
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 收到客户端 " + address[0] + ":" + str(address[1]) + \
|
||||
" 发送的指令: '" + str(buf) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
operation = process_command(buf)
|
||||
|
||||
if operation == "nodata":
|
||||
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
|
||||
else:
|
||||
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
|
||||
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
|
||||
str(operation) + " " + str(LOG_FILE)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command)
|
||||
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
|
||||
except socket.timeout:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 客户端连接超时: " + address[0] + ":" + str(address[1]) + "==="
|
||||
logging.warning(logstr)
|
||||
print('time out')
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 处理客户端 " + address[0] + ":" + str(address[1]) + \
|
||||
" 请求时发生错误: " + str(e) + "==="
|
||||
logging.error(logstr, exc_info=True)
|
||||
print("Error processing request:", e)
|
||||
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
98
templates/listener_udp.py.tpl
Normal file
98
templates/listener_udp.py.tpl
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
# Device: {device_name} ({device_id}) - UDP Protocol
|
||||
|
||||
import socket
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# ====== 配置参数(从配置文件读取)======
|
||||
TMS_SERVER_IP = '{tms_server_ip}'
|
||||
TMS_PORT = {listen_port}
|
||||
UPC_DEV_IP = '{upc_ip}'
|
||||
UPC_DEV_PORT = {upc_port}
|
||||
SENDER_FILE = '{base_dir}/bin/sender_udp.py'
|
||||
LOG_FILE = '{base_dir}/log/{device_id}.log'
|
||||
PYTHON_PATH = '{python_path}'
|
||||
DEVICE_ID = '{device_id}'
|
||||
# =========================
|
||||
|
||||
BUFSIZE = 1024
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
# 命令映射表
|
||||
COMMAND_MAPPINGS = {command_mappings}
|
||||
|
||||
|
||||
def process_command(buf):
|
||||
"""处理接收到的命令,返回对应的操作指令"""
|
||||
buf = buf.strip()
|
||||
if buf in COMMAND_MAPPINGS:
|
||||
return COMMAND_MAPPINGS[buf]
|
||||
return "nodata"
|
||||
|
||||
|
||||
def main():
|
||||
# 创建 UDP socket
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
|
||||
except OSError as e:
|
||||
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
|
||||
" 无法绑定UDP端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
sys.exit(1)
|
||||
|
||||
logging.info("UDP服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
|
||||
print(f"[{{DEVICE_ID}}] UDP服务启动,监听 {{TMS_SERVER_IP}}:{{TMS_PORT}}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
# UDP 使用 recvfrom 接收数据,同时获取客户端地址
|
||||
buf_bytes, client_addr = sock.recvfrom(BUFSIZE)
|
||||
buf = buf_bytes.decode('utf-8').strip()
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 收到UDP客户端 " + client_addr[0] + ":" + str(client_addr[1]) + \
|
||||
" 发送的指令: '" + str(buf) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
operation = process_command(buf)
|
||||
|
||||
if operation == "nodata":
|
||||
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
# 发送UDP响应
|
||||
sock.sendto(('Unknown command: %s' % buf).encode('utf-8'), client_addr)
|
||||
else:
|
||||
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
|
||||
logging.info(logstr)
|
||||
print(logstr)
|
||||
|
||||
# 执行发送指令的脚本
|
||||
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
|
||||
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
|
||||
str(operation) + " " + str(LOG_FILE)
|
||||
logging.info("执行外部命令: %s" % os_command)
|
||||
os.system(os_command)
|
||||
|
||||
# 发送UDP响应
|
||||
sock.sendto(('Command %s processed as %s' % (buf, operation)).encode('utf-8'), client_addr)
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = "===" + datetime_str + " 处理UDP请求时发生错误: " + str(e) + "==="
|
||||
logging.error(logstr, exc_info=True)
|
||||
print("Error processing UDP request:", e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
119
templates/sender_tcp.py.tpl
Normal file
119
templates/sender_tcp.py.tpl
Normal file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
import logging
|
||||
import telnetlib
|
||||
|
||||
|
||||
def tcp_command_send(upc_addr, upc_command, data):
|
||||
"""负责发送数据和接收一次响应"""
|
||||
timeout = 2
|
||||
socket.setdefaulttimeout(timeout)
|
||||
try:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
logging.debug(f"尝试连接到 {{upc_addr[0]}}:{{upc_addr[1]}}...")
|
||||
client.connect(upc_addr)
|
||||
logging.debug(f"成功连接到 {{upc_addr[0]}}:{{upc_addr[1]}}。")
|
||||
|
||||
logging.info(f"正在发送命令 '{{upc_command}}' 到 {{upc_addr}}: {{data!r}} (原始字节)")
|
||||
client.send(data)
|
||||
logging.debug(f"数据发送完成。")
|
||||
|
||||
recv_buffer_size = 1024
|
||||
response_bytes = b''
|
||||
try:
|
||||
logging.debug(f"尝试从 {{upc_addr}} 接收响应数据...")
|
||||
response_bytes = client.recv(recv_buffer_size)
|
||||
if response_bytes:
|
||||
logging.info(f"从 {{upc_addr}} 收到原始响应字节: {{response_bytes!r}}")
|
||||
try:
|
||||
response_str = response_bytes.decode('utf-8', errors='ignore')
|
||||
logging.info(f"从 {{upc_addr}} 收到解码响应字符串: '{{response_str}}'")
|
||||
except Exception as decode_e:
|
||||
logging.warning(f"解码从 {{upc_addr}} 收到的响应时发生错误: {{decode_e}}")
|
||||
else:
|
||||
logging.info(f"从 {{upc_addr}} 未收到响应数据 (连接可能已关闭或设备未发送)。")
|
||||
except socket.timeout:
|
||||
logging.warning(f"从 {{upc_addr}} 接收响应超时。")
|
||||
except OSError as recv_e:
|
||||
logging.error(f"从 {{upc_addr}} 接收响应时发生网络错误: {{recv_e}}")
|
||||
|
||||
client.close()
|
||||
logging.debug(f"连接关闭。")
|
||||
return True
|
||||
except OSError as e:
|
||||
logging.error(f"命令 '{{upc_command}}' 发送至 {{upc_addr}} 失败: {{e}}")
|
||||
return False
|
||||
|
||||
|
||||
# 指令定义表(从配置文件读取)
|
||||
COMMAND_DEFINITIONS = {command_definitions}
|
||||
|
||||
|
||||
def upc_send_command(upc_addr, upc_command, log_file):
|
||||
"""将命令发送给终端设备"""
|
||||
data = None
|
||||
|
||||
# 查找指令定义
|
||||
if upc_command in COMMAND_DEFINITIONS:
|
||||
hex_str = COMMAND_DEFINITIONS[upc_command]
|
||||
data = bytes.fromhex(hex_str)
|
||||
|
||||
if data is None:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} 未知命令: {{upc_command}},没有对应的数据可发送。"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
else:
|
||||
i = 1
|
||||
while i <= 3: # 尝试发送3次
|
||||
if tcp_command_send(upc_addr, upc_command, data):
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送成功"
|
||||
logging.info(logstr)
|
||||
return
|
||||
else:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送失败,3秒后进行第{{i+1}}次尝试"
|
||||
logging.warning(logstr)
|
||||
time.sleep(3)
|
||||
i = i + 1
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} {{upc_command}}命令在3次尝试后发送均失败!"
|
||||
logging.error(logstr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
UPC_DEV_IP = sys.argv[1]
|
||||
UPC_DEV_PORT = sys.argv[2]
|
||||
upc_command = sys.argv[3]
|
||||
LOG_FILE = sys.argv[4]
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
UPC_ADDR = (UPC_DEV_IP, int(UPC_DEV_PORT))
|
||||
|
||||
# 验证端口是否能Telnet通
|
||||
try:
|
||||
logging.debug(f"尝试通过 Telnet 检查端口 {{UPC_ADDR[0]}}:{{UPC_ADDR[1]}} 可访问性...")
|
||||
tn = telnetlib.Telnet(UPC_DEV_IP, UPC_DEV_PORT)
|
||||
tn.close()
|
||||
logging.debug(f"端口 {{UPC_ADDR[0]}}:{{UPC_ADDR[1]}} Telnet 检查通过。")
|
||||
except OSError as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"!!!!!ERROR!!!!!{{datetime_str}} {{UPC_ADDR}} 端口无法访问,请检查设备或网络连接: {{e}}!!!!!"
|
||||
logging.error(logstr)
|
||||
print(logstr)
|
||||
except Exception as e:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"!!!!!ERROR!!!!!{{datetime_str}} {{UPC_ADDR}} Telnet检查时发生未知错误: {{e}}!!!!!"
|
||||
logging.error(logstr, exc_info=True)
|
||||
print(logstr)
|
||||
else:
|
||||
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)
|
||||
107
templates/sender_udp.py.tpl
Normal file
107
templates/sender_udp.py.tpl
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Auto-generated from template. DO NOT EDIT DIRECTLY!
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
import logging
|
||||
|
||||
|
||||
def udp_command_send(upc_addr, upc_command, data, timeout=2):
|
||||
"""通过UDP发送数据并接收响应"""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.settimeout(timeout)
|
||||
|
||||
try:
|
||||
logging.debug(f"尝试发送UDP数据到 {{upc_addr[0]}}:{{upc_addr[1]}}...")
|
||||
|
||||
logging.info(f"正在发送UDP命令 '{{upc_command}}' 到 {{upc_addr}}: {{data!r}} (原始字节)")
|
||||
sock.sendto(data, upc_addr)
|
||||
logging.debug(f"UDP数据发送完成。")
|
||||
|
||||
# 尝试接收响应
|
||||
recv_buffer_size = 1024
|
||||
try:
|
||||
logging.debug(f"等待从 {{upc_addr}} 接收UDP响应...")
|
||||
response_bytes, addr = sock.recvfrom(recv_buffer_size)
|
||||
if response_bytes:
|
||||
logging.info(f"从 {{addr}} 收到UDP原始响应字节: {{response_bytes!r}}")
|
||||
try:
|
||||
response_str = response_bytes.decode('utf-8', errors='ignore')
|
||||
logging.info(f"从 {{addr}} 收到UDP解码响应字符串: '{{response_str}}'")
|
||||
except Exception as decode_e:
|
||||
logging.warning(f"解码UDP响应时发生错误: {{decode_e}}")
|
||||
else:
|
||||
logging.info(f"未收到UDP响应数据。")
|
||||
except socket.timeout:
|
||||
logging.warning(f"接收UDP响应超时(设备可能不返回响应,这通常是正常的)。")
|
||||
except OSError as recv_e:
|
||||
logging.error(f"接收UDP响应时发生网络错误: {{recv_e}}")
|
||||
|
||||
sock.close()
|
||||
logging.debug(f"UDP socket关闭。")
|
||||
return True
|
||||
except OSError as e:
|
||||
logging.error(f"UDP命令 '{{upc_command}}' 发送至 {{upc_addr}} 失败: {{e}}")
|
||||
return False
|
||||
finally:
|
||||
try:
|
||||
sock.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# 指令定义表(从配置文件读取)
|
||||
COMMAND_DEFINITIONS = {command_definitions}
|
||||
|
||||
|
||||
def upc_send_command(upc_addr, upc_command, log_file):
|
||||
"""将命令发送给终端设备"""
|
||||
data = None
|
||||
|
||||
# 查找指令定义
|
||||
if upc_command in COMMAND_DEFINITIONS:
|
||||
hex_str = COMMAND_DEFINITIONS[upc_command]
|
||||
data = bytes.fromhex(hex_str)
|
||||
|
||||
if data is None:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} 未知命令: {{upc_command}},没有对应的数据可发送。"
|
||||
logging.warning(logstr)
|
||||
print(logstr)
|
||||
else:
|
||||
i = 1
|
||||
while i <= 3: # 尝试发送3次
|
||||
if udp_command_send(upc_addr, upc_command, data):
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送成功"
|
||||
logging.info(logstr)
|
||||
return
|
||||
else:
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送失败,3秒后进行第{{i+1}}次尝试"
|
||||
logging.warning(logstr)
|
||||
time.sleep(3)
|
||||
i = i + 1
|
||||
|
||||
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
|
||||
logstr = f"{{datetime_str}} {{upc_command}}命令在3次尝试后发送均失败!"
|
||||
logging.error(logstr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ISOTIMEFORMAT = '%Y-%m-%d %X'
|
||||
|
||||
UPC_DEV_IP = sys.argv[1]
|
||||
UPC_DEV_PORT = int(sys.argv[2])
|
||||
upc_command = sys.argv[3]
|
||||
LOG_FILE = sys.argv[4]
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
|
||||
UPC_ADDR = (UPC_DEV_IP, UPC_DEV_PORT)
|
||||
|
||||
# UDP 是无连接的,无需像TCP那样预先检查端口连通性
|
||||
# 直接发送数据
|
||||
logging.info(f"UDP模式:准备发送命令到 {{UPC_ADDR}}")
|
||||
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)
|
||||
3
upcstart.sh
Normal file
3
upcstart.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
su root -c "/usr/bin/python /opt/upc_resent/bin/192.168.8.73.py &"
|
||||
su root -c "/usr/bin/python /opt/upc_resent/bin/192.168.8.125.py &"
|
||||
Reference in New Issue
Block a user