2023-03-11 08:04:43 +00:00
|
|
|
|
#!/usr/bin/env python3
|
2023-03-11 13:25:34 +00:00
|
|
|
|
# coding:utf-8
|
2023-03-10 01:34:44 +00:00
|
|
|
|
import socketserver
|
|
|
|
|
import subprocess
|
2023-03-11 03:51:56 +00:00
|
|
|
|
import pickle
|
2023-03-13 07:27:36 +00:00
|
|
|
|
from collections import defaultdict
|
2023-03-13 09:20:43 +00:00
|
|
|
|
import datetime
|
|
|
|
|
import time
|
2023-03-18 06:53:09 +00:00
|
|
|
|
import requests
|
2023-03-19 05:32:33 +00:00
|
|
|
|
import socket
|
2023-03-18 06:53:09 +00:00
|
|
|
|
# import json
|
2023-03-23 06:56:48 +00:00
|
|
|
|
from threading import Timer
|
2024-01-05 07:52:10 +00:00
|
|
|
|
from loguru import logger
|
2024-01-23 10:33:35 +00:00
|
|
|
|
import os
|
2023-03-18 06:53:09 +00:00
|
|
|
|
|
2024-01-25 02:25:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def gettm():
|
|
|
|
|
"""
|
|
|
|
|
返回时戳和日期
|
|
|
|
|
"""
|
|
|
|
|
t= datetime.datetime.now()
|
|
|
|
|
d = str(t)
|
|
|
|
|
return d,d[:10]
|
|
|
|
|
|
|
|
|
|
def save2file(data,isR=1):
|
|
|
|
|
"""
|
|
|
|
|
存储数据至文件
|
|
|
|
|
"""
|
|
|
|
|
t,d = gettm()
|
|
|
|
|
|
2024-01-25 02:43:28 +00:00
|
|
|
|
p = '/'.join(['./trlog',d])
|
2024-01-25 02:25:08 +00:00
|
|
|
|
if not os.path.exists(p):
|
|
|
|
|
os.makedirs(p)
|
|
|
|
|
|
|
|
|
|
l=f"{'[R]' if isR else '[T]'} - {t} --- {data}\n"
|
2024-01-25 02:43:28 +00:00
|
|
|
|
f=open('/'.join(['./trlog',d,'trlog.txt']),'a')
|
2024-01-25 02:25:08 +00:00
|
|
|
|
f.write(l)
|
|
|
|
|
f.close
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-18 06:53:09 +00:00
|
|
|
|
SERVER = "http://www.pushplus.plus/send"
|
|
|
|
|
TOKEN = "ff328cba923a4225bc4acd0086a9014c"
|
2023-03-18 09:06:09 +00:00
|
|
|
|
# SERVER = "http://push.nmhd.eu.org:12722/push/murmur"
|
2023-03-18 06:53:09 +00:00
|
|
|
|
# TOKEN = "tt"
|
|
|
|
|
|
2023-03-18 09:06:09 +00:00
|
|
|
|
def pp2wx(title,content,description):
|
|
|
|
|
"""通过pushplus发送至微信,有频次限制.
|
2023-03-18 06:53:09 +00:00
|
|
|
|
title:标题
|
|
|
|
|
content:内容"""
|
|
|
|
|
|
|
|
|
|
ppmsg = {"token":TOKEN,
|
2023-03-18 09:06:09 +00:00
|
|
|
|
"template":"json",
|
|
|
|
|
"channel":"wechat",
|
|
|
|
|
"description": description,
|
|
|
|
|
}
|
2023-03-18 06:53:09 +00:00
|
|
|
|
ppmsg["title"] = title
|
|
|
|
|
ppmsg["content"] = content
|
|
|
|
|
# ppmsg["description"]= content
|
|
|
|
|
requests.post(SERVER, json=ppmsg)
|
2023-03-11 03:51:56 +00:00
|
|
|
|
|
2023-03-23 06:56:48 +00:00
|
|
|
|
msgcache=[]
|
2023-03-23 07:56:02 +00:00
|
|
|
|
pushisbusy=0
|
2023-03-23 06:56:48 +00:00
|
|
|
|
def s2wx(title="",description="", content=""):
|
2023-03-18 09:06:09 +00:00
|
|
|
|
"""通过自建msgpusher发送至微信
|
|
|
|
|
当前title值无效
|
|
|
|
|
"""
|
2024-01-05 07:52:10 +00:00
|
|
|
|
# logger.debug(content)
|
2023-04-02 09:09:53 +00:00
|
|
|
|
# return
|
2023-03-23 06:56:48 +00:00
|
|
|
|
# 受API限制,频繁发送会失败
|
|
|
|
|
# 拟合并发送,满3条已发送,超时时间10s
|
|
|
|
|
if len(content):
|
|
|
|
|
t=f"""
|
2024-01-05 07:52:10 +00:00
|
|
|
|
**时戳:**
|
|
|
|
|
{datetime.datetime.now()}
|
|
|
|
|
**信息:**
|
2023-03-23 06:56:48 +00:00
|
|
|
|
{content}"""
|
|
|
|
|
msgcache.append(t)
|
|
|
|
|
|
2023-03-23 08:52:58 +00:00
|
|
|
|
global pushisbusy
|
|
|
|
|
if pushisbusy:
|
2023-03-28 06:40:52 +00:00
|
|
|
|
Timer(10,s2wx).start()
|
2023-03-23 08:52:58 +00:00
|
|
|
|
return
|
|
|
|
|
pushisbusy=1
|
2023-04-03 02:24:24 +00:00
|
|
|
|
le = len(msgcache)
|
2023-03-23 06:56:48 +00:00
|
|
|
|
def send():
|
|
|
|
|
c= " \n".join(msgcache[:3])
|
2024-01-05 07:52:10 +00:00
|
|
|
|
try:
|
2024-10-21 08:42:37 +00:00
|
|
|
|
res = requests.post("http://8.137.110.19:4014/push/murmur", json={
|
2024-01-05 07:52:10 +00:00
|
|
|
|
"title": title,
|
|
|
|
|
"description": description,
|
|
|
|
|
"content": c,
|
2024-10-21 08:42:37 +00:00
|
|
|
|
"channel":"all-TT",
|
|
|
|
|
"token": "gjvL2gMZqj326isgafmz"})
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.debug("msgpusher {}",res)
|
|
|
|
|
except:
|
|
|
|
|
logger.error("msgpusher error");
|
2024-10-21 09:10:55 +00:00
|
|
|
|
|
2024-01-05 08:04:19 +00:00
|
|
|
|
try:
|
2024-10-21 09:10:55 +00:00
|
|
|
|
res = requests.post("https://push.020824.xyz/push/murmur", json={
|
2024-01-05 08:04:19 +00:00
|
|
|
|
"title": title,
|
|
|
|
|
"description": description,
|
2024-10-21 09:10:55 +00:00
|
|
|
|
"content": c,
|
|
|
|
|
"channel":"all-TT",
|
|
|
|
|
"token": "gjvL2gMZqj326isgafmz"})
|
|
|
|
|
logger.debug("msgpusher {}",res)
|
2024-01-05 08:04:19 +00:00
|
|
|
|
except:
|
2024-10-21 09:10:55 +00:00
|
|
|
|
logger.error("msgpusher error");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-01-05 08:04:19 +00:00
|
|
|
|
|
2024-01-05 07:52:10 +00:00
|
|
|
|
# try:
|
2023-09-10 01:28:26 +00:00
|
|
|
|
# try:
|
|
|
|
|
# res = res.json()
|
|
|
|
|
# except:
|
|
|
|
|
# s="http://push.nmhd.eu.org:12722/push/murmur"
|
|
|
|
|
# # s="http://47.108.213.155:11722/push/murmur"
|
|
|
|
|
# res = requests.post(s, json={
|
|
|
|
|
# "title": title,
|
|
|
|
|
# "description": description,
|
|
|
|
|
# "content": c,
|
|
|
|
|
# "token": "tt"})
|
|
|
|
|
# print("nmhd",s)
|
2023-03-25 09:14:55 +00:00
|
|
|
|
# else:
|
|
|
|
|
# if res["success"]:
|
|
|
|
|
# return None
|
|
|
|
|
# else:
|
|
|
|
|
# return res["message"]
|
2023-03-23 06:56:48 +00:00
|
|
|
|
|
2023-04-03 02:24:24 +00:00
|
|
|
|
if le >2:
|
2023-03-23 06:56:48 +00:00
|
|
|
|
send()
|
2023-04-03 02:24:24 +00:00
|
|
|
|
msgcache.pop(0)
|
|
|
|
|
msgcache.pop(0)
|
|
|
|
|
msgcache.pop(0)
|
2023-04-03 02:53:29 +00:00
|
|
|
|
# Timer(10,s2wx).start()
|
2023-04-03 02:24:24 +00:00
|
|
|
|
elif (not len(content)) and le:
|
2023-03-23 06:56:48 +00:00
|
|
|
|
# 等效超时
|
|
|
|
|
send()
|
2023-04-03 02:53:29 +00:00
|
|
|
|
for i in range(le):
|
2023-04-02 09:09:53 +00:00
|
|
|
|
msgcache.pop(0)
|
2023-04-03 02:53:29 +00:00
|
|
|
|
# Timer(10,s2wx).start()
|
2023-03-23 07:56:02 +00:00
|
|
|
|
pushisbusy=0
|
2023-04-03 02:53:29 +00:00
|
|
|
|
Timer(10,s2wx).start()
|
2023-03-18 09:06:09 +00:00
|
|
|
|
# GET 方式
|
|
|
|
|
# res = requests.get(f"{SERVER}/push/{USERNAME}?title={title}"
|
|
|
|
|
# f"&description={description}&content={content}&token={TOKEN}")
|
|
|
|
|
|
|
|
|
|
# POST 方式
|
2023-03-23 06:56:48 +00:00
|
|
|
|
# res = requests.post("http://push.nmhd.eu.org:12722/push/murmur", json={
|
|
|
|
|
# "title": title,
|
|
|
|
|
# "description": description,
|
|
|
|
|
# "content": f"""
|
|
|
|
|
# *时戳:*
|
|
|
|
|
# _{datetime.datetime.now()}_
|
|
|
|
|
# *信息:*
|
|
|
|
|
# {content}""",
|
|
|
|
|
# "token": "tt"
|
|
|
|
|
# })
|
|
|
|
|
# try:
|
|
|
|
|
# res = res.json()
|
|
|
|
|
# except:
|
|
|
|
|
# return
|
|
|
|
|
# else:
|
|
|
|
|
# if res["success"]:
|
|
|
|
|
# return None
|
|
|
|
|
# else:
|
|
|
|
|
# return res["message"]
|
2023-03-28 06:40:52 +00:00
|
|
|
|
Timer(10,s2wx).start()
|
2023-03-18 09:06:09 +00:00
|
|
|
|
|
2023-03-13 07:27:36 +00:00
|
|
|
|
cache = defaultdict(list)
|
2023-03-11 13:25:34 +00:00
|
|
|
|
offs = 0 # 偏移量
|
2023-03-13 07:27:36 +00:00
|
|
|
|
|
|
|
|
|
# 保存终端信息,ccid=地址
|
2023-03-11 13:25:34 +00:00
|
|
|
|
p = {}
|
2023-03-13 07:27:36 +00:00
|
|
|
|
# 地址 ==ccid
|
2023-03-11 13:25:34 +00:00
|
|
|
|
pp = {}
|
|
|
|
|
|
2023-03-13 11:27:54 +00:00
|
|
|
|
|
2023-03-13 09:20:43 +00:00
|
|
|
|
def add_timestamp():
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info("-------------------------↓ {} ↓ -------------------------",datetime.datetime.now() )
|
2023-03-11 03:51:56 +00:00
|
|
|
|
|
2023-03-10 01:34:44 +00:00
|
|
|
|
|
2023-03-11 03:51:56 +00:00
|
|
|
|
def save_cache(dic):
|
2023-03-11 13:25:34 +00:00
|
|
|
|
"""缓存未发送成功的消息
|
2023-03-13 07:14:36 +00:00
|
|
|
|
仅在目标终端未上线或发送失败时缓存
|
|
|
|
|
发送失败的一般原因是终端掉线但未及时更新在线列表"""
|
2023-03-11 03:51:56 +00:00
|
|
|
|
|
|
|
|
|
# f=open("./cache.txt",mode='w+')
|
|
|
|
|
# f.write(str(dic))
|
|
|
|
|
# f.close
|
2023-03-11 13:25:34 +00:00
|
|
|
|
pickle.dump(dic, open("./cache.txt", "wb"))
|
|
|
|
|
|
2023-03-11 03:51:56 +00:00
|
|
|
|
|
|
|
|
|
def load_cache():
|
2023-03-11 13:25:34 +00:00
|
|
|
|
"""程序启动时加载缓存"""
|
2023-03-11 03:51:56 +00:00
|
|
|
|
try:
|
|
|
|
|
# f=open("./cache.txt")
|
|
|
|
|
# c = eval(f.read())
|
|
|
|
|
# f.close()
|
2023-03-11 13:25:34 +00:00
|
|
|
|
c = pickle.load(open("./cache.txt", "rb"))
|
2023-03-11 03:51:56 +00:00
|
|
|
|
return c
|
|
|
|
|
except:
|
|
|
|
|
return None
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
|
2024-10-24 06:50:54 +00:00
|
|
|
|
def update_pairs(addr, ccid, clear=0,cnt=[0]):
|
2023-03-11 13:25:34 +00:00
|
|
|
|
"""更新终端库
|
2023-03-10 09:58:19 +00:00
|
|
|
|
addr:绑定tcp地址
|
|
|
|
|
ccid:终端号
|
2024-10-24 06:38:21 +00:00
|
|
|
|
clear:清空掉线终端
|
|
|
|
|
cnt:心跳包数量"""
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-21 07:14:32 +00:00
|
|
|
|
if not clear:
|
2023-03-11 13:25:34 +00:00
|
|
|
|
# 添加或更新客户端
|
2023-03-21 07:14:32 +00:00
|
|
|
|
pp[addr] = ccid
|
|
|
|
|
p.clear
|
|
|
|
|
|
2023-03-18 06:53:09 +00:00
|
|
|
|
if ccid not in p:
|
2024-10-24 08:10:28 +00:00
|
|
|
|
# 新终端上线,推送在线消息
|
|
|
|
|
cnt[0] = 0
|
2023-03-20 15:10:13 +00:00
|
|
|
|
t = f"""*信息:*
|
|
|
|
|
天通终端上线。
|
2023-03-18 09:06:09 +00:00
|
|
|
|
CCID:{ccid.decode()}
|
2023-03-23 06:56:48 +00:00
|
|
|
|
地址:{str(addr.getpeername())}"""
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
2023-03-19 09:48:50 +00:00
|
|
|
|
s2wx("","天通终端上线",t)
|
2023-03-20 15:10:13 +00:00
|
|
|
|
# p[ccid] = addr
|
2023-03-21 07:14:32 +00:00
|
|
|
|
|
2023-03-10 09:58:19 +00:00
|
|
|
|
else:
|
|
|
|
|
del p[ccid]
|
|
|
|
|
del pp[addr]
|
|
|
|
|
|
|
|
|
|
# 打印在线终端
|
2023-03-20 15:10:13 +00:00
|
|
|
|
# for i in p:
|
|
|
|
|
# print(i, "<--->", p[i])
|
2023-03-21 01:46:59 +00:00
|
|
|
|
od= []
|
2023-03-20 15:10:13 +00:00
|
|
|
|
for i in pp:
|
|
|
|
|
p[pp[i]] = i
|
2023-03-29 02:43:27 +00:00
|
|
|
|
# od.append(f"{pp[i].decode()}<--->{i.getpeername()}")
|
|
|
|
|
# 可能客户端未断开,导致多个连接指向相同的ccid,故需更新后再遍历打印
|
|
|
|
|
for i in p:
|
2023-03-30 13:07:02 +00:00
|
|
|
|
od.append(f"{i.decode()}<--->{p[i].getpeername()}")
|
2023-03-21 01:46:59 +00:00
|
|
|
|
# print('\r\n'.join(zd))
|
|
|
|
|
clents = ' \n'+'\r\n'.join(od) if len(od) else ""
|
2023-03-30 13:07:02 +00:00
|
|
|
|
t=f"在线终端已更新,数量{len(od)}。{clents}"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
2024-10-24 06:50:54 +00:00
|
|
|
|
# cnt[0]是一个列表,它的默认值只会在函数定义时初始化一次,因此它的值在多次调用时保持不变
|
2024-10-24 06:55:22 +00:00
|
|
|
|
# cnt[0]为10的倍数
|
|
|
|
|
if cnt[0]%10 == 0:
|
2024-10-24 06:38:21 +00:00
|
|
|
|
s2wx("","",t)
|
2024-10-24 06:55:22 +00:00
|
|
|
|
cnt[0] += 1
|
2023-03-11 13:25:34 +00:00
|
|
|
|
|
2023-03-10 09:58:19 +00:00
|
|
|
|
def get_addr(ccid):
|
2023-03-11 13:25:34 +00:00
|
|
|
|
"""获取ccid对应的地址"""
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-10 01:34:44 +00:00
|
|
|
|
try:
|
2023-03-10 09:58:19 +00:00
|
|
|
|
# 如果有直接返回
|
|
|
|
|
return p[ccid]
|
2023-03-10 01:34:44 +00:00
|
|
|
|
except Exception:
|
2023-03-11 13:25:34 +00:00
|
|
|
|
# 没有就返回None
|
2023-03-10 09:58:19 +00:00
|
|
|
|
return None
|
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
|
2023-03-10 09:58:19 +00:00
|
|
|
|
def get_ccid(addr):
|
|
|
|
|
try:
|
|
|
|
|
# 如果有直接返回
|
|
|
|
|
return pp[addr]
|
|
|
|
|
except Exception:
|
2023-03-11 13:25:34 +00:00
|
|
|
|
# 没有就返回None
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.warning("终端未上报心跳注册ccid。")
|
2023-03-10 09:58:19 +00:00
|
|
|
|
return None
|
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
|
|
|
|
|
"""
|
2023-03-10 09:58:19 +00:00
|
|
|
|
+--------+--------------+----------+----------+--------------+------------------------+--------+
|
|
|
|
|
| ff | 长度 | 地址信息 | 信令 | 内容 | 校验位 |
|
|
|
|
|
+--------+--------------+----------+----------+--------------+------------------------+--------+
|
2023-03-13 09:20:43 +00:00
|
|
|
|
| | 2Bytes | 4Bytes | 心跳 | 0x01 | 时间戳32bit(单位ms) | 1Bytes |
|
2023-03-10 09:58:19 +00:00
|
|
|
|
+ $TTMS +--------------+----------+----------+--------------+------------------------+--------+
|
2023-03-13 09:20:43 +00:00
|
|
|
|
| | 2Bytes | 4Bytes | 传输数据 | 0xaa | 载荷 | 1Bytes |
|
2023-03-10 09:58:19 +00:00
|
|
|
|
+--------+--------------+----------+----------+--------------+------------------------+--------+
|
2023-03-11 13:25:34 +00:00
|
|
|
|
"""
|
|
|
|
|
|
2024-10-22 07:18:56 +00:00
|
|
|
|
# 回复ACK给终端,使用命令0xAA,载荷为四字节0xFFFFFFFF
|
|
|
|
|
def ack2client(addr,data):
|
|
|
|
|
msg = bytearray(data[:])
|
|
|
|
|
msg[11 + offs] = 0xAA
|
|
|
|
|
# 覆写32bit时戳为FF
|
|
|
|
|
msg[12 + offs:16 + offs] = int(0xFFFFFFFF).to_bytes(4,byteorder="big")
|
|
|
|
|
# 计算校验和
|
|
|
|
|
crc = 0
|
|
|
|
|
for i in msg[:-1]:
|
|
|
|
|
crc = crc ^ i
|
|
|
|
|
msg[-1] = crc
|
|
|
|
|
addr.send(msg)
|
|
|
|
|
# save2file(f"[SERVER --> {get_ccid(addr).decode() if get_ccid(addr) else 'None'}][{len(msg)}] {msg.hex(' ')}",0)
|
|
|
|
|
# logger.debug("服务器回复ACK。")
|
|
|
|
|
|
2023-03-13 11:27:54 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
def tt_hh(addr, data):
|
|
|
|
|
"""处理心跳"""
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
|
|
|
|
# 更新pairs
|
2023-03-11 13:25:34 +00:00
|
|
|
|
ccid = data[7 + offs : 11 + offs]
|
|
|
|
|
update_pairs(addr, ccid)
|
2023-03-10 09:58:19 +00:00
|
|
|
|
# 组帧再返回
|
2023-03-14 13:21:21 +00:00
|
|
|
|
msg = bytearray(data[:])
|
2023-03-23 01:28:23 +00:00
|
|
|
|
msg[:5] = b"$TTMX"
|
2024-01-25 02:25:08 +00:00
|
|
|
|
val = "%04x" % int(time.time()) #取Unix时间戳,以s为单位
|
2023-03-14 14:04:51 +00:00
|
|
|
|
tmp=[]
|
|
|
|
|
for i in range(0,len(val),2):
|
|
|
|
|
tmp.append(int(val[i:i+2],16))
|
|
|
|
|
msg[12:-1] = tmp
|
2023-03-13 09:20:43 +00:00
|
|
|
|
# 计算校验和
|
|
|
|
|
crc = 0
|
|
|
|
|
for i in msg[:-1]:
|
|
|
|
|
crc = crc ^ i
|
|
|
|
|
msg[-1] = crc
|
|
|
|
|
add_timestamp()
|
|
|
|
|
addr.send(msg)
|
2024-01-25 02:25:08 +00:00
|
|
|
|
save2file(f"[SERVER --> {get_ccid(addr).decode() if get_ccid(addr) else 'None'}][{len(msg)}] {msg.hex(' ')}",0)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.debug("服务器回复心跳包。")
|
2024-10-22 07:18:56 +00:00
|
|
|
|
ack2client(addr,msg)
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-13 09:20:43 +00:00
|
|
|
|
# 从缓存中匹配到数据才重发
|
2023-03-11 08:04:43 +00:00
|
|
|
|
# 仅有新终端上线时才重发
|
2023-03-14 14:13:41 +00:00
|
|
|
|
if cache and ccid in cache:
|
2023-03-13 11:27:54 +00:00
|
|
|
|
msgs = cache[ccid][:] # 浅拷贝
|
|
|
|
|
sccid = msgs[0][7 + offs : 11 + offs]
|
|
|
|
|
print("有", len(msgs), "包缓存数据待发。", sccid, "-->", ccid)
|
2023-03-20 15:10:13 +00:00
|
|
|
|
s2wx("","",f"有{len(msgs)}包缓存数据待发。 \n{sccid} --> {ccid}")
|
2023-03-11 08:04:43 +00:00
|
|
|
|
for i in range(len(msgs)):
|
|
|
|
|
try:
|
2023-03-13 09:20:43 +00:00
|
|
|
|
add_timestamp()
|
2023-03-11 09:06:55 +00:00
|
|
|
|
# 按缓存先后顺序发送
|
2023-03-11 08:04:43 +00:00
|
|
|
|
addr.send(msgs[i])
|
2024-06-28 02:24:11 +00:00
|
|
|
|
save2file(f"[SERVER --> {get_ccid(addr).decode() if get_ccid(addr) else 'None'}][{len(msgs[i])}] {msgs[i].hex(' ')}")
|
2024-01-05 07:52:10 +00:00
|
|
|
|
time.sleep(1)
|
2023-03-13 07:27:36 +00:00
|
|
|
|
# 成功则清空已发送成功的缓存数据
|
2023-03-13 02:11:29 +00:00
|
|
|
|
cache[ccid].pop(0)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.debug(f"第 {i + 1} 包缓存数据发送完成。")
|
2023-03-11 08:04:43 +00:00
|
|
|
|
except:
|
2023-03-11 09:06:55 +00:00
|
|
|
|
# 异常时退出循环,不用再尝试发送后续msgs
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.error(f"第 {i + 1} 包发送失败,停止尝试")
|
2023-03-20 15:10:13 +00:00
|
|
|
|
s2wx("","",f"第{i + 1}包发送失败,停止尝试。")
|
2023-03-11 08:04:43 +00:00
|
|
|
|
break
|
2023-03-13 02:11:29 +00:00
|
|
|
|
if cache[ccid] == []:
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(f"缓存数据全部发送完成。 {sccid} --> {ccid}")
|
2023-03-20 15:10:13 +00:00
|
|
|
|
s2wx("","",f"缓存数据全部发送完成。 \n{sccid} --> {ccid}")
|
2023-03-13 02:11:29 +00:00
|
|
|
|
del cache[ccid]
|
|
|
|
|
save_cache(cache)
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
2023-03-13 11:27:54 +00:00
|
|
|
|
|
2023-03-13 09:20:43 +00:00
|
|
|
|
def check_valid(data):
|
|
|
|
|
# 检查数据有效性
|
|
|
|
|
|
|
|
|
|
return bytearray(data[:])
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-22 03:26:46 +00:00
|
|
|
|
def get_info(data):
|
|
|
|
|
# print(type(data[12]))
|
|
|
|
|
o=0
|
|
|
|
|
def h2s(x):
|
|
|
|
|
# x= int.from_bytes(x)
|
|
|
|
|
return str(x)
|
|
|
|
|
pass
|
2023-09-12 09:51:15 +00:00
|
|
|
|
sn = "_".join(list(map(h2s,data[12:19])))
|
2023-06-19 08:59:26 +00:00
|
|
|
|
index=int.from_bytes(data[20:21],byteorder="big")
|
|
|
|
|
cnt=int.from_bytes(data[21:22],byteorder="big")
|
2023-03-22 06:04:13 +00:00
|
|
|
|
t=f"流水号20{sn} \n序号\[{index}/{cnt}]"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
2023-03-22 03:26:46 +00:00
|
|
|
|
s2wx("","",t)
|
|
|
|
|
|
2023-03-13 11:27:54 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
def tt_trans(addr, data):
|
|
|
|
|
"""发送数据到指定ccid"""
|
|
|
|
|
|
2023-03-22 03:26:46 +00:00
|
|
|
|
get_info(data)
|
2023-03-13 07:14:36 +00:00
|
|
|
|
sccid = get_ccid(addr)
|
|
|
|
|
if not sccid:
|
|
|
|
|
return -1
|
2023-03-11 13:25:34 +00:00
|
|
|
|
tccid = data[7 + offs : 11 + offs]
|
2023-03-20 15:10:13 +00:00
|
|
|
|
# taddr = get_addr(tccid)
|
2023-03-10 09:58:19 +00:00
|
|
|
|
# 组帧
|
2023-03-13 09:20:43 +00:00
|
|
|
|
msg = check_valid(data)
|
2023-03-11 13:25:34 +00:00
|
|
|
|
msg[:5] = b"$TTMX"
|
2023-03-13 07:14:36 +00:00
|
|
|
|
msg[7 + offs : 11 + offs] = sccid
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
|
|
|
|
# 计算校验和
|
|
|
|
|
crc = 0
|
2023-03-11 03:51:56 +00:00
|
|
|
|
for i in msg[:-1]:
|
2023-03-10 09:58:19 +00:00
|
|
|
|
crc = crc ^ i
|
2023-03-11 13:25:34 +00:00
|
|
|
|
msg[-1] = crc
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-20 15:10:13 +00:00
|
|
|
|
if tccid not in p:
|
2023-03-11 09:06:55 +00:00
|
|
|
|
# 未找到匹配的在线终端
|
2023-03-11 08:04:43 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
# 更新缓存
|
|
|
|
|
# {tccid1=[msg1,msg2,...],...}
|
2023-03-11 03:51:56 +00:00
|
|
|
|
cache[tccid].append(msg)
|
|
|
|
|
save_cache(cache)
|
2023-03-11 09:06:55 +00:00
|
|
|
|
|
2023-03-27 03:30:04 +00:00
|
|
|
|
t=f"目标终端{tccid.decode()}未在线。 \n数据已缓存,待目标终端上线后重发。"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
2023-03-27 03:30:04 +00:00
|
|
|
|
s2wx("","",t)
|
2023-03-11 03:51:56 +00:00
|
|
|
|
return 0
|
2023-03-20 15:10:13 +00:00
|
|
|
|
taddr = get_addr(tccid)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(f"匹配在线终端为:{tccid} <---> {taddr}")
|
2023-03-11 03:51:56 +00:00
|
|
|
|
|
2023-03-10 09:58:19 +00:00
|
|
|
|
# 发送
|
|
|
|
|
try:
|
2023-03-13 09:20:43 +00:00
|
|
|
|
add_timestamp()
|
2023-03-10 09:58:19 +00:00
|
|
|
|
taddr.send(msg)
|
2024-01-25 02:25:08 +00:00
|
|
|
|
save2file(f"[SERVER --> {get_ccid(taddr).decode() if get_ccid(taddr) else 'None'}][{len(msg)}] {msg.hex(' ')}",0)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(f"数据发送成功。 {sccid} --> {tccid}")
|
2023-03-20 15:10:13 +00:00
|
|
|
|
s2wx("","",f"匹配到在线终端, 数据发送成功。 \n{sccid.decode()} ---> {tccid.decode()}")
|
2023-03-10 09:58:19 +00:00
|
|
|
|
except Exception:
|
2023-03-11 08:04:43 +00:00
|
|
|
|
# 发送失败
|
2023-03-11 09:06:55 +00:00
|
|
|
|
taddr.close()
|
2023-03-11 03:51:56 +00:00
|
|
|
|
# 更新pairs,清空对应终端
|
2023-03-11 13:25:34 +00:00
|
|
|
|
update_pairs(taddr, tccid, 1)
|
|
|
|
|
# 更新缓存
|
|
|
|
|
# {tccid1=[msg1,msg2,...],...}
|
2023-03-11 03:51:56 +00:00
|
|
|
|
cache[tccid].append(msg)
|
|
|
|
|
save_cache(cache)
|
2023-03-11 09:06:55 +00:00
|
|
|
|
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.error("发送失败,终端{}可能已掉线。数据已缓存,待目标终端上线后重发。", taddr)
|
2023-03-20 15:10:13 +00:00
|
|
|
|
s2wx("","",f"发送失败,终端{taddr}可能已掉线。 \n数据已缓存,待目标终端上线后重发。")
|
2023-03-10 09:58:19 +00:00
|
|
|
|
return 0
|
|
|
|
|
|
2024-01-23 10:33:35 +00:00
|
|
|
|
def isInlst(tar,lst):
|
|
|
|
|
"""
|
|
|
|
|
在列表中查找目标子列表
|
2023-03-11 13:25:34 +00:00
|
|
|
|
|
2024-01-23 10:33:35 +00:00
|
|
|
|
返回匹配的列表
|
|
|
|
|
"""
|
|
|
|
|
index = []
|
|
|
|
|
for x in range(len(lst)):
|
|
|
|
|
if lst[x:x+len(tar)] == tar :
|
|
|
|
|
index.append(x)
|
|
|
|
|
|
|
|
|
|
rst = []
|
|
|
|
|
for x in range(len(index)):
|
|
|
|
|
if x<len(index)-1:
|
|
|
|
|
rst.append(lst[index[x]:index[x+1]])
|
|
|
|
|
if x == len(index)-1:
|
|
|
|
|
rst.append(lst[index[-1]:])
|
|
|
|
|
|
|
|
|
|
return rst
|
|
|
|
|
|
|
|
|
|
# 便于拼合数据的缓存
|
|
|
|
|
recCache = {}
|
|
|
|
|
def data_split(addr):
|
2023-03-13 07:14:36 +00:00
|
|
|
|
# 按帧头分割长数据
|
|
|
|
|
|
2023-03-13 11:27:54 +00:00
|
|
|
|
h = b"$TTMS" # b'\x24\x54\x54\x4d\x53'
|
2024-01-23 10:33:35 +00:00
|
|
|
|
dlist = isInlst([0x24,0x54,0x54,0x4d,0x53],recCache[addr])
|
|
|
|
|
# print(dlist)
|
|
|
|
|
|
|
|
|
|
#校验每帧数据
|
2023-03-13 07:14:36 +00:00
|
|
|
|
for i in range(len(dlist)):
|
2024-01-23 10:33:35 +00:00
|
|
|
|
flen = (dlist[i][5]<<8)+dlist[i][6]
|
|
|
|
|
if flen != len(dlist[i]) :
|
2024-01-24 02:48:28 +00:00
|
|
|
|
logger.warning("第{}数据帧不匹配,应收{}<-->实收{}",i+1,flen,len(dlist[i]))
|
2024-01-23 10:33:35 +00:00
|
|
|
|
|
|
|
|
|
# 清空缓存
|
|
|
|
|
recCache[addr].clear()
|
|
|
|
|
|
|
|
|
|
# 因为无帧尾,需添加帧是否完整的校验
|
|
|
|
|
if len(dlist) :
|
|
|
|
|
# 目前情形多为两包粘包,故最后一包肯定不完整
|
2024-01-24 02:48:28 +00:00
|
|
|
|
# logger.debug(bytes(dlist[-1]).hex(" "))
|
2024-01-23 10:33:35 +00:00
|
|
|
|
flen = (dlist[-1][5]<<8)+dlist[-1][6]
|
|
|
|
|
if flen <= len(dlist[-1]) :
|
|
|
|
|
recCache[addr].extend(dlist[-1][flen:])
|
|
|
|
|
for x in range(len(dlist[-1])-flen):
|
|
|
|
|
dlist[-1].pop()
|
|
|
|
|
else:
|
|
|
|
|
recCache[addr].extend(dlist[-1][:])
|
|
|
|
|
dlist.pop()
|
|
|
|
|
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.debug(f"解析为 {len(dlist)} 包数据。")
|
2024-01-23 10:33:35 +00:00
|
|
|
|
if len(recCache[addr]):
|
|
|
|
|
logger.warning("缓存数据为{}",bytes(recCache[addr]).hex(" "))
|
|
|
|
|
return dlist[:]
|
2023-03-13 07:14:36 +00:00
|
|
|
|
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
def tt_decode(addr, data):
|
|
|
|
|
"""处理收到的数据
|
2023-03-13 07:14:36 +00:00
|
|
|
|
|
2023-03-11 09:06:55 +00:00
|
|
|
|
数据正常返回0
|
2023-03-11 13:25:34 +00:00
|
|
|
|
数据异常返回-1"""
|
2024-01-23 10:33:35 +00:00
|
|
|
|
# 追加至缓存末尾
|
|
|
|
|
if addr not in recCache:
|
|
|
|
|
recCache[addr]=[]
|
|
|
|
|
recCache[addr].extend(data)
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-13 07:14:36 +00:00
|
|
|
|
flag = -1
|
|
|
|
|
|
2024-01-23 10:33:35 +00:00
|
|
|
|
dlist = data_split(addr)
|
|
|
|
|
if len(dlist)==0:
|
|
|
|
|
logger.warning("not enough data")
|
|
|
|
|
|
2023-03-13 07:14:36 +00:00
|
|
|
|
for data in dlist:
|
2024-01-23 10:33:35 +00:00
|
|
|
|
data = bytes(data)
|
2023-03-13 07:14:36 +00:00
|
|
|
|
cmd = data[11 + offs]
|
|
|
|
|
# 回退到if-elif而不用match,因服务器默认版本3.8
|
|
|
|
|
if cmd == 0x01:
|
|
|
|
|
# 处理心跳
|
|
|
|
|
flag = tt_hh(addr, data)
|
|
|
|
|
elif cmd == 0xAA:
|
|
|
|
|
# 处理数据
|
|
|
|
|
if tt_trans(addr, data):
|
|
|
|
|
flag = -1
|
|
|
|
|
break
|
|
|
|
|
else:
|
2023-03-13 11:27:54 +00:00
|
|
|
|
flag = 0
|
2023-03-13 07:14:36 +00:00
|
|
|
|
else:
|
|
|
|
|
break
|
|
|
|
|
return flag
|
|
|
|
|
|
2023-03-10 01:34:44 +00:00
|
|
|
|
class MyServer(socketserver.BaseRequestHandler):
|
2023-03-19 02:27:02 +00:00
|
|
|
|
def setup(self):
|
2023-09-09 02:08:53 +00:00
|
|
|
|
self.request.settimeout(60*1.5)
|
2023-03-22 03:26:46 +00:00
|
|
|
|
self.err = " "
|
2023-04-03 02:08:32 +00:00
|
|
|
|
self.recDataBuff=[]
|
2023-03-19 02:27:02 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
def handle(self): # 回调
|
2023-03-13 09:20:43 +00:00
|
|
|
|
add_timestamp()
|
2023-03-29 02:43:27 +00:00
|
|
|
|
t=f"TCP客户端{str(self.client_address)}已连接,等待上报心跳注册ccid。"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info("TCP客户端{}已连接,等待上报心跳注册ccid。",str(self.client_address))
|
2023-09-11 07:13:52 +00:00
|
|
|
|
s2wx("天通消息","TCP客户端接入",t)
|
2023-03-10 01:34:44 +00:00
|
|
|
|
conn = self.request
|
2023-03-10 09:58:19 +00:00
|
|
|
|
# print(type(conn),conn.fd)
|
2023-03-11 13:25:34 +00:00
|
|
|
|
|
2023-03-10 01:34:44 +00:00
|
|
|
|
while True:
|
2023-03-19 05:32:33 +00:00
|
|
|
|
try:
|
|
|
|
|
data = conn.recv(1024000)
|
|
|
|
|
except socket.timeout:
|
2023-03-20 15:10:13 +00:00
|
|
|
|
self.err = "心跳超时。"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.warning("{self.client_address}超时。")
|
2023-03-19 05:32:33 +00:00
|
|
|
|
break
|
2023-03-19 09:48:50 +00:00
|
|
|
|
if not data:
|
|
|
|
|
break
|
|
|
|
|
add_timestamp()
|
2023-04-03 02:08:32 +00:00
|
|
|
|
self.recDataBuff.extend(data)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
# logger.debug("[R] {}",data.hex(" "))
|
2024-01-25 02:25:08 +00:00
|
|
|
|
save2file(f"[{get_ccid(conn).decode() if get_ccid(conn) else 'None'} --> SERVER][{len(data)}] {data.hex(' ')}")
|
2023-03-30 13:07:02 +00:00
|
|
|
|
t = f"从{str(self.client_address)}<->[{get_ccid(conn).decode() if get_ccid(conn) else 'None'}]接收到新数据,长度{len(data)}字节。"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
|
|
|
|
logger.debug("[R] - {}",data.hex(" "))
|
|
|
|
|
# print(data.hex(" "))
|
2024-10-24 06:38:21 +00:00
|
|
|
|
# 心跳报文17字节,避免推送心跳报文刷屏
|
|
|
|
|
if len(data) > 17:
|
|
|
|
|
s2wx("","",t)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
# print("--",len(self.recDataBuff))
|
2023-09-12 09:51:15 +00:00
|
|
|
|
# print(self.recDataBuff[:])
|
2023-03-19 09:48:50 +00:00
|
|
|
|
if tt_decode(conn, data):
|
2023-03-21 07:14:32 +00:00
|
|
|
|
self.err= "切断。"
|
2024-01-23 10:33:35 +00:00
|
|
|
|
# logger.warning(f"{self.client_address}疑是非法连接")
|
2023-03-21 07:14:32 +00:00
|
|
|
|
# conn.close()
|
|
|
|
|
# break
|
2023-03-19 02:27:02 +00:00
|
|
|
|
|
|
|
|
|
def finish(self):
|
|
|
|
|
|
|
|
|
|
if self.request in pp:
|
2023-03-20 15:10:13 +00:00
|
|
|
|
t = f"""终端下线了。{self.err}
|
|
|
|
|
CCID:{pp[self.request].decode()}
|
2023-03-21 07:14:32 +00:00
|
|
|
|
地址:{str(self.client_address)}"""
|
2023-03-29 02:43:27 +00:00
|
|
|
|
update_pairs(self.request,get_ccid(self.request),1)
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
2023-03-19 02:27:02 +00:00
|
|
|
|
s2wx("","天通终端下线了",t)
|
2024-01-23 10:33:35 +00:00
|
|
|
|
recCache[self.request].clear()
|
2023-03-21 07:14:32 +00:00
|
|
|
|
# print("终端",self.client_address,"下线了。",self.err)
|
2023-03-29 02:43:27 +00:00
|
|
|
|
# update_pairs(self.request,get_ccid(self.request),1)
|
2023-03-19 02:27:02 +00:00
|
|
|
|
else:
|
2023-03-21 07:14:32 +00:00
|
|
|
|
t= f"TCP客户端{str(self.client_address)}已断开连接。{self.err}"
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info(t)
|
2024-01-23 10:33:35 +00:00
|
|
|
|
recCache[self.request].clear()
|
2023-09-10 01:28:26 +00:00
|
|
|
|
# s2wx("天通消息","TCP客户端断开",t)
|
2023-03-19 02:27:02 +00:00
|
|
|
|
|
|
|
|
|
|
2023-03-10 09:58:19 +00:00
|
|
|
|
|
2023-03-10 01:34:44 +00:00
|
|
|
|
|
2023-03-11 13:25:34 +00:00
|
|
|
|
if __name__ == "__main__":
|
2024-01-25 02:25:08 +00:00
|
|
|
|
_,t = gettm()
|
2024-01-25 02:43:28 +00:00
|
|
|
|
if not os.path.exists('./debug'):
|
|
|
|
|
os.mkdir('./debug')
|
|
|
|
|
logger.add('/'.join(['./debug',t,'/log_{time}.log']))
|
2023-03-11 03:51:56 +00:00
|
|
|
|
# load_cache
|
2023-03-21 01:46:59 +00:00
|
|
|
|
if load_cache():
|
|
|
|
|
cache = load_cache()
|
2023-03-19 09:57:35 +00:00
|
|
|
|
socketserver.TCPServer.allow_reuse_address = True
|
2023-03-12 05:32:32 +00:00
|
|
|
|
server = socketserver.ThreadingTCPServer(("", 7222), MyServer)
|
2023-03-13 09:20:43 +00:00
|
|
|
|
add_timestamp()
|
2024-01-05 07:52:10 +00:00
|
|
|
|
logger.info("服务端{}初始化成功。", server.server_address)
|
2023-03-20 15:10:13 +00:00
|
|
|
|
s2wx("天通消息","服务器上线","服务器端初始化完成,等待终端连接。")
|
2023-03-19 02:27:02 +00:00
|
|
|
|
server.timeout = 10
|
2023-03-10 01:34:44 +00:00
|
|
|
|
server.serve_forever()
|
2023-03-13 07:14:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
以下几种情况服务器会主动断开终端:
|
|
|
|
|
单次数据不以帧头开始
|
|
|
|
|
单次数据长度不足11
|
|
|
|
|
未上报心跳(注册ccid)而直接发数据
|
2023-03-13 11:27:54 +00:00
|
|
|
|
"""
|