UDP/TCP multithreading/sockets asynchrones

UDP/TCP multithreading/sockets asynchrones - C++ - Programmation

Marsh Posté le 24-07-2006 à 01:27:02    

voila je me lance, je bosse actuellement sur un projet de jeu video et j'apprends la programmation en C++ win32 avec les sockets et TCP et UDP
 
voila j'ai pas mal de question à poser par rapport à ce que j'ai remarqué :)
 
1/ si je créé 2 instances d'un meme programme qui fait envoie et reception de messages en UDP avec le meme port par ex 1234 et la meme IP donc 127.0.0.1 et en utilisant 1 thread pour les envois et un thread pour les receptions, en gros dans chaque thread y'a une boucle while(1), pourquoi une de mes instances receptionne ses propres messages et ceux envoyés par l'autre, et pourquoi l'autre instance n'arrive pas à recevoir ses propres messages et ceux de la première? (j'ai malheureusement pas de 2ème pc sous la main la)
 
2/ les threads c'est bien gentil mais ca me pompe toutes mes ressources processeur, y a-t-il un moyen de coder ca de maniere a ce que ca "bouffe" moins? comme un MSN ou un jeu réseau(ex: half-life, quake3 et compagnie, ...) comment c'est gérer dans ces programmes?
 
3/ j'ai vaguement lu sur les sockets asynchrones, ca a l'air intéressant car ca "bouffe" beaucoup moins de puissance processeur, vu que c'est un evenement windows qui dit quand un message a été recu et qu'il faut le traiter. ok ! mais j'ai aussi vu sur gamedev que des fois y'a un mini-plantage et que ca renvoit une erreur et qu'il faut attendre en moyenne 750ms avant de pouvoir réenvoyer ou rerecevoir, quelqu'un a des infos dessus? des expériences ? j'ai cru ainsi comprendre qu'il fallait mieux faire un systeme de threads sur le serveur et de sockets asynchrones sur le client, mmh si ca marche si bien que ca pourquoi ne pas le faire sur les 2? les sockets asynchrones sont-elles utilisables aussi avec UDP(j'ai testé TCP et ca marche)?
 
4/ il me faut un systeme ou je peux actualiser mes positions de joueurs par UDP toutes les 30ms (40ms=la perception de l'oeil donc c'est impec) et qui envoie par TCP les informations importantes(ex: un objet qui a été ramassé). handicap, il faut que ca prenne le moins de ressources processeur possible et que ce soit fiable, des idées? conseils? expériences? quelqu'un sait comment marche le systeme sur tel ou tel jeu?


Message édité par blooddevil le 24-07-2006 à 01:31:04
Reply

Marsh Posté le 24-07-2006 à 01:27:02   

Reply

Marsh Posté le 24-07-2006 à 08:58:11    

Deja t'utilise quoi pour programmer tes conenctions ? Si tu utilise un truc fait main, je te conseil de tester RakNet.
 
Ensuite, je pense que cherche à utilsier toutes les 30ms le reseau pour communiquer me semble assez lourd ... Y a pas moyen de revoir ton schéma de com ?

Reply

Marsh Posté le 24-07-2006 à 11:51:08    

j'ai entendu parlé de raknet oui mais je prefere coder par moi-meme, car :
1) ca me permet d'apprendre le fonction des sockets, protocoles TCP et UDP
2) je connais sur le bout des doigts le systeme que je vais mettre en place
3) je peux mieux optimisé
 
actuellement comme je t'ai dit j'ai fait des tests en TCP et UDP
non 30ms ne me semble pas lourd, j'enverrais juste un seul packet qui va faire 100 octets, de toute facon le rafraichissement des positions des joueurs doit etre fait le plus souvent possible meme si j'avoue avoir pensé à n'envoyer que les modifications des positions mais ca je verrais par moi-meme lorsque j'aurais fait tous les tests que je compte faire.

Reply

Marsh Posté le 24-07-2006 à 11:55:56    

C'est pas tes threads qui mangent tes ressources, c'est tes while(1) ; tu peux gérer effectivement des choses par évenement plutot que d'attendre des informations indéfiniment, genre évenement sur caractere recu dans le tuyau.

Reply

Marsh Posté le 24-07-2006 à 12:04:42    

mais le fait de faire des sockets asynchrones (donc par tuyau) ca n'enleve pas la portabilité? j'ai cru comprendre qu'il pouvait se produire une erreur de temps en temps...?
je croyais que les sockets blocantes dans des threads, quand elles sont en attente d'envoi ou de reception, elles relachent le travail du CPU sur le thread pour qu'il puisse s'occuper ailleurs...?

Reply

Marsh Posté le 24-07-2006 à 13:56:43    

Le souci, c'est le mélange big/little endian il me semble, en parlant de portabilité.

Reply

Marsh Posté le 24-07-2006 à 14:05:54    

Une technique pas mal utilisée est la fonction select() :
Tu laisse tes socket en mode bloquant, et tu as la possibilité avec select de faire attendre au processus/thread l'arrivée de données sur un/plusieurs socket, avec si tu le désire un timeout.
Tu libére donc totalement le processeur durant ce temps d'attente, plutot que de faire un while().
 
Je ne saurais trop te conseiller la doc ci-dessous si tu ne l'as pas encore lue. ( la fonction select est très bien  expliquée)
http://www.chez.com/vidalc/lf/socket.html
 
Sinon pour ton systeme de TCP/UDP, ca me semble pas très pratique, moi ce que j'ai fait, c'est que j'ai rajouté une couche par dessus UDP qui me permet d'envoyer à la fois des paquets sensibles ou non. Les paquets sensibles sont renvoyés tant que l'interlocuteur en face n'a pas confirmé les avoir recu.
 
Et 30 ms d'intervalle, pour un jeu ca ne me semble pas excessif...


Message édité par pegasus32 le 24-07-2006 à 14:07:25
Reply

Marsh Posté le 24-07-2006 à 14:12:10    

Et pour ton 4.) à mon avis il ne faut pas raisonner suivant la perception de l'oeil, de toute facon pour des mises à jour toutes les 30ms, si la vitesse du mouvement est élevée, l'animation sera saccadée.
 
Tu devrais plutot envoyer des vecteurs de mouvement (l'object va dans cette direction à cette vitesse), et le pc qui fait la simulation fait bouger l'objet suivant ce vecteur à chaque frame, et n'attend donc pas le prochain paquet pour le mettre à jour.
Tu obtiendra donc un mouvement parfaitement fluide, bien que ce soit une approximation du mouvement réel (mais ce n'est pas grave puisque le prochain paquet remettra les pendules à l'heure)


Message édité par pegasus32 le 24-07-2006 à 14:16:08
Reply

Marsh Posté le 24-07-2006 à 16:22:00    

Pour ton 1.) ca vient du fait qu'une seule socket à la fois peut écouter sur un port donné du pc. Donc il faudrait que tu mettes un port d'écoute différent à chaque instance de ton programme si tu les fait tourner sur le même pc (via un paramètre passé à celle ci par exemple).

Reply

Marsh Posté le 24-07-2006 à 16:30:36    

pegasus, imagines que j'ai un jeu de vaisseau dans l'espace avec un plan 2D et qu'il soit possible de jouer à 2joueurs simultanément en réseau local ou par internet grace au protocol UDP. imagines que j'utilise ton systeme(qui me parait pas mal d'ailleurs). lorsqu'un des joueurs va vouloir tirer, le temps que l'information remonte au serveur puis arrive au client, voire meme le temps que l'information parte du client pour aller vers les autres clients(en imaginant que c'est une information importante et qu'elle peut couper le passage par le serveur), il y aura quand meme un décalage par rapport aux 2écrans, je me trompe? comment faire par exemple pour que les 2missiles soit vraiment synchronisés, car cela peut ensuite poser un probleme par rapport à des vaisseaux ennemis, le missile sur l'écran du lanceur va tuer l'ennemi de tres peu, et comme sur l'autre écran(du 2eme joueur) y a un petit décalage, il va rater l'ennemi... tu vois ou je veux en venir? comment fais tu pour compenser ca? car je suppose que la dessus, meme en faisant une prédiction grace à des vecteurs, cela ne permet pas de deviner qu'un des 2 joueurs va tirer... à moins que tu décides de griller les premieres positions du missile, quand il est créé sur l'écran 2. si tu pouvais m'éclairer :)

Reply

Marsh Posté le 24-07-2006 à 16:30:36   

Reply

Marsh Posté le 24-07-2006 à 16:31:12    

blooddevil a écrit :

pegasus, imagines que j'ai un jeu de vaisseau dans l'espace avec un plan 2D et qu'il soit possible de jouer à 2joueurs simultanément en réseau local ou par internet grace au protocol UDP. imagines que j'utilise ton systeme(qui me parait pas mal d'ailleurs). lorsqu'un des joueurs va vouloir tirer, le temps que l'information remonte au serveur puis arrive au client, voire meme le temps que l'information parte du client pour aller vers les autres clients(en imaginant que c'est une information importante et qu'elle peut couper le passage par le serveur), il y aura quand meme un décalage par rapport aux 2écrans, je me trompe? comment faire par exemple pour que les 2missiles soient vraiment synchronisés, car cela peut ensuite poser un probleme par rapport à des vaisseaux ennemis, le missile sur l'écran du lanceur va tuer l'ennemi de tres peu, et comme sur l'autre écran(du 2eme joueur) y a un petit décalage, il va rater l'ennemi... tu vois ou je veux en venir? comment fais tu pour compenser ca? car je suppose que la dessus, meme en faisant une prédiction grace à des vecteurs, cela ne permet pas de deviner qu'un des 2 joueurs va tirer... à moins que tu décides de griller les premieres positions du missile, quand il est créé sur l'écran 2. si tu pouvais m'éclairer :)


Reply

Marsh Posté le 24-07-2006 à 17:23:55    

Moi je suis parti dans une optique où le serveur a autorité sur les clients : les clients ne communiquent pas entre entre eux, toutes les communications passent par le serveur.
 
De plus, quand un joueur tire une roquette, le client dit au serveur "je veux creer une roquette".
 
La simulation de la roquette se fait alors sur le serveur, le client lui se contente d'afficher les infos qui lui envoit le serveur, même pour sa propre roquette.
donc tous les clients verront la roquette au meme coordonnées.
 
Maintenant effectivement il y aura un décalage entre la position affichée et la position réelle de la roquette, à cause du ping.
 
Pour cela tu peut faire de la prédiction en tenant compte du ping au niveau du client.
 
Mais de toute facon c'est le serveur qui a les vraies coordonnées de tous les objets, c'est donc lui qui décide si il y a collision ou non.

Reply

Marsh Posté le 24-07-2006 à 17:44:26    

en gros pegasus si je te comprends bien tu vas a l'opposé de l'idée que j'avais :) dans mon idée je pensais que le serveur ne servait qu'a diffuser l'information envoyée par un client mais en fait c'est pas ca, toi tu proposes une architecture avec un serveur lourd et des clients léger(en gros ils ne font qu'afficher les infos envoyées par le serveur et point barre), c'est un peu comme un architecture 3-tiers avec un client web non ? tout le gros du boulot est fait coté serveur et le client n'est que la partie résultat graphique c'est bien ca ?
n'empeche qu'avec ce systeme celui qui créé une roquette ne la verra pas se créer tout de suite à l'écran je me trompe? y'aura un léger p'tit temps de différence?enfin ca dépend du ping je suppose en reseau local avec 10-15 de ping je pense que l'affichage est instantané alors que sur le net avec 100 de ping on ressent tout de suite beaucoup plus le décalage. donc en gros le serveur à la vérité absolue et le client peut etre légèrement décalé par rapport au serveur?  
quand tu me parles de prédiction en tenant compte du ping au niveau du client, ca j'y ai pensé mais le probleme c'est que le ping ca varie :)
autre détail concernant le serveur lourd et client léger:
quand par exemple le jeu doit créer un ennemi, ou qu'un ennemi utilise un algo pour se déplacer, comme A*, ou sont fait ses calculs? sur le serveur? donc toutes les unités, objets sont instanciés sur le serveur aussi afin qu'il traite les données? donc en gros le client instancie toutes les unités et objets coté client sauf qu'en gros ils sont creux(j'entends par la qu'ils n'ont pas de calculs), ils sont affichés à telles coordonnées à tel instant, en gros c'est une sorte de "vue" du serveur à un instant donné?
désolé de te faire chier avec autant de questions a la con mais j'aime bien avoir quelque chose de parfait ou s'y approchant :) et j'aime bien tout controler :)

Reply

Marsh Posté le 24-07-2006 à 18:14:01    

blooddevil a écrit :


3) je peux mieux optimisé


 
ça je ne pense pas  [:everything4free]

Reply

Marsh Posté le 24-07-2006 à 18:17:17    

bah si car ca va etre adapté a un programme ou un jeu précis donc évidemment que ce sera toujours un peu plus optimisé qu'une bibliothèque générale, meme si celle si fonctionne deja avec de tres bonnes performances

Reply

Marsh Posté le 24-07-2006 à 19:11:34    

Voila en gros tu as compris ce que je voulais dire ;)
En fait le client possède les informations nécessaire à l'affichage de la scène, donc pour une entité : le modèle, la texture, position etc...
 
Et l'ensemble de la simulation est gérée coté serveur.
 
Après bien sur il est possible de faire plein de prédictions cotés client, comme celle du movement, mais également pour la tir d'une roquette par exemple : le client prends l'initiative de tirer la roquette, et après le serveur peut très bien lui dire : non, tu n'as pas pu tirer cette roquette parce que "xxx".
 
Si je me souvient bien, dans le multijoueur de quake1 (pas quakeworld), il n'y avait pas de prédiction, même pour les mouvement, ce qui fait que quand on voulait avancer, ce mouvement avait un décalage égal au ping, c'etait assez injouable :D
 
Le systeme de serveur autoritaire permet en plus de limiter les tricheries, puisque tu peut à peu pres tout controller : munitions, etc, et en cas de probleme tu peut toujours refuser l'action demandée par le client.
 
Evidemment un système décentré est toujours possible, mais ca complique pas mal les choses (enfin je pense), et ca alourdis pas mal la charge réseau des différents clients, vu que chacun d'eux doit envoyer les infos à l'ensemble des autres clients.
 
[hs]
Coté programmation, si tu as une bonne approche ca se fait relativement facilement. Moi j'ai completement séparé l'objet lui même de sa représentation graphique. Par exemple coté serveur j'aurai un objet qui gère un ennemi, donc pathfinding etc...et à cet objet j'attache un mesh (géométrie&texture). Coté client j'aurai juste des entités génériques auquelles j'attache ce même mesh. T'évites ainsi d'avoir à programmer deux fois tes objets pour le serveur et le client ;)
[/hs]
 
Bon tout ca c'est la theorie, j'ai déja fait le code réseau mais pas encore fini le petit jeu qui permet de tester tout ca ;)

Reply

Marsh Posté le 26-07-2006 à 16:25:37    

j'ai remarqué que quand j'utilise l'UDP avec des threads (1 en réception et 1 en émission) et bien par exemple le recvfrom ou le sendto ne sont pas bloquant, ce qui est genant car ca me prend toute la puissance processeur, quelqu'un sait comment les rendre blocant?

Reply

Marsh Posté le 26-07-2006 à 18:06:59    

http://www.chez.com/vidalc/lf/socket.html , paragraphe sur le select()
Et les sockets sont bloquants par défaut, ton programme doit donc bloquer sur les instructions recv, à moins de les passer en mode non bloquant explicitement
Les instructions send ne bloquent jamais, par contre.


Message édité par pegasus32 le 26-07-2006 à 18:12:28
Reply

Marsh Posté le 26-07-2006 à 18:29:33    

pegasus de mon coté ce que je vois c'est que les sockets avec UDP ne sont pas blocantes, j'ai lu le site et je sais que ca va en contradiction avec ce qu'il dit mais je sais ce que je vois:)
imagines que je créé un thread, dedans je mets un while(1) et dans le while je mets:
- recvfrom() le recv() n'est pas utilisable car c'est de l'UDP
- printf() sur le buffer de reception
 
et ben le printf tourne en permanance donc pour moi recvfrom() ne bloque pas non? ma déduction est bonne? comme ca peut se faire? on m'aurait menti ?
sinon pour le select() j'attends d'avoir un exemple potable car je suis en win32 et la c'est pour du UNIX ce qui n'est pas trop ma tasse de "café" :/

Reply

Marsh Posté le 26-07-2006 à 19:13:56    

Et bien je confirme ce que j'ai mis plus haut : les appels à recv & recvfrom sont bloquants. A moins que tu te sois mis en mode non-bloquant ou que recvfrom() a générée une erreur ( elle retourne alors -1 )
 
 
Tu n'as pas oublié
#ifdef WIN32
 WSADATA WSAData;
 WSAStartup(MAKEWORD(2,0), &WSAData);
#endif
? ;)
 
Pour ce qui est de select , l'exemple donné est totalement portable, t'as juste à inclure winsock2.h à la place des librairies unix.


Message édité par pegasus32 le 26-07-2006 à 19:16:13
Reply

Marsh Posté le 27-07-2006 à 22:24:44    

blooddevil a écrit :

pegasus, imagines que j'ai un jeu de vaisseau dans l'espace avec un plan 2D et qu'il soit possible de jouer à 2joueurs simultanément en réseau local ou par internet grace au protocol UDP. imagines que j'utilise ton systeme(qui me parait pas mal d'ailleurs). lorsqu'un des joueurs va vouloir tirer, le temps que l'information remonte au serveur puis arrive au client, voire meme le temps que l'information parte du client pour aller vers les autres clients(en imaginant que c'est une information importante et qu'elle peut couper le passage par le serveur), il y aura quand meme un décalage par rapport aux 2écrans, je me trompe? comment faire par exemple pour que les 2missiles soit vraiment synchronisés, car cela peut ensuite poser un probleme par rapport à des vaisseaux ennemis, le missile sur l'écran du lanceur va tuer l'ennemi de tres peu, et comme sur l'autre écran(du 2eme joueur) y a un petit décalage, il va rater l'ennemi... tu vois ou je veux en venir? comment fais tu pour compenser ca? car je suppose que la dessus, meme en faisant une prédiction grace à des vecteurs, cela ne permet pas de deviner qu'un des 2 joueurs va tirer... à moins que tu décides de griller les premieres positions du missile, quand il est créé sur l'écran 2. si tu pouvais m'éclairer :)


Tu devrais lire qqs articles sur le netcode dans les jeux en temps réel, c'est délicat et il n'y a pas 36 manières de le faire correctement.
Mais pegasus a raison, ce n'est pas (seulement) les positions que tu dois envoyer sur le réseau, mais les informations cinématiques qui permettent d'extrapoler le mouvement des divers objets pendant le laps de temps où tu n'auras plus d'information. Et c'est là que tu dois t'intéresser aux méthodes d'intégration du mouvement qui donnent les résultats les plus précis pour éviter d'être trop à coté de la plaque si le réseau "lagge". Il y a bcp bcp mieux que l'intégration d'Euler, qui est le calcul du mvt le plus simple, comme la méthode de Verlet ou de Beeman.
http://en.wikipedia.org/wiki/Time_integration_method
http://www.gamedev.net/reference/p [...] es/verlet/
 
Il y a une liste d'articles ici: http://www.gamedev.net/reference/l [...] yid=30#168
http://www.flipcode.com/articles/network_part07.shtml
 

Citation :

quand par exemple le jeu doit créer un ennemi, ou qu'un ennemi utilise un algo pour se déplacer, comme A*, ou sont fait ses calculs? sur le serveur? donc toutes les unités, objets sont instanciés sur le serveur aussi afin qu'il traite les données? donc en gros le client instancie toutes les unités et objets coté client sauf qu'en gros ils sont creux(j'entends par la qu'ils n'ont pas de calculs), ils sont affichés à telles coordonnées à tel instant, en gros c'est une sorte de "vue" du serveur à un instant donné?
désolé de te faire chier avec autant de questions a la con mais j'aime bien avoir quelque chose de parfait ou s'y approchant :) et j'aime bien tout controler :)


 
Généralement, le mieux, c'est que les calculs soient effectués sur tous les clients, le serveur ne servant qu'à synchroniser et à s'assurer qu'il n'y a pas de désynchro au niveau des clients. Le serveur est le chef d'orchestre, c'est lui qui dirige en envoyant un signal de tempo, le "heartbeat", et les clients jouent ensemble en calculant toutes les positions chacun de son coté, sachant que le tempo doit être identique pour tout le monde. Le serveur n'a qu'a vérifier que tout le monde est synchrone. C'est en tout cas comme ça que c'est fait sur TA Spring. Et ça marche. Spring n'a pas besoin d'être aussi rapide qu'un FPS, mais par contre, il y a sans doute bcp plus de données échangées, car ce n'est pas quelques acteurs qu'il faut synchroniser, mais des milliers.  
Je ne connais pas dans le détail la procédure de rattrapage quand l'un prend du retard sur les autres par contre. Mais si le lag est trop important, ou pire, si ça bugge chez l'un des joueurs, c'est foutu.


Message édité par el muchacho le 27-07-2006 à 23:07:02

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 28-07-2006 à 09:47:16    

Ah c'est marrant j'aurait plutot dit le contraire ;) A savoir que c'est le serveur qui s'occupe des calculs, et que le client affiche les infos du serveur, en jouant sur l'interpolation entre les infos des paquets.
 
Si chaque client calcule de son coté, il n'y a donc aucune place pour le hasard. Mais effectivement, pour un jeu style RTS, où les paquets sont moins fréquents que dans un FPS, ca peut être intéressant :)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed