【问题标题】:Time-server time type issue时间服务器时间类型问题
【发布时间】:2014-08-17 14:13:00
【问题描述】:

所以我在 Linux 上用 C 语言编写了一个时间服务器-客户端应用程序,它应该将当前的 unix 时间戳发送到客户端。

一切正常,但有人告诉我 time_t 可能并不总是相同的大小和字节顺序。我如何确保我发送的时间客户总是能理解?

目前我只是这样做

time_t now = htonl(time(0));

然后发送。

我在 google 和 stackoverflow 上进行了搜索,但似乎其他人只是发送了 ctime() 或 strftime() 生成的时间字符串。

提前致谢!

【问题讨论】:

    标签: c linux sockets networking time-t


    【解决方案1】:

    Ìn 一般发送二进制数据很容易出错,因为发送方和接收方对其解释方式不同。

    特别是对于time_t,甚至不清楚会涉及多少位,它可能是 32 或 64 甚至更复杂的东西,因为 time_t 甚至可能被实现为 struct。

    在您使用 htonl() 的特殊情况下,假定为 32 位,因为 htonl() 采用 32 位值。

    因此,故障安全解决方案确实是发送系统时间的文本表示。

    以编程方式可能如下所示:

    char st[64] = "";
    
    {
      struct * tm = gmtime(time(NULL));
      if (NULL == tm)
      {
        fprintf(stderr, "gmtime() failed\n");
      }
      {
        if(0 == strftime(st, sizeof(st), "%s", tm)) /* Prints the text representaiotn of the seconds since Epoch into st. */
        {
          fprintf(stderr, "strftime() failed\n");
        }
      }
    }
    

    要反转此操作,您可以使用strptime():

    char st[64] = "123456789123";
    time_t t;
    memset(&t, 0, sizeof(t));
    {
      struct tm = {0};
      char p = strptime(t, "%s", &tm);
      if (NULL == p || p != (t + strlen(t)))
      {
        fprintf(stderr, "strptime() failed\n");
      }
      else
      {
        t = mktime(&tm);
      }
    }
    

    使用strptime() 和strftime() 的好处是,您可以轻松更改传输中的日期/时间格式,只需在调用这两个函数时修改指定的格式。

    将"%s" 更改为"%Y-%m-%d %H:%M:%S" 将像"2014-05-20 13:14:15" 一样转移时间。


    但是,如果您真的想以二进制格式发送自 Epoch 以来的秒数并保持故障安全和便携,您需要注意三件事:

    1. 以便携式方式获取自 Epoch 以来的秒数。
    2. 选择一个足够大的整数类型。
    3. 将此“大”值转换为网络字节顺序。

    一种可能的方法是:

    #include <time.h>
    #include <inttypes.h> /* For uint64_t, as 64bit should do to represent the seconds since Epoch for the next few years. */
    
    ...
    
    time_t t_epochbegin;
    memset(&t_epochbegin, 0, sizeof(t_epochbegin);
    uint64_t t_host = (uint64_t) difftime(time(NULL), t_epochbegin); /* Get the seconds since Epoch without relying on time_t being an integer. */
    uint64_t t_network = htonll(t_host); /* Convert to network byte order. */
    

    关于如何实现非标准htonll(),请参阅此问题的各种答案:Big Endian and Little Endian support for byte ordering


    以上示例中的所有代码都假定运行代码的系统提供了一个计时器,并且尽管对 time() 的调用不会失败。

    【讨论】:

    • 非常感谢!这比我要求的要多,如果可以的话,我现在就给你投票! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2011-10-24
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    相关资源
    最近更新 更多