import socket import struct import random import time import threading from datetime import datetime, timedelta # 报文类型常量 MSG_DEBUG = 0 MSG_LVDS = 1 MSG_CAN = 2 MSG_AD9361_CTRL = 3 MSG_WAVE_CTRL = 4 MSG_TEST_PARAM_CTRL = 5 MSG_TEST_WAVE_UPLOAD = 6 MSG_GPS = 7 MSG_STATUS_MONITOR = 8 MSG_PROTO_PARAM_CTRL = 9 MSG_DATA_UPLOAD = 10 MSG_DATA_COLLECT = 11 MSG_DEMOD_DATA = 12 MSG_NOTIFICATION = 13 # 解调器编号常量 VDES_DEMOD_RANGE = (0, 3) # VDES解调器编号0-3 AIS_DEMOD_RANGE = (4, 5) # AIS解调器编号4-5 # 长江入海口坐标范围 (31.0°N - 31.5°N, 121.5°E - 122.0°E) YANGTZE_DELTA_CENTER = (31.23, 121.77) # 上海附近 DELTA_RANGE = 0.05 # ±0.05度 ≈ 5海里 class VDESServer: def __init__(self, host='localhost', port=10): self.host = host self.port = port self.header = b'####' self.running = False self.server_socket = None self.ship_mmsi = 123456789 # 船舶MMSI def start(self): """启动TCP服务器""" self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.bind((self.host, self.port)) self.server_socket.listen(1) self.running = True print(f"VDES Server started on {self.host}:{self.port}") # 接受客户端连接 client_socket, addr = self.server_socket.accept() print(f"Connected by {addr}") # 启动接收线程和定时发送线程 recv_thread = threading.Thread(target=self.handle_client, args=(client_socket,)) send_thread = threading.Thread(target=self.send_periodic_messages, args=(client_socket,)) recv_thread.start() send_thread.start() recv_thread.join() send_thread.join() def stop(self): """停止服务器""" self.running = False if self.server_socket: self.server_socket.close() def build_packet(self, msg_type, content): """构建协议报文:帧头(4) + 类型(4) + 长度(4) + 内容(N)""" length = len(content) return self.header + struct.pack('>I', msg_type) + struct.pack('>I', length) + content def parse_packet(self, data): """解析接收到的报文""" if len(data) < 12 or data[:4] != self.header: return None, None msg_type = struct.unpack('>I', data[4:8])[0] length = struct.unpack('>I', data[8:12])[0] content = data[12:12+length] if len(data) >= 12 + length else None return msg_type, content def handle_debug_command(self, content): """处理调试指令报文(类型0)""" cmd_type = content[0] if content else 0 responses = { 0: "初始化地检", 1: "测试波形上注完成", 2: "LVDS数据开始上注", 3: "CAN初始化", 4: "LVDS初始化", 5: "AD9361重新校准", 6: "GPS初始化" } response_msg = responses.get(cmd_type, "未知指令") print(f"执行调试指令: {response_msg}") # 返回通知报文确认 return self.build_packet(MSG_NOTIFICATION, struct.pack('B', 0)) # 类型0: VDES协议开始执行 def handle_client(self, client_socket): """处理客户端请求""" while self.running: try: data = client_socket.recv(32768) if not data: break msg_type, content = self.parse_packet(data) if msg_type is None: continue # 根据报文类型处理 if msg_type == MSG_DEBUG: response = self.handle_debug_command(content) elif msg_type == MSG_AD9361_CTRL: response = self.build_packet(MSG_NOTIFICATION, struct.pack('B', 7)) # AD9361状态更新 else: response = self.build_packet(MSG_NOTIFICATION, struct.pack('B', 3)) # 通用确认 client_socket.send(response) except Exception as e: print(f"处理错误: {e}") break def send_periodic_messages(self, client_socket): """定时发送状态监控和GPS报文""" while self.running: try: # 每秒发送GPS数据(类型7) gps_data = self.generate_gps_data() client_socket.send(self.build_packet(MSG_GPS, gps_data)) # 每秒发送状态监控(类型8) status_data = bytes([random.randint(0, 100) for _ in range(50)]) # 随机状态数据 client_socket.send(self.build_packet(MSG_STATUS_MONITOR, status_data)) # 每5秒发送解调数据(类型12) if int(time.time()) % 5 == 0: demod_data = self.generate_demod_data() client_socket.send(self.build_packet(MSG_DEMOD_DATA, demod_data)) time.sleep(1) except Exception as e: print(f"发送错误: {e}") break def generate_gps_data(self): """生成长江入海口附近的GPS数据""" # 在长江入海口附近随机生成位置 lat = YANGTZE_DELTA_CENTER[0] + random.uniform(-DELTA_RANGE, DELTA_RANGE) lon = YANGTZE_DELTA_CENTER[1] + random.uniform(-DELTA_RANGE, DELTA_RANGE) # 转换为度分格式*10000000 lat_int = int(lat * 10000000) lon_int = int(lon * 10000000) # 其他GPS数据字段 utc_time = int((datetime.utcnow() - datetime(1980, 1, 6)).total_seconds()) altitude = random.randint(-10, 50) # 海拔高度(米) used_satellites = random.randint(5, 12) gps_satellites = random.randint(4, 8) beidou_satellites = random.randint(4, 8) gps_status = random.randint(1, 4) # GPS状态 pos_mode = random.randint(1, 3) # 定位模式 hdop = random.randint(10, 50) # 水平精度因子 speed = random.randint(0, 2000) # 运动速度 (0.01节) course = random.randint(0, 35900) # 运动方向 (度*100) # 打包GPS数据 return struct.pack('>Q', utc_time) + \ struct.pack('>i', lon_int) + \ struct.pack('>i', lat_int) + \ struct.pack('>i', altitude) + \ struct.pack('>H', used_satellites) + \ struct.pack('>H', gps_satellites) + \ struct.pack('>H', beidou_satellites) + \ struct.pack('B', gps_status) + \ struct.pack('B', pos_mode) + \ struct.pack('>I', hdop) + \ struct.pack('>I', speed) + \ struct.pack('>I', course) def generate_demod_data(self): """生成解调数据报文(类型12)""" demodulator_id = random.randint(0, 5) msg_type = 12 # 固定值12 satellite_id = random.randint(1, 255) demod_data = struct.pack('B', msg_type) + struct.pack('B', satellite_id) + struct.pack('B', demodulator_id) # 根据解调器编号生成数据 if VDES_DEMOD_RANGE[0] <= demodulator_id <= VDES_DEMOD_RANGE[1]: # VDES解调器 (0-3): 使用M.2092-1 Annex5格式 msg_id = random.choice([10, 11, 12, 20, 21]) content = struct.pack('B', msg_id) + os.urandom(20) # 随机生成20字节数据 else: # AIS解调器 (4-5): 使用M.1371-5 Annex8 Message1格式 content = self.generate_ais_message1() return demod_data + content def generate_ais_message1(self): """生成AIS Message 1(位置报告)""" # 在长江入海口附近随机生成位置 lat = YANGTZE_DELTA_CENTER[0] + random.uniform(-DELTA_RANGE, DELTA_RANGE) lon = YANGTZE_DELTA_CENTER[1] + random.uniform(-DELTA_RANGE, DELTA_RANGE) # 转换为1/10000分钟格式 lat_min = int(lat * 60 * 10000) lon_min = int(lon * 60 * 10000) # 其他AIS字段 message_id = 1 repeat_indicator = 0 navigational_status = random.randint(0, 15) # 航行状态 rate_of_turn = random.randint(-128, 127) # 转向率 speed_over_ground = random.randint(0, 1022) # 对地航速 (0.1节) position_accuracy = 1 # 高精度 course_over_ground = random.randint(0, 3599) # 对地航向 (0.1度) true_heading = random.randint(0, 359) # 真航向 timestamp = random.randint(0, 59) # UTC秒 maneuver_indicator = random.randint(0, 1) # 操纵指示器 spare = 0 raim_flag = 0 # RAIM标志 # 打包AIS Message 1 return struct.pack('>B', message_id) + \ struct.pack('>B', (repeat_indicator << 6) | (navigational_status << 2) | (rate_of_turn >> 6)) + \ struct.pack('>B', (rate_of_turn & 0x3F) << 2) | (speed_over_ground >> 8) + \ struct.pack('>B', speed_over_ground & 0xFF) + \ struct.pack('>B', (position_accuracy << 7) | (lon_min >> 25)) + \ struct.pack('>B', (lon_min >> 17) & 0xFF) + \ struct.pack('>B', (lon_min >> 9) & 0xFF) + \ struct.pack('>B', (lon_min >> 1) & 0xFF) + \ struct.pack('>B', ((lon_min & 0x1) << 7) | (lat_min >> 20)) + \ struct.pack('>B', (lat_min >> 12) & 0xFF) + \ struct.pack('>B', (lat_min >> 4) & 0xFF) + \ struct.pack('>B', ((lat_min & 0xF) << 4) | (course_over_ground >> 8)) + \ struct.pack('>B', course_over_ground & 0xFF) + \ struct.pack('>H', true_heading) + \ struct.pack('>B', timestamp) + \ struct.pack('>B', (maneuver_indicator << 2) | spare) + \ struct.pack('>B', raim_flag) if __name__ == "__main__": server = VDESServer() try: server.start() except PermissionError: print("错误:需要管理员权限绑定到端口10") except KeyboardInterrupt: server.stop()