一、问题背景
多个传感器分布在不同的主机上,且主机之间用局域网连接,但都与外网隔绝;在此情况下需要统一主机时间,否则传感器数据难以同步。
两台电脑需要时间同步:
- 电脑A :Windows系统(10.*..102),作为时间戳发送方
- 电脑B :Linux系统(10.*..101),作为时间戳接收方
内网环境,无法访问外网NTP服务器。
二、思考与排查过程
1. 最初尝试:NTP服务器方案
尝试将Linux配置为NTP服务器,Windows作为客户端同步。
Linux端配置:
bash
# 安装ntp
sudo apt install ntp -y
# 配置/etc/ntp.conf
sudo tee /etc/ntp.conf <<EOF
server 127.127.1.0
fudge 127.127.1.0 stratum 10
restrict 10.111.34.0 mask 255.255.255.0 nomodify notrap
restrict 127.0.0.1
restrict ::1
restrict default ignore
driftfile /var/lib/ntp/drift
EOF
sudo systemctl restart ntp
Windows端同步:
cmd
w32tm /config /manualpeerlist:"10.111.34.101" /syncfromflags:manual /reliable:yes /update
net stop w32time && net start w32time
w32tm /resync
2. 问题发现:网络通但同步失败
通过抓包发现网络是通的,但Windows不认Linux的NTP响应:
bash
# Linux上抓包
sudo tcpdump -i any udp port 123 -vv
抓包结果显示Linux有回复,但包含[bad udp cksum],Windows可能因此丢弃数据包。
3. 方案转向:自定义Python脚本
既然标准NTP协议不行,改用简单的UDP自定义协议,Windows发送时间戳,Linux接收并设置时间。
三、最终解决方案
步骤1:Windows发送端脚本
创建 time_sender.py:
python
import socket
import struct
import time
def send_timestamp():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
linux_ip = "10.111.34.101"
port = 12345
while True:
timestamp = time.time()
data = struct.pack('d', timestamp)
sock.sendto(data, (linux_ip, port))
print(f"发送: {timestamp:.3f} -> {time.ctime(timestamp)}")
time.sleep(1)
if __name__ == "__main__":
send_timestamp()
步骤2:Linux接收并设置时间脚本
创建 time_receiver.py:
python
import socket
import struct
import time
import os
def set_system_time(timestamp):
date_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
os.system(f"sudo date -s '{date_str}'")
os.system("sudo hwclock --systohc 2>/dev/null") # 同步硬件时钟
print(f"时间已设置为: {date_str}")
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 12345))
print("等待接收时间戳...")
last_time = 0
while True:
data, addr = sock.recvfrom(1024)
win_time = struct.unpack('d', data)[0]
print(f"\n收到来自 {addr[0]}:{win_time:.3f}")
# 只在时间变化较大时设置(避免频繁设置)
if abs(win_time - last_time) > 0.5:
set_system_time(win_time)
last_time = win_time
步骤3:Linux监控脚本(查看时间差)
创建 time_check.py:
python
import socket
import struct
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 12345))
print("监控时间差...")
while True:
data, addr = sock.recvfrom(1024)
win_time = struct.unpack('d', data)[0]
local_time = time.time()
diff = win_time - local_time
print(f"Windows: {win_time:.3f} | Linux: {local_time:.3f} | 差值: {diff:+.3f}秒")
四、运行流程
1. 在Linux上启动接收端(需要root权限)
bash
sudo python3 time_receiver.py
2. 在Linux上另开终端启动监控(可选)
bash
python3 time_check.py
3. 在Windows上启动发送端
cmd
python time_sender.py
五、关键命令总结
| 用途 | 命令 |
|---|---|
| Linux设置时间 | sudo date -s "2026-03-12 20:30:00" |
| Linux查看时间 | date |
| Windows设置时间 | date 2026-03-12 和 time 20:30:00 |
| 抓包诊断 | sudo tcpdump -i any udp port 123 -vv |
| NTP服务状态 | ntpq -p |
| Windows时间服务 | w32tm /query /status |
六、方案优势
- 简单可靠:绕过复杂的NTP协议,直接用UDP传输时间戳
- 完全可控:可以监控时间差,确保同步精度
- 内网可用:不依赖外网,适合封闭环境
- 跨平台:Python脚本可在Windows/Linux运行
这个方案最终成功解决了内网环境下Windows和Linux系统间的时间同步问题,实现了时间戳的对齐需求。