全球主机交流论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

CeraNetworks网络延迟测速工具IP归属甄别会员请立即修改密码
123
返回列表 发新帖
楼主: yaoruisheng

为了同步时间,我绞尽脑汁写了个bash脚本,很粗糙,

[复制链接]
 楼主| 发表于 2024-3-6 11:55:40 | 显示全部楼层
Sam_Edward 发表于 2024-3-6 08:27
没玩过盒子,不明白为什么要同步,另外以下是chatgpt 优化过的代码,你自己看对不对,不知道你要用于做什么 ...

但是这个脚本有问题,shell变量无法存储nul
发表于 2024-3-6 12:12:42 | 显示全部楼层
yaoruisheng 发表于 2024-3-6 11:55
但是这个脚本有问题,shell变量无法存储nul

您的脚本尝试通过Bash脚本与NTP服务器进行通信,从而同步时间。然而,确实如您所说,Bash中的变量处理对于包含null(\0)的数据有局限性,这会影响从NTP响应中正确提取时间戳。

在Bash中处理包含null字符的数据时,常见的问题是null字符会导致字符串的提前终止,因为Bash和许多其他工具都是用C语言编写的,而C语言中的字符串是以null字符为结束标志的。这意味着,当Bash遇到null字符时,它会认为字符串到此为止。

您的脚本中,尝试通过read -n 48 response来读取NTP响应是一个很好的尝试,但是处理二进制数据(尤其是包含null字符的)时,read命令和Bash变量都可能无**确处理。

一个更稳妥的解决方案是使用像xxd(或其他能处理二进制数据的工具)将二进制数据转换成十六进制字符串,然后再进行解析。虽然这种方法可能需要更复杂的处理逻辑,但它能避免处理含有null字符的字符串时遇到的问题。

举个例子,您可以使用下面的方法来安全地处理NTP响应:

    使用dd或cat命令读取NTP响应,并立即通过管道传递给xxd或类似工具转换为十六进制。
    解析十六进制数据以提取时间戳。

这里是一个简化的例子,演示如何使用xxd来处理响应:
  1. # 使用`dd`命令从NTP响应中读取48个字节的数据
  2. response=$(dd bs=48 count=1 <&5 2>/dev/null | xxd -p -c 48)

  3. # 假设我们得到的十六进制数据存储在$response中,然后进行解析
  4. # 这里仅作为展示,实际解析逻辑可能需要根据NTP协议详细说明进行调整
复制代码


完整修改后的代码:
  1. #!/bin/bash

  2. # NTP服务器地址和端口
  3. NTP_SERVER="ntp.tencent.com"
  4. NTP_PORT=123

  5. # 创建UDP连接
  6. exec 5<>/dev/udp/${NTP_SERVER}/${NTP_PORT}

  7. # 发送NTP请求包 (根据NTP协议格式)
  8. printf '\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' >&5

  9. # 使用dd命令从UDP连接中读取NTP响应,并通过xxd转换为十六进制
  10. response_hex=$(dd bs=48 count=1 <&5 2>/dev/null | xxd -p -u -c 48)

  11. # 检查是否收到响应
  12. if [ -z "$response_hex" ]; then
  13.   echo "从NTP服务器获取时间失败。"
  14.   exit 1
  15. fi

  16. # 将十六进制响应转换为二进制,并提取时间戳(从第40个字节开始的4个字节)
  17. time_hex=${response_hex:40*2:8}
  18. # 使用awk将十六进制时间戳转换为十进制
  19. time_dec=$(echo $time_hex | awk '{print strtonum("0x"$0)}')

  20. # NTP时间戳起始于1900年,Unix时间戳起始于1970年
  21. # 需要从NTP时间戳减去差值(2208988800秒)
  22. unix_time=$((time_dec - 2208988800))

  23. # 设置系统时间
  24. if date -s "@$unix_time" > /dev/null 2>&1; then
  25.   echo "时间已成功同步至: $(date)"
  26. else
  27.   echo "设置系统时间失败。"
  28. fi

  29. # 关闭UDP连接
  30. exec 5<&-
  31. exec 5>&-
复制代码

请注意,根据您的系统配置和权限,直接设置系统时间可能需要管理员权限。此外,处理十六进制数据和时间戳转换时,请确保按照NTP协议的详细说明进行调整。
发表于 2024-3-6 12:17:22 | 显示全部楼层
curl一下date就行了,两行的事情,还整什么ntp莫名其妙
发表于 2024-3-6 12:52:54 | 显示全部楼层
都是用ntp客户端 没想到同步时间还能这样搞
 楼主| 发表于 2024-3-6 14:12:54 | 显示全部楼层
随便起个名字 发表于 2024-3-6 12:52
都是用ntp客户端 没想到同步时间还能这样搞

apt安装个客户端,需要一堆依赖。太占用空间了。
发表于 2024-3-7 08:27:34 | 显示全部楼层
yaoruisheng 发表于 2024-3-6 08:58
这个也是可以的,不过google国内无法访问就是了。

你自己换成taobao.com就可以了
发表于 2024-3-7 08:38:02 | 显示全部楼层
本帖最后由 aru 于 2024-3-7 08:40 编辑
yaoruisheng 发表于 2024-3-6 08:57
需要安装一堆依赖。


如果你的机器用了systemd,那我推荐 systemd-timesyncd ,非常小巧
apt update && apt -y install systemd-timesyncd &&  systemctl enable systemd-timesyncd && systemctl start systemd-timesyncd

Debian 9、Ubuntu 16.04 开始就用了systemd
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|全球主机交流论坛

GMT+8, 2024-5-11 19:19 , Processed in 0.102806 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表