Files
VDES_Backend/报文模拟解析/develop/vdes_send.py
2026-07-13 15:37:05 +08:00

214 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import struct
import socket
import time
import random
import math
class Ship:
def __init__(self, mmsi, lat, lon, heading, speed=280.24):
self.mmsi = mmsi
self.lat = lat
self.lon = lon
self.heading = heading
self.speed = speed # 加速100倍用于演示
def update_position(self):
"""更新船只位置"""
# 速度转换
speed_kmh = self.speed * 1.852
speed_kmps = speed_kmh / 3600
distance_km = speed_kmps * 1
# 航向转弧度
heading_rad = math.radians(self.heading)
# 计算经纬度变化
delta_lat = distance_km / 111.0 * math.cos(heading_rad)
delta_lon = distance_km / (111.0 * math.cos(math.radians(self.lat))) * math.sin(heading_rad)
# 更新位置
self.lat += delta_lat
self.lon += delta_lon
return self.lon, self.lat
class OwnShip(Ship):
def __init__(self, lat, lon, heading, speed=280.24):
super().__init__(336295999, lat, lon, heading, speed) # 使用固定MMSI作为本船
def get_position(self):
"""获取本船位置并更新"""
return self.update_position()
class VDESPacketCreator:
@staticmethod
def create_tcp_packet(packet_type, content):
"""创建符合VDES TCP协议的报文"""
header = b'####'
type_field = struct.pack('>I', packet_type)
length_field = struct.pack('>I', len(content))
return header + type_field + length_field + content
@classmethod
def create_gps_packet(cls, own_ship):
"""创建GPS解析数据报文(类型7)的内容"""
lon, lat = own_ship.get_position()
# 打包GPS数据
return struct.pack(
'>QiiiHHHBBIII',
1680000000, # UTC时间
int(lon * 10000000), # 经度
int(lat * 10000000), # 纬度
50, # 海拔高度
10, # 定位使用的卫星数
8, # GPS卫星数
7, # 北斗卫星数
1, # GPS状态
3, # 定位模式
2550, # 水平精度因子
1024, # 运动速度
own_ship.heading # 运动方向
)
@classmethod
def create_ais_info_packet(cls, ship):
"""创建解调信息报文(类型12)的内容"""
demod_content = cls.encode_demod_fields(ship)
# 打包解调信息
message_type = 12
satellite_id = 1
demodulator_id = 0
demod_slot = 1234
receive_delay = 5678
snr = 25.75
# 处理信噪比
snr_int = int(snr)
snr_frac = int((snr - snr_int) * 100)
snr_packed = (snr_int & 0xFF) << 8 | (snr_frac & 0xFF)
header = struct.pack(
'>BBBHHH',
message_type,
satellite_id,
demodulator_id,
demod_slot,
receive_delay,
snr_packed
)
return header + demod_content
@staticmethod
def encode_demod_fields(ship):
"""编码解调信息字段"""
lon, lat = ship.update_position()
# 准备数据
message_id = 1
repeat_indicator = 0
user_id = ship.mmsi
navigation_status = 8
rot = -128
sog = 102
position_accuracy = 1
cog = ship.heading
true_heading = ship.heading
timestamp = 30
special_maneuver = 0
spare = 0
raim_flag = 0
comm_state = 0
# 转换为协议要求的格式
longitude_min = int(lon * 60 * 10000)
latitude_min = int(lat * 60 * 10000)
# 构建二进制位
bits = [
format(message_id, '06b'),
format(repeat_indicator, '02b'),
format(user_id, '030b'),
format(navigation_status, '04b'),
format(rot & 0xFF, '08b'),
format(min(sog, 1023), '010b'),
str(position_accuracy),
format(longitude_min & 0x0FFFFFFF, '028b'),
format(latitude_min & 0x07FFFFFF, '027b'),
format(min(cog, 3600), '012b'),
format(min(true_heading, 511), '09b'),
format(min(timestamp, 63), '06b'),
format(special_maneuver, '02b'),
format(spare, '03b'),
str(raim_flag),
format(comm_state, '019b')
]
# 合并所有位并转换为字节
bit_string = ''.join(bits)
binary_int = int(bit_string, 2)
byte_length = (len(bit_string) + 7) // 8
return binary_int.to_bytes(byte_length, 'big')
class VDEServer:
def __init__(self, host='127.0.0.1', port=10):
self.host = host
self.port = port
self.own_ship = OwnShip(31.23, 123.87, 90)
self.ships = self.create_ships(30)
@staticmethod
def create_ships(count):
"""创建指定数量的船只"""
return [
Ship(
mmsi=336295939 + i,
lat=round(random.uniform(30.0, 34.0), 6),
lon=round(random.uniform(123.5, 126.0), 6),
heading=random.randint(0, 359)
) for i in range(count)
]
def send_data_continuously(self):
"""启动Socket服务端并持续发送数据"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((self.host, self.port))
s.listen(1)
print(f"Socket服务端已启动监听 {self.host}:{self.port}")
while True:
try:
conn, addr = s.accept()
print(f"客户端连接来自: {addr}")
while True:
try:
# 随机选择一艘船发送AIS报文
selected_ship = random.choice(self.ships)
ais_data = VDESPacketCreator.create_ais_info_packet(selected_ship)
ais_packet = VDESPacketCreator.create_tcp_packet(12, ais_data)
conn.sendall(ais_packet)
# 发送本船GPS报文
gps_content = VDESPacketCreator.create_gps_packet(self.own_ship)
gps_packet = VDESPacketCreator.create_tcp_packet(7, gps_content)
conn.sendall(gps_packet)
time.sleep(0.5)
except (ConnectionResetError, BrokenPipeError):
print("客户端断开连接")
break
except KeyboardInterrupt:
print("\n服务端已停止")
break
except Exception as e:
print(f"服务端错误: {e}")
break
if __name__ == "__main__":
server = VDEServer()
server.send_data_continuously()