`
daimojingdeyu
  • 浏览: 271622 次
  • 性别: Icon_minigender_1
  • 来自: 山东
社区版块
存档分类
最新评论

Java校正电脑时间(java 时间同步)

    博客分类:
  • Java
阅读更多
写这个程序的原因:
家里的电脑老了,主板电池没有电了,开机老是提示有错误,按了F1才能继续。无奈买了一块主板电池。换上之后不用点击F1了,但是主板的时间还是走不稳当,关机后时钟明显是有点慢,开机后系统时间老是慢半拍。
上网找软件呗,嘿嘿。先找到一个iTimeSync程序,先说一个不爽的地方,点击校正时,不知道程序要连到什么地方去,反正出一坨连接信息,不爽。但有一个功能刚刚好是我想要的“随Windows启动,校正,退出”,O(∩_∩)O哈哈~,经过使用发现不好用,因为系统上网使用的ADSL拨号上网的,开机后软件启动了,但是拨号上网还是有一定的延时的,基本上每次都是iTimeSync启动了,进行校正时网络还没有连上,程序是出错退出的。虽然有一个每隔几个小时的自动校正的功能,可是偶不想让这个程序老是在后台运行,因为电脑开机的时候时间运行不会有太多的差异。
换了一个InternetTime,这个程序虽然简洁,“随Windows启动,校正,退出”功能依然是启动后马上校正,这样还是会失败,程序还会弹出一个什么Socket连接异常的对话框。更加不好。
总结一下这两个程序不能满足俺的需求的原因:ADSL拨号连接有一定的时延,程序在进行校正前没有对电脑是不是上网了进行判断,没有网络连接的情况下就进行了时间校正。

自己制造一个:
没有枪没有炮,我们自己造。首先看几个时间相关的协议:
1、RFC 867 :Daytime Protocol 服务器监听端口13,以固定字符串的格式将时间返回给客户端,中国授时中心的服务器貌似使用的这种协议。
2、RFC 868 :Time Protocol 服务器监听37端口,以一个32bit的整数返回当前距离1900年1月1日0点0分0秒的秒数。
3、RFC 1305:Network Time Protocol 这个协议有点复杂,没有仔细研究。
4、RFC 2030:Simple Network Time Protocol 与RFC1305相比做了一下简化。

这里选择一个最简单的 RFC868 ^_^。
先看下协议的具体内容:
When used via TCP the time service works as follows:

   S: Listen on port 37 (45 octal).

   U: Connect to port 37.

   S: Send the time as a 32 bit binary number.

   U: Receive the time.

   U: Close the connection.

   S: Close the connection.
从上面可以看出,客户端需要实现下面的功能:
1、和服务器的37端口建立一个TCP连接。
2、解析服务器返回的32bit的整数秒为一个具体的时间。解析过程也比较的简单,需要注意的就是网络字节序使用的是高位在前的方式(网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式)。

程序的实现:
1、判断计算机是否在线,通过ping www.hao123.com进行判断,没有想到更好的办法,先凑合着用了。有更好方法的同学欢迎提建议。如果ping 通了表示电脑已经在线,可以进行步骤2了;没有ping通的话,就休眠2分钟,然后重复1.
2、从实现了RFC868协议的时间服务器获取网络时间,这里找到了三个服务器"time-a.nist.gov", "time-nw.nist.gov", "time.nist.gov".对32bit的解析知道字节序就好了。
最近发现上面的服务器不好使了,可以到下面的地址找些能用的http://tf.nist.gov/tf-cgi/servers.cgi
3、调用本地本机的date、time两个Dos命令修改系统日期和时间。
4、程序退出

因为Java没有相关的接口只能牺牲一下平台无关性了,只能在XP系统下使用。

使用Runtime和process两个类时需要注意:1、waitFor方法的使用,这个方法会一直阻塞直到外部命令执行结束,然后返回外部命令执行的结果。当你在一个Process上调用waitFor方法时,当前线程是阻塞的,如果外部命令无法执行结束,那么你的线程就会一直阻塞下去,这种意外会影响我们程序的执行。所以在调用date或是time命令是需要使用"cmd /c date 参数"的形式,表示执行完命令后退出Dos窗口,因为默认Dos窗口是不会自动退出的,这样就会导致前面提到的线程阻塞。
2、本地的系统对标准输入和输出所提供的缓冲池有效,所以错误的对标准输出快速的写入和从标准输入快速的读入都有可能造成子进程的锁,甚至死锁。为了处理好外部命令大量输出的情况,你要确保你的程序处理好外部命令所需要的输入或者输出。也就是说如果你调用的本地程序的输出过多,或者是输出过快,可能造成死锁。还好这个时间程序调用的两个命令不涉及大量输出的情况。如果程序涉及了大量输出,请参考下面的代码:
Process proc = rt.exec("javac");
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
int exitVal = proc.waitFor();

附件中有对应的Java程序实现
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics