3

システムの現地時間をサーバーの時刻に変更して使用することを考えていましたが、これを行う方法は他にもあると思います。私はc#で時計のようなものを見つけようとしていましたが、何も見つかりませんでした。サーバーの時刻をDateTime形式で受信しています。

編集:サーバーと同じ時間に動作しているときに使用するアプリケーションが必要です。サーバーの時刻を一度取得したいのですが、その後、サーバーから取得した時刻を使用して、アプリケーションをwhileループで動作させます。私のシステムの時間とサーバーの時間(5秒でも)の間に違いがあるかもしれません、そしてそれが私がこれをしたい理由です。

4

4 に答える 4

4

意味が完全に明確ではありませんがIClock、コード内のあらゆる場所で使用する独自のインターフェイスを作成し、サーバー(またはNTP)と定期的に同期する実装を作成することはできます。

私のNodaTimeプロジェクトでは、同期の目的ではなく、テストのしやすさのために、注入可能な時計のアイデアをすでに使用しています。(タイムサービスは基本的に依存関係です。)基本的にアイデアは実行可能です:)すでにこれを行っているものは見つからないかもしれませんが、書くのはそれほど難しいことではありません。ただし、時間を調整する方法を検討する必要があります。たとえば、サーバー時間が「最後のサーバー時間+現地時間の測定値」よりも進んでいる場合は、個別にジャンプするのではなく、徐々に時間を調整することをお勧めします。

もちろん、これは常にアプリケーションに対してローカルにすることを前提としています。もう1つの方法(コンテキストによっては適切でない場合があります)は、ホストに時刻同期クライアントを実行するように要求し(最近では、Windowsがデフォルトで実行していると思います)、サーバーとクライアントの違いが発生した場合に失敗し始めることです。大きすぎる。(とにかく正確に同期することは決してありません。少なくとも長くはありません。ある程度の余裕を持たせる必要があります。)

于 2013-02-28T08:11:01.290 に答える
2

時間を同期するために@JonSkeetが提供した答えは良さそうです、私はいくつかのことを指摘したかっただけです。

@Alexeiがすでに述べたように、ユーザーは現地時間を変更できるようにするために管理者権限が必要です(少なくともWindowsでは)が、時間が同期しなくなる可能性のある他の問題(インターネット接続の不良、ハッキングなど)もある可能性があります。 )。これは、クライアントの時間がサーバーの時間と実際に同じであるという保証がないことを意味します。したがって、少なくともサーバー側でリクエストが受信された時間を確認する必要があります。さらに、ここでユーザビリティの問題が発生する可能性もありますが、アプリケーションで自分のローカルマシンの時刻を変更できるようにしたいですか?地獄はありません。

要約すると:

  • 少なくともリクエストサーバーサイドの時間を確認してください
  • クライアントマシンの時刻を変更せずに、アプリケーションに何らかのインジケーターを表示します

アプリケーションでインジケーターを処理する方法は、さまざまな方法で実行できます。

  • サーバーと定期的に同期されるアプリケーション(最初のアイデア)の時計を表示する
  • ある種のカウントダウンを表示し(「x秒後に送信できます。」)、リクエストを受信したときに、resetCountdownリクエストをクライアントにプッシュします。
  • 「送信ボタン」またはあなたが持っているものを有効にします。これはカウントダウンと同じように機能します。

このクライアントサイドのようなリクエストを検証することはほぼ不可能であることを覚えておいてください。したがって、サーバーサイドにいくつかのチェックを組み込む必要があります。

私は実際にコメントを書きたかったのですが、それはちょっと長くなりました.. :)

于 2013-02-28T09:37:41.460 に答える
1

これは6歳なので、ちょっとした降霊術ですが、ネットワークゲームでも同様の問題に対処する必要がありました。

すぐに明らかになる理由から、私が「マルコポーロ」と呼んだテクニックを採用しました。メッセージを交換できるようにするには2つのクロックが必要であり、その精度は、メッセージを交換できる速度に依存します。

免責事項:私はこれを最初に行うのではなく、これが2つのクロックを同期するための最も基本的な方法であると確信しています。それでも、文書化された方法は見つかりませんでした。

クロックB(同期しようとしているクロック)では、次のことを行います::

// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;

// Send that to clock A
SendSyncRequest();

// Wait for an answer
Sleep(..);

クロックA(基準クロック)には、次のハンドラーがあります::

// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
    // We received "Marco" - Send "Polo"
    SendSyncReply(DateTime.UtcNow);
}

そして時計Bに戻る::

// This is triggered by SendSyncReply
OnReceiveSyncReply(DateTime remoteHalfTime)
{
    // Log the time we received it
    DateTime localTime_Polo_Receive = DateTime.UtcNow;

    // The remote time is somewhere between the two local times
    // On average, it will be in the middle of the two
    DateTime localHalfTime = localTime_Marco_Send  + 
         (localTime_Polo_Receive - localTime_Marco_Send) / 2;

    // As a result, the estimated dT from A to B is
    TimeSpan estimatedDT_A_B = localHalfTime - remoteHalfTime;
}

その結果、現在の現地時間から差し引いてリモート時間を見積もることができる、気の利いたTimeSpanにアクセスできるようになりました。

DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;

この見積もりの​​精度は、send-receive-send-receiveのラウンドトリップ時間の影響を受けます。また、クロックドリフトも考慮する必要があります(これは複数回行う必要があります)。

  1. 往復時間。瞬時であれば、正確なdTが得られます。戻ってくるのに1秒かかる場合、遅延が送信側にあるのか受信側にあるのかわかりません。その結果、エラーは0 <e <RTTになり、平均してRTT/2になります。送信(または受信)に他の時間よりも時間がかかることがわかっている場合は、それを活用してください。受信した時間はハーフタイムではありませんが、各レッグにかかる​​時間に比例してシフトします。
  2. クロックドリフト。CPUクロックはドリフトし、おそらく1日あたり1秒です。したがって、潜在的なドリフトが重要な役割を果たす可能性がある場合は、もう一度ポーリングしてください。
于 2019-07-09T16:36:40.347 に答える
0

サーバーは常にUTCモードで時間を節約する必要があります。
サーバーでは、次のようにUTCで時間を節約できます。

  DateTime utcTime = new DateTime(0, DateTimeKind.Utc);

また:

    DateTime utcTimeNow = DateTime.UtcNow;

クライアントでは、UTCに保存されている時刻を取得すると、次のように現地時間に変換できます。

    public DateTime ToLocalTime(DateTime utcTime)
    {
        //Assumes that even if utcTime kind is no properly deifned it is indeed UTC time
        DateTime serverTime= new DateTime(utcTime.Ticks, DateTimeKind.Utc);
        return TimeZoneInfo.ConvertTimeFromUtc(serverTime, m_localTimeZone);            
    }

ローカルタイムゾーンを変更する場合は、構成から使用するタイムゾーンを読み取る方法のコード例を次に示します。

string localTimeZoneId = sysParamsHelper.ReadString(LOCAL_TIME_ZONE_ID_KEY, LOCAL_TIME_ZONE_DEFAULT_ID);
    ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();

    foreach (TimeZoneInfo timeZoneInfo in timeZones)
    {                
       if(timeZoneInfo.Id.Equals(localTimeZoneId))
       {
           m_localTimeZone = timeZoneInfo;
           break;
       }
    }

    if (m_localTimeZone == null)
    {
        m_logger.Error(LogTopicEnum.AMR, "Could not find time zone with id: " + localTimeZoneId + " . will use default time zone (UTC).");
        m_localTimeZone = TimeZoneInfo.Utc;
    }          
于 2013-02-28T08:12:11.987 に答える