Synchronisation multi-appareils (téléphone mobile) - React Native
P粉151466081
2023-09-05 11:58:38
<p>J'essaie de créer un Lightshow qui se lancera sur les appareils mobiles de tous les utilisateurs en même temps (peut avoir jusqu'à 2 000 à 3 000 utilisateurs). Tous les utilisateurs utiliseront Internet (Wi-Fi ou données mobiles). Dans notre FE, nous utilisons Apollo pour les abonnements et cela fonctionne à merveille. </p>
<p>Mais le problème est que l'utilisateur A peut obtenir des événements d'abonnement plus rapidement que l'utilisateur B. Cela signifie que l'utilisateur A commencera à jouer au jeu plus tôt que l'utilisateur B, ce qui pose problème car nous avons une architecture lighshow et les utilisateurs ne peuvent pas commencer plus tôt ou plus tard. En tant qu'utilisateur, vous verrez immédiatement la différence, et cela n'a pas l'air bien. </p>
<p>Ce que je vois, c'est que la différence de latence peut atteindre 300 ms. Le temps entre Android (Xiaomi 9) et iOS (iPhone11) est généralement d'environ 180 ms+-. Si l’on compare deux appareils iOS, iPhone 11 et iPhone 13, la différence est d’environ 50 à 100 millisecondes. Existe-t-il un moyen d'éliminer cette différence, ou au moins de la réduire à 40-60 ms pour tous les appareils ? </p>
<p>À partir de BE, nous envoyons l'heure du serveur (utc+0) et le spectacle de lumière commencera avec l'horodatage => Dans FE, j'ai ajouté 10 secondes pour donner à tous les appareils le temps de résoudre la fonctionnalité, donc le démarrage est un délai-> "horodatage + 10 secondes".</p>
<p>Dans FE, j'ai utilisé la bibliothèque "react-native-ntp-client" pour obtenir la même heure sur tous les types d'appareils (ios/android, car j'ai trouvé que l'heure est légèrement différente pour chaque appareil). Je calcule ensuite la différence entre "start" et "ntpTime" et la fournisse comme délai d'attente à ma fonction setTimeout, qui déclenchera le début du spectacle de lumière. </p>
<p>Ci-dessous, j'ai fourni un exemple de la façon dont j'utilise l'écran sur lequel se trouve le spectacle de lumière. </p>
<pre class="brush:php;toolbar:false;">importer dayjs depuis 'dayjs';
importer ntpClient depuis 'react-native-ntp-client' ;
exporter const LightshowScreen : React.FC<
LightshowScreenProps<'Lightshow'>
> = ({itinéraire}) =>
const {données, chargement} = useSubscription(JOIN_LIGHTSHOW_SUBSCRIPTION, {
variables : {lightshowId : route.params.lightshow.id},
});
useEffect(() => {
const getServerTime = async (lightshowStartAt : numéro) =>
// Retarder le démarrage de 10 s pour laisser suffisamment de temps pour terminer nos fonctions - lightshowStartAt est l'horodatage de notre serveur
const lightshowStart = dayjs.unix(lightshowStartAt).add(10, 's');
ntpClient.getNetworkTime('time.cloudflare.com', 123, (erreur, date) => {
si (erreur) {
console.error('Impossible de se connecter', erreur);
retour;
}
console.log('NTP client date - ', date); // Lundi 08 juillet 2013 21:31:31 GMT+0200 (Paris, Madrid (heure d'été))
laissez ntpTime = dayjs(date);
// Diff en ms
const diff = lightshowStart.diff(ntpTime);
// Après ce délai, tous les appareils devraient commencer à jouer en même temps
setTimeout(() => {
lightshowStartHandler();
}, différence);
});
} ;
if (data && data?.joinLightshow.started) {
const lightshowData = data.lightshow;
getServerTime(lightshowData.startedAt);
}
}, [données]);
useEffect(() => {
if (data && data?.joinLightshow?.finished) {
lightshowFinishHandler();
}
}, [données]);
retour (
<View style={style.container}>
....
</Afficher>
);
};</pré>
<p>Merci pour tous vos commentaires et réflexions ;)</p>
Ce que tu veux faire est vraiment difficile. La synchronisation d'un tel appareil est difficile. Faire cela est presque impossible lorsque vous ne possédez pas et ne contrôlez pas le matériel. Franchement, je ne pense pas que vous obtiendrez jamais ce que vous voulez.
Les horodatages ne fonctionneront jamais. D’une part, ces appareils n’auront pas tous le même timing. Ils seront tous légèrement décalés. Votre prochaine idée est de leur envoyer l'heure à partir d'une source centrale telle que votre serveur. Le problème est que l’envoi de données à chaque appareil prendra un temps différent et aléatoire. Vous pouvez essayer de deviner la latence en pré-calculant le temps aller-retour pour une douzaine de paquets, mais cela reste une estimation et peut ne pas être précis pour le paquet suivant. NTP permet de maintenir les heures des appareils proches de la même heure, mais pas aussi précises que vous le souhaiteriez.
Même s'il atteint la précision souhaitée, Android n'est pas un système d'exploitation en temps réel. Ce n’est pas le cas avec l’iPhone. Même si vous réglez votre alarme sur 12:00:00, elle ne se déclenchera pas à 12:00:00.000 exactement. Quelque temps après, il se déclenchera lorsque le système d'exploitation aura du temps d'inactivité, des cœurs inactifs et considérera votre application comme l'application planifiée la plus importante. Cela peut prendre des centaines de millisecondes. Il existe des systèmes d'exploitation qui peuvent vous donner la promesse que vous souhaitez. Connus sous le nom de systèmes d'exploitation en temps réel, ils sont souvent utilisés dans des appareils embarqués qui ne peuvent pas tomber en panne, tels que les équipements médicaux et les contrôleurs de machines coûteuses. Il s’agit d’une approche complètement différente de l’écriture de systèmes d’exploitation par rapport à celles utilisées par les appareils grand public.
Je recommande vraiment de repenser vos besoins et d’être plus réaliste à leur sujet. Il existe des technologies qui vous permettent d'obtenir ce que vous voulez, mais pas sur du matériel aléatoire sur des systèmes d'exploitation grand public sur Internet.
De plus, si vous souhaitez faire cela, je ne recommande vraiment pas d'utiliser React Native, il exécute l'interpréteur dans un langage ramassé et a un timing très aléatoire. Vous souhaiterez au moins écrire votre lanceur en C, car c'est l'approche la plus prévisible.
Mais vraiment, veuillez reconsidérer vos besoins. Pourquoi doit-il démarrer dans les 50 millisecondes ? Lorsque vous faites des choses sur Internet, est-ce vraiment important si les gens sont désynchronisés pendant une seconde ?