美文网首页iOS开发之常见问题
iOS关于时间的处理(二)—— 客户端和服务器的时间同步问题解决

iOS关于时间的处理(二)—— 客户端和服务器的时间同步问题解决

作者: 刀客传奇 | 来源:发表于2017-08-30 16:44 被阅读40次

版本记录

版本号 时间
V1.0 2017.08.30

前言

很多时候我们是需要服务器和客户端时间的同步的,比如说活动的倒计时,抢购等。而且做好时间同步还有一个优势就是防止客户端用户本地时间有误差导致问题。感兴趣的可以看上面几篇。
1. iOS关于时间的处理(一)—— 有关时间的基本知识

功能要求

要做到客户端和服务器端时间同步。


功能实现

1. 问题分析

我们可以按照下面的思路进行

  • 获取服务器某一时刻 A 的时间;
  • 记录获取到时刻 A 时的本地时间 B
  • 需要用到时间时,获取当前本地时间 C,当 C - B 作为时间间隔 D,则 A + D 则是当前服务器的时间。

这里要准确做到客户端时间和服务器时间一致,很关键的问题就是B和C不能受系统时间的影响。要解决这个问题,要依靠iOS的两个接口。

  • 获取设备当前时间 Now,该值受系统时间影响,用户如果修改时间,值也会随着变化。
  • 获取设备上次重启的时间 BootTime,该值受系统时间影响,用户如果修改时间,值也会随着变化。

由上面 iOS 提供的两个接口,我们可以获取本地时间 BC:设备自上次重启后运行的时间(BootTime - Now),该值与系统时间无关。利用时间差这一概念就很好的解决了时间受系统影响的这个问题了。

2. 代码实现

  • 获取当前 Unix Time
static func now() -> Int {
        var now =  timeval()
        var tz = timezone()
        gettimeofday(&now, &tz)
        return now.tv_sec
 }
  • 获取设备上次重启的 Unix Time
func boottime() -> Int {

        var mid = [CTL_KERN, KERN_BOOTTIME]
        var boottime = timeval()
        var size = MemoryLayout.size(ofValue: boottime)

        if sysctl(&mid, 2, &boottime, &size, nil, 0) != -1 {
            return boottime.tv_sec
        }
        return 0
 }
  • 进行时间校准
// 接口获取服务器时间处理
let serverTime = xxx                        // 获取到的服务器时间
let runTime0 = now() - boottime()            // 当前设备运行时间

// 需要用到时间时
let runTime1 = now() - boottime()            // 当前时刻设备运行时间
let currentTime = serverTime + runTime1     // 当前服务器时间

题外话

关于时间的使用,还有另外一个用途就是时间的测量,在做方法执行时间的benchmark的时候,我们获取时间的方法要满足两个要求,一是精读要高,而是API本身几乎不耗CPU时间。一般认为UI线程只要阻塞16.7ms就会出现掉帧现象,第一篇中提到的几种时间的方法,其中NSDate调用返回的精读是0.000004 S,也就是4微秒,CACurrentMediaTime()返回的精读也在微秒级别,精读上都符合要求。

下面看一下别人提供的示例代码

int testCount = 10000;
double avgCost = 0;
for (int i = 0; i < testCount; i ++) {
    NSDate* begin = [NSDate date];
    NSLog(@"a meaningless log");
    avgCost += -[begin timeIntervalSinceNow];
}
NSLog(@"benchmark with NSDate: %f", avgCost/testCount);

avgCost = 0;
for (int i = 0; i < testCount; i ++) {
    double startTime = CACurrentMediaTime();
    NSLog(@"a meaningless log");
    double endTime = CACurrentMediaTime();
    avgCost += (endTime - startTime);
}
NSLog(@"benchmark with CACurrentMediaTime: %f", avgCost/testCount);

下面看输出结果

benchmark with NSDate: 0.000046
benchmark with CACurrentMediaTime: 0.000037

可以看出CACurrentMediaTimeNSDate代码本身的损耗差异在几微秒,而我们做UI性能优化的维度在毫秒级别,几个微秒的差异完全不会影响我们最后的判断结果。所以使用NSDate做benchmark完全是可行的。

参考文章

1. iOS 客户端与服务端做时间同步
2. iOS关于时间的处理

相关文章

  • iOS 关于时间的处理

    iOS关于时间的处理(一)—— 有关时间的基本知识iOS关于时间的处理(二)—— 客户端和服务器的时间同步问题解决

  • iOS关于时间的处理(二)—— 客户端和服务器的时间同步问题解决

    版本记录 前言 很多时候我们是需要服务器和客户端时间的同步的,比如说活动的倒计时,抢购等。而且做好时间同步还有一个...

  • Lua处理时区和夏令时问题

    一般游戏都会在登录时把服务器时间戳同步到客户端,然后定时同步,保证客户端与服务器时间戳一致,在一些涉及时间的逻辑里...

  • 服务器时间同步、修改docker时区

    《服务器时间同步、修改docker时区》 一、服务器时间同步 安装ntp服务 时间同步命令 修改时区 二、linu...

  • Ajax全接触(一)基础理论

    什么是同步? 客户端要发起请求,服务器端要去处理,而且去响应,这时候客户端完全是等待,等待服务器端的处理和响应,当...

  • NTP集群服务器搭建

    NTP服务器 10.11.52 服务器需要能联网,从互联网的时间中心中同步时间。 NTP客户端 10.11.6.5...

  • iOS关于时间的处理

    转自:iOS关于时间的处理 做App避免不了要和时间打交道,关于时间的处理,里面有不少门道,远不是一行API调用,...

  • iOS关于时间的处理

    做App避免不了要和时间打交道,关于时间的处理,里面有不少门道,远不是一行API调用,获取当前系统时间这么简单。我...

  • NTP时间服务器同步小结

    在SecBox上测试,使用ntpd,将本地作为客户端,和网络时间服务器进行时间同步。 修改点: 1、在etc/re...

  • iOS 同步服务器时间

    在项目中遇到需要同步服务器时间的需求,解决方案如下。 1.App启动后获取服务器当前时间时间戳ServerTime...

网友评论

  • zero_zql:假如获取完A的时候,这时用户去设置刻意更改时间,也会产生误差
    刀客传奇:@zero_zql 等你知道了,欢迎一起探讨
    zero_zql:@刀客传奇 我也不太清楚,没有实践过
    刀客传奇:@zero_zql 请教你怎么做的 说下

本文标题:iOS关于时间的处理(二)—— 客户端和服务器的时间同步问题解决

本文链接:https://www.haomeiwen.com/subject/hwutjxtx.html