マルチデバイス (携帯電話) の同期 - React Native
P粉151466081
2023-09-05 11:58:38
<p>すべてのユーザーのモバイル デバイスで同時に起動するライトショーを作成しようとしています (最大 2000 ~ 3000 ユーザーが参加可能)。すべてのユーザーはインターネット (Wi-Fi またはモバイル データ) を使用します。私たちの FE では、サブスクリプションに Apollo を使用していますが、それは魅力的に機能します。 </p>
<p>しかし問題は、ユーザー A がユーザー B よりも早くサブスクリプション イベントを取得できることです。これは、ユーザー A がユーザー B よりも早くゲームのプレイを開始することを意味します。ライトショー アーキテクチャがあり、ユーザーは早くも遅くも開始できないため、これが問題になります。ユーザーとしては違いがすぐにわかりますが、見た目は良くありません。 </p>
<p>遅延の差は最大 300 ミリ秒になる可能性があることがわかります。 Android(Xiaomi 9)とiOS(iPhone11)の間の時間は、ほとんどが180ms程度です。 2 つの 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;">dayjs を 'dayjs' からインポートします。
「react-native-ntp-client」から ntpClient をインポートします。
エクスポート const LightshowScreen: React.FC<
LightshowScreenProps<'Lightshow'>
> = ({ルート}) => {
const {データ、読み込み中} = useSubscription(JOIN_LIGHTSHOW_SUBSCRIPTION, {
変数: {lightshowId:route.params.lightshow.id}、
});
useEffect(() => {
const getServerTime = async (lightshowStartAt:number) => {
// 関数を完了するのに十分な時間を確保するために開始を 10 秒遅らせます - lightshowStartAt はサーバーからのタイムスタンプです
const lightshowStart = dayjs.unix(lightshowStartAt).add(10, 's');
ntpClient.getNetworkTime('time.cloudflare.com', 123, (エラー, 日付) => {
if (エラー) {
console.error('接続できません', エラー);
戻る;
}
console.log('NTP client date - ', date); // Mon Jul 08 2013 21:31:31 GMT 0200 (パリ、マドリッド (heure d’été))
let ntpTime = dayjs(date);
// ミリ秒単位の差分
const diff = lightshowStart.diff(ntpTime);
// このタイムアウトの後、すべてのデバイスが同時に再生を開始する必要があります
setTimeout(() => {
ライトショーStartHandler();
}、差分);
});
};
if (データ && データ?.joinLightshow.started) {
const lightshowData = data.lightshow;
getServerTime(lightshowData.startedAt);
}
}、 [データ]);
useEffect(() => {
if (データ && データ?.joinLightshow?.finished) {
ライトショー終了ハンドラー();
}
}、 [データ]);
戻る (
<スタイル={style.container}の表示>
....
</表示>
);
};</pre>
<p>たくさんのコメントやご意見ありがとうございます;)</p>
あなたがやりたいことは本当に難しいです。このようなデバイスの同期は困難です。ハードウェアを所有および制御していない場合、これを行うことはほぼ不可能です。率直に言って、欲しいものは決して手に入らないと思います。
タイムスタンプは機能しません。まず、これらのデバイスはすべて同じタイミングではありません。それらはすべてわずかにずれます。次のアイデアは、サーバーなどの中央ソースから時刻を送信することです。問題は、各デバイスへのデータの送信にかかる時間がランダムで異なることです。数十のパケットの往復時間を事前に計算して遅延を推測することもできますが、それはまだ推測であり、次のパケットでは正確ではない可能性があります。 NTP は、デバイスの時刻をほぼ同じ時刻に保つのに役立ちますが、必要なほど正確ではありません。
たとえ希望する精度が得られたとしても、Android はリアルタイム オペレーティング システムではありません。 iPhoneの場合はそうではありません。アラームを 12:00:00 に設定したとしても、ちょうど 12:00:00.000 にアラームが鳴ることはありません。その後しばらくして、オペレーティング システムにアイドル時間があり、コアがアイドル状態になり、アプリケーションが最も重要なスケジュール済みアプリケーションであるとみなされたときに起動されます。これには数百ミリ秒かかる場合があります。あなたが望む約束を与えることができるオペレーティングシステムがあります。リアルタイム オペレーティング システムとして知られるこれらは、医療機器や高価な機械のコントローラーなど、故障が許されない組み込み機器でよく使用されます。これらは、民生用デバイスで使用されるオペレーティング システムとはまったく異なるアプローチでオペレーティング システムを作成します。
自分のニーズを再考し、より現実的になることを強くお勧めします。欲しいものを入手できるテクノロジーはありますが、インターネット上の消費者向けオペレーティング システム上のランダムなハードウェアでは入手できません。
また、これを実行したい場合は、React Native を使用することはあまりお勧めしません。React Native はガベージ コレクション言語でインタープリタを実行し、タイミングが非常にランダムになります。これが最も予測可能なアプローチであるため、少なくともランチャーを C で作成することをお勧めします。
しかし実際には、自分のニーズを再考してください。なぜ 50 ミリ秒以内に開始する必要があるのでしょうか?インターネット上で何かをするとき、人々が一瞬でも同期していなくても、本当に問題になるのでしょうか?