多裝置(手機)同步 - React Native
P粉151466081
2023-09-05 11:58:38
<p>我正在嘗試建立 Lightshow,它將同時在所有用戶的行動裝置上啟動(最多可以有 2000-3000 個用戶)。所有用戶都將使用網路(Wi-Fi 或行動數據)。在我們的 FE,我們使用 Apollo 進行訂閱,這就像一個魅力。 </p>
<p>但問題是,用戶 A 可以比用戶 B 更快地獲取訂閱事件。這意味著用戶 A 將比用戶 B 更早開始玩遊戲,這是一個問題,因為我們有 lighshow 架構,而用戶可以『不能早點或晚點開始。作為用戶,您會立即看到差異,而且看起來不太好。 </p>
<p>我看到的是延遲差異可以達到300ms。 android (小米 9) 與 ios (iPhone11) 之間的時間大多約為 180ms -。如果我們比較兩台 iOS 裝置 iPhone 11 和 iPhone 13,差異約為 50-100 毫秒。對於所有設備,有沒有辦法消除這種差異,或至少將其降低到 40-60 毫秒? </p>
<p>從BE 開始,我們發送伺服器時間(utc 0),燈光秀將以時間戳開始=> 在FE 中,我添加10 秒來為所有設備提供解決該功能的時間,因此啟動被延遲-> "時間戳10 秒」。</p>
<p>在 FE 中,我使用庫“react-native-ntp-client”在所有類型的設備上獲得相同的時間(ios/android,因為我發現每個設備的時間略有不同)。然後我計算“start”和“ntpTime”之間的差異,並將其作為超時提供給我的 setTimeout 函數,這將觸發燈光秀的開始。 </p>
<p>下面我提供了一個範例,說明我如何使用燈光秀所在的螢幕。 </p>
<pre class="brush:php;toolbar:false;">import dayjs from 'dayjs';
import ntpClient from 'react-native-ntp-client';
export const LightshowScreen: React.FC<
LightshowScreenProps<'Lightshow'>
> = ({route}) => {
const {data, loading} = useSubscription(JOIN_LIGHTSHOW_SUBSCRIPTION, {
variables: {lightshowId: route.params.lightshow.id},
});
useEffect(() => {
const getServerTime = async (lightshowStartAt: number) => {
// Delay start 10s to provide enough time to finish our functions - lightshowStartAt is timestamp from our server
const lightshowStart = dayjs.unix(lightshowStartAt).add(10, 's');
ntpClient.getNetworkTime('time.cloudflare.com', 123, (error, date) => {
if (error) {
console.error('Cant connect', error);
return;
}
console.log('NTP client date - ', date); // Mon Jul 08 2013 21:31:31 GMT 0200 (Paris, Madrid (heure d’été))
let ntpTime = dayjs(date);
// Diff in ms
const diff = lightshowStart.diff(ntpTime);
// After this timeout all devices should start play at the same time
setTimeout(() => {
lightshowStartHandler();
}, diff);
});
};
if (data && data?.joinLightshow.started) {
const lightshowData = data.lightshow;
getServerTime(lightshowData.startedAt);
}
}, [data]);
useEffect(() => {
if (data && data?.joinLightshow?.finished) {
lightshowFinishHandler();
}
}, [data]);
return (
<View style={style.container}>
....
</View>
);
};</pre>
<p>感謝您的所有評論和想法;)</p>
你想做的事情真的很難。同步這樣的設備很困難。當您不擁有和控制硬體時,這樣做幾乎是不可能的。坦白說,我認為你永遠不會得到你想要的。
時間戳永遠不會起作用。其一,這些設備不會都有相同的時間。他們都會稍微偏離。您的下一個想法是從中央來源(例如您的伺服器)向他們發送時間。問題在於,向每個設備發送資料將花費不同的、隨機的時間。您可以嘗試透過預先計算十幾個資料包的往返時間來猜測延遲,但這仍然是一個猜測,對於下一個資料包可能不準確。 NTP 有助於使裝置的時間接近相同時間,但沒有達到您想要的精確度。
即使它確實達到了您想要的準確性 - Android 也不是即時作業系統。 iPhone 則不然。即使您將鬧鐘設為 12:00:00,它也不會恰好在 12:00:00.000 觸發。在那之後的一段時間,當作業系統有空閒時間、空閒核心並且認為您的應用程式是最重要的調度應用程式時,它將觸發。這可能需要幾百毫秒。有些作業系統可以為您帶來您想要的承諾。它們被稱為即時作業系統,通常用於不會故障的嵌入式設備,例如醫療設備和昂貴機器的控制器。它們是一種與消費性設備所使用的完全不同的作業系統編寫方法。
我真的建議重新考慮您的需求並更現實地對待它們。有些技術可以讓您得到您想要的東西,但不能透過網路在消費者作業系統上的隨機硬體上獲得。
另外,如果你想這樣做 - 我真的不建議使用 React Native,它以垃圾收集語言運行解釋器,並且具有非常隨機的計時。您至少需要用 C 語言編寫啟動器,因為這是最可預測的方法。
但實際上,請重新考慮您的需求。為什麼需要在 50 毫秒內啟動?當您透過網路做事時,如果人們有一秒鐘不同步,這真的很重要嗎?