- 论坛徽章:
- 0
|
本帖最后由 iamlimeng 于 2013-05-08 15:59 编辑
最近写个小程序,需要获得准确NTP时间,不依赖系统时间。我把其中的部分提出来,做成了一个可以用来同步本机时间的小桌面应用。因为Windows本身可以设置自动与授时服务器同步时间,从功能上看这个程序是多余的,但本版Perl写的桌面应用很少,尤其是GUI程序,更少,在此共享一下,希望跟大家多多交流,共同进步。
代码写得不好,大家将就参考啊。另外,对授时服务器的工作原理了解很少,如有更好的方式实现,希望前辈们多多指点。- #!/usr/bin/perl
- use strict;
- #use warnings;
- use Win32::GUI qw( MB_ICONINFORMATION MB_OK );
- use POSIX qw/ _exit /;
- use threads;
- use threads::shared;
- use Thread::Queue;
- use Net::Time qw(inet_time);
- my $my_name = "NTP Time Synchronizer V2.0";
- my $about= <<EOF;
- /`\\ /`\\
- (/\\ V /\\) $my_name
- /6 6\\ -- Written by Limeng o_*, May 8, 2013
- >{= Y =}<
- /'-^-'\\ All Rights Reserved 2010-3000 ChangSha
- (_)""-(_) Homepage: http://limeng.class22.net
- E-mail: iamlimeng\@163.com
- BlueIdea!
- 本程序用于从国际授时服务器获得时间,并校准系统时间!
- EOF
- my @time_sever = (
- 'time-a.nist.gov',
- 'time-b.nist.gov',
- 'utcnist.colorado.edu',
- 'time-nw.nist.gov',
- 'nist1-dc.glassey.com',
- 'nist1-ny.glassey.com',
- 'nist1-sj.glassey.com',
- 'time.nist.gov',
- 'salmon.maths.tcd.ie',
- 'nist1.symmetricom.com',
- '210.72.145.44',
- '133.100.11.8',
- 'time-a.timefreq.bldrdoc.gov',
- 'time-b.timefreq.bldrdoc.gov',
- 'time-c.timefreq.bldrdoc.gov',
- 'nist1.aol-ca.truetime.com',
- 'nist1.aol-va.truetime.com',
- );
- my $data_queue = new Thread::Queue;
- my $result_queue = new Thread::Queue;
- my $MAX_THREADS = 5;
- my $processing_count :shared = 0;
- my %checked :shared = ();
- my $net_time :shared = '';
- my $thread;
- my $w_m = 360;
- my $h_m = 240;
- my $icon = new Win32::GUI::Icon("icon.ico");
- my $wm_class = new Win32::GUI::Class(
- -name => 'Limeng',
- -icon => $icon,
- );
- my $font1 = Win32::GUI::Font->new(
- -name => "Arial",
- -size => 14,
- );
- my $font2 = Win32::GUI::Font->new(
- -name => "宋体",
- -size => 11,
- );
- my $main = Win32::GUI::Window->new(
- -title => " $my_name",
- -class => $wm_class,
- -size => [$w_m,$h_m],
- -maximizebox => 0,
- -dialogui => 1,
- -noflicker => 1,
- -resizable => 0,
- );
- $main->AddLabel(
- -name => 'Local',
- -font => $font1,
- -pos => [$w_m-315,50],
- -size => [$w_m,20],
- -text => "",
- );
- $main->AddLabel(
- -name => 'Net',
- -font => $font1,
- -pos => [$w_m-315,100],
- -size => [$w_m,20],
- -text => "",
- );
- $main->AddButton(
- -name => 'B1',
- -pos => [$w_m-300,$h_m-70],
- -font => $font2,
- -text => " 校准时间 ",
- -default => 1,
- -ok => 1,
- -visible => 1,
- -onClick => \&doAdjust,
- );
- $main->AddButton(
- -name => 'B2',
- -pos => [$w_m-150,$h_m-70],
- -text => " 关于程序 ",
- -font => $font2,
- -default => 1,
- -ok => 1,
- -visible => 1,
- -onClick => \&aboutMe,
- );
- my $timer1 = $main->AddTimer('T1',1000);
- $main->B1->Disable();
- $main->Center();
- $main->Show();
- &ObtainNetTime;
- Win32::GUI::Dialog();
- $main->Hide();
- undef $main;
- POSIX::_exit(0);
- sub Window_Terminate {
- return -1;
- }
- sub doAdjust {
- $thread = threads->new(\&Adjust);
- $thread->detach();
- return 0;
- }
- sub aboutMe {
- my $self = shift;
- $self->MessageBox("$about","关于本程序...",MB_ICONINFORMATION | MB_OK,);
- return 0;
- }
- sub T1_Timer {
- my $now = gettime();
- $main->Local->Change(-text => "本机时间: $now");
- }
- sub T2_Timer {
- $net_time++;
- my $now = time_from_utc($net_time);
- $main->Net->Change(-text => "网络时间: $now");
- }
- sub Adjust {
- my ($date,$time) = split(/\s+/,time_from_utc($net_time));
- my $result1 = system("date $date");
- my $result2 = system("time $time");
- if ($result1 or $result2) { $main->MessageBox("本机时间校准失败, 请以管理员身份运行本程序并重试!","本机时间校准失败!",MB_ICONINFORMATION | MB_OK,); }
- else { $main->MessageBox("本机时间校准成功!","本机时间校准成功!",MB_ICONINFORMATION | MB_OK,); }
- }
- sub gettime {
- my ($sec,$min,$hour,$day,$mon,$year,$weekday,$yeardate,$savinglightday) = (localtime(time));
- $sec = ($sec < 10)? "0$sec":$sec;
- $min = ($min < 10)? "0$min":$min;
- $hour = ($hour < 10)? "0$hour":$hour;
- $day = ($day < 10)? "0$day":$day;
- $year += 1900;
- $mon = ($mon < 9)? "0".($mon+1):($mon+1);
- return("$year/$mon/$day $hour:$min:$sec");
- }
- sub ObtainNetTime {
- $main->Net->Change(-text => "连接国际授时服务器...");
- my $total = @time_sever;
- my $sucess = 0;
- for (my $n = 0; $n < $MAX_THREADS; $n++) {
- threads->create(\&thread_io);
- }
- foreach my $time_sever(@time_sever) {
- if ($data_queue ->pending() > $MAX_THREADS * 20) {
- select(undef, undef, undef, 0.02);
- redo;
- }
- $data_queue->enqueue("$time_sever");
- if ($result_queue->pending() > 0) {
- while (my $result = $result_queue->dequeue_nb()) {
- if ($result) { $sucess++; }
- }
- }
- }
- my $times = 1;
- while ($processing_count > 0 or $data_queue->pending() > 0 or $result_queue->pending() > 0) {
- select(undef, undef, undef, 0.02);
- while (my $result = $result_queue->dequeue_nb()) {
- if ($result) { $sucess++; }
- }
- last if ($times > 300 or $sucess >= $total or $sucess >= 3);
- $times++;
- }
- foreach my $thread (threads->list(threads::all)) {
- $thread->detach();
- }
- # Check completion and recheck
- if ($sucess < 3) {
- my @recheck;
- foreach (@time_sever) {
- if (!$checked{$_}) { push(@recheck,"$_"); }
- }
- if (@recheck) {
- foreach my $time_sever (@recheck) {
- next if ($checked{$time_sever});
- my $result = obtain_time($time_sever);
- if ($result) { $sucess++; }
- }
- }
- }
- if ($sucess >= 3) {
- my @utc = sort values %checked;
- for (0..$#utc) {
- if (abs($utc[$_+1] - $utc[$_]) <= 10 or abs($utc[$_-1] - $utc[$_]) <= 10) {
- $net_time = $utc[$_];
- }
- }
- }
- if ($net_time) {
- $main->B1->Enable();
- my $timer2 = $main->AddTimer('T2',1000);
- }
- else {
- $main->MessageBox("连接国际授时服务器失败, 请检查网络并重试!","连接国际授时服务器失败!",MB_ICONINFORMATION | MB_OK,);
- $main->Hide();
- undef $main;
- POSIX::_exit(0);
- }
- return(0);
- }
- sub thread_io()
- {
- while (my $data = $data_queue->dequeue())
- {
- {
- lock $processing_count;
- ++$processing_count;
- }
- my $result = obtain_time($data);
- $result_queue->enqueue($result);
- {
- lock $processing_count;
- --$processing_count;
- }
- }
- }
- sub obtain_time {
- my $time_sever = shift;
- my $time = inet_time($time_sever,'udp',3);
- if ($time) {
- $checked{$time_sever} = $time;
- return(1);
- }
- else { return(0); }
- }
- sub time_from_utc {
- my $utc = shift;
- my ($sec,$min,$hour,$day,$mon,$year,$weekday,$yeardate,$savinglightday) = (localtime($utc));
- $sec = ($sec < 10)? "0$sec":$sec;
- $min = ($min < 10)? "0$min":$min;
- $hour = ($hour < 10)? "0$hour":$hour;
- $day = ($day < 10)? "0$day":$day;
- $mon = ($mon < 9)? "0".($mon+1):($mon+1);
- $year += 1900;
- return("$year/$mon/$day $hour:$min:$sec");
- }
复制代码 工作原理:用多线程从多个授时服务器获取时间,成功后,可以用授时服务器时间来同步本机时间。
打包后的程序如下:
NetTimeSynchronizer.rar
(1.31 MB, 下载次数: 612)
|
|