ntpサーバを使って,デバイス間の時刻修正
カウントダウンアプリをつくっていますが,各自のスマホの時間がバラバラなので,ntpから差分とった時刻で正確な時間を出すようにしてみました.
修正中ですが,概ねこれで作動します.
元ネタはこれ→ http://ftvoid.com/blog/post/847
HTML5ならもう少し簡単だったのですが,,
using UnityEngine;
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine.UI;//use unity gui
// NTP同期時刻を管理するクラス
public class NtpDate : MonoBehaviour {
private DateTime ntpDate; // NTP同期時刻
private float rcvAppDate; // NTP通信時のアプリ時刻
private IPEndPoint ipAny;
private UdpClient sock;
private Thread thread;
private volatile bool threadRunning = false;
private byte[] rcvData;
public string myString; //for time display
private DateTime endDate; //for end date
public Transform myButton; //get button object
public Text countText; //Text用変数
private TimeSpan zure;
// 初期化
void Start() {
// リクエスト実行
SyncDate();
// 時刻表示(デバッグ用)
StartCoroutine(ShowSyncDate());
//Debug.Log (System.DateTime.Now);
}
// 同期時刻の表示
private IEnumerator ShowSyncDate() {
while ( true ) {
yield return new WaitForSeconds(0.1f);//0.5f
timeCheck ();// do timeCheck() every 1 second
//if ( Date == false ) {
if ( Date == null ) {
Debug.Log("Time is not received.");
} else {
//Debug.Log("Receive date : " + Date.ToString());
// Debug.Log (DateTime.Now);// DateTime.Now is confiured time
}
}
}
/// for GUI my add
public void timeCheck(){
endDate = new DateTime(2016, 4, 2, 18,30,00); //本番用
// endDate = new DateTime(2016, 2, 4, 12,30,00);//for test
TimeSpan sabun = endDate - DateTime.Now; //compare now time and end time
// Debug.Log ("before" + sabun);
// Debug.Log ("after" + (sabun - zure));
//int result = TimeSpan.Compare(endDate, DateTime.Now);// cant use
sabun = sabun - zure;//zure naosu
if (sabun.Days <= 0 && sabun.Hours <= 0 && sabun.Minutes <= 0 && sabun.Seconds <= 0) { //sabun is all zero and minus
myString = "Light It Up Blue!"; //message of button
countText.text = myString; //put text to GUItext
myButton.GetComponent<Toggle>().interactable = true; //unlock the button
} else {
myString = string.Format ("{0:00}D{1:00}H{2:00}M{3:00}S", sabun.Days, sabun.Hours, sabun.Minutes, sabun.Seconds);//string format
countText.text = myString; //time remaining
myButton.GetComponent<Toggle>().interactable = false; //lock button before last time
}
}
public void Update(){
// timeCheck ();
}
// アプリケーション終了時処理
void OnApplicationQuit() {
if ( thread != null ) {
thread.Abort();
}
if ( sock != null ) {
sock.Close();
}
}
// 時刻同期を行う
public void SyncDate() {
// リクエスト実行
threadRunning = true;
thread = new Thread(new ThreadStart(Request));
thread.Start();
// リクエスト待機コルーチン実行
StartCoroutine(WaitForRequest());
Debug.Log("Thread is started.");
}
// NTPサーバに対してリクエストを実行する
private void Request() {
// ソケットを開く
ipAny = new IPEndPoint(IPAddress.Any, 123);
// sock = new UdpClient(ipAny);
sock = new UdpClient();
// リクエスト送信
byte[] sndData = new byte[48];
sndData[0] = 0xB;
sock.Send(sndData, sndData.Length, "ntp.jst.mfeed.ad.jp", 123);
// データ受信
rcvData = sock.Receive(ref ipAny);
// 実行中フラグクリア
threadRunning = false;
}
// リクエスト待機コルーチン
private IEnumerator WaitForRequest() {
// リクエスト終了まで待機
while ( threadRunning ) {
yield return 0;
}
// アプリ時刻保存
rcvAppDate = Time.realtimeSinceStartup;
Debug.Log (rcvAppDate);
// 受信したバイナリデータをDateTime型に変換
ntpDate = new DateTime(1900, 1, 1);
var high = (double)BitConverter.ToUInt32(new byte[] { rcvData[43], rcvData[42], rcvData[41], rcvData[40] }, 0);
var low = (double)BitConverter.ToUInt32(new byte[] { rcvData[47], rcvData[46], rcvData[45], rcvData[44] }, 0);
ntpDate = ntpDate.AddSeconds(high + low / UInt32.MaxValue);
// UTC→ローカル日時に変換
ntpDate = ntpDate.ToLocalTime();
zure = Date - DateTime.Now;
Debug.Log ("zure" + zure);
}
// NTP同期時刻
public DateTime Date {
get {
return ntpDate.AddSeconds(Time.realtimeSinceStartup - rcvAppDate);
}
}
}
