程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 網絡游戲中的(低精度)時間同步

網絡游戲中的(低精度)時間同步

編輯:C++入門知識

網絡游戲中的(低精度)時間同步


對於網絡游戲來說,從物體的移動、攻擊到最基礎的計時等等,都需要客戶端與服務器保持時間的相對一致,那麼服務器與客戶端同步便是一個必須要解決的問題。通常,網絡游戲都會利用心跳來進行同步,那麼當客戶端並不需要如此精度的同步時,有沒有其他方法呢?這裡主要討論低精度的時間同步(精確到秒)。

工作中接觸過3種簡單的時間同步方法:

首先,定義時間同步類

/// 32位操作系統
typedef unsigned int64_t QWORD;
typedef unsigned long    DWORD;


class TimeSynchronize()
{
public:
    void ServerTimeSync(QWORD ServerTime);
    QWORD GetLocalTime();

private:
    QWORD initServerTime;
    QWORD initClientTime;
    DWORD initClientTimeFromStartup;
};

/// 服務器下發同步消息
void TimeSynchronize::ServerTimeSync(unsigned int64_t serverTime)
{
    initClientTime = time(NULL);
    initServerTime = serverTime;
    initClientTimeFromStartup = timeGetTime();
}

1.當客戶端啟動的時候,服務器向客戶端下發服務器當前的時間,當客戶端需要獲取當前時間時,只需用校正過的時間加上本地時間即可。

DWORD TimeSynchronize::GetLocalTime()
{
    return initServerTime  - initClientTime + time(NULL);   ///< initServerTime  - initClientTime為了消除客戶端與服務器的時間誤差
}
看到這裡,細心的同學要笑了,這種做法修改本地的系統時間,不就修改了該函數的返回值麼。確實,接口中只要取用了本地時間,便將修改本地時間的風險帶入了接口。

2.服務器定時向客戶端發送同步消息,就是所謂的心跳機制,類似TCP中的心跳,服務器定時發送一個自定義的結構體(心跳包或心跳幀),讓對方知道自己“在線”。 以確保鏈接的有效性。當服務器超過一定時間沒有收到來自客戶端的回復,則當做玩家掉線,服務器關閉socket鏈接。不同的游戲也會根據游戲類型的不同,根據自己的需要設計心跳機制,間隔從幾十ms到幾s不等。

那麼當客戶端在大部分時間中並不需要高精度的時間同步時,有沒有其他辦法以降低對服務器性能的消耗?

3.利用timeGetTime接口,與同步時獲取的服務器時間模擬當前時間。

//  timeGetTime:函數以毫秒計的系統時間。該時間為從系統開啟算起所經過的時間。 
//  DWORD timeGetTime(VOID); 
//  參數:無參數。 
//  返回值:以毫秒值返回系統時間。
DWORD TimeSynchronize::GetLocalTime()
{
    return initServerTime + timeGetTime() - initClientTimeFromStartup + initServerTime  - initClientTime;
}

可以看到timeGetTime的返回值精度為(ms),對於精度要求為(s)級的應用來說,已然夠用了。

當然利用timeGetTime()要注意返回值為32位,取值范圍為0~2^32,約為49.71天,要避免溢出。如果服務端利用該接口,又不便於重啟服務器,建議利用精度更高的接口,如:QueryPerformanceFrequency(),QueryPerformanceCounter()。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved