Voilà, petite question:
Je suis novice en prog réseau, et j'aimerais dans le cadre d'un projet de jeux tour/tour, permettre à deux ou trois joueurs
de jouer les uns contre les autres. Rien de bien extraordinaire, mais n'ayant aucune connaissance dans le reseau en générale, et désireux de me former
petit à petit, quelle librairie me conseillez-vous ?
En sachant que je ne cherche pas la haute performance, mais plutôt une bonne souplesses d'utilisation et une certaine facilité de mise en
œuvre, pour le débutant que je suis. J'ai fait mon petit tour des popotes sur le net bien sûr, mais j'aimerais avoir vos conseil
à vous ici aussi...
Merci d'avance pour vos précieux conseils...
Hors ligne
je déconseille racknet , ou alors tu attent ma new lib, ou alors y'a toujours mon ancienne lib ou le tcp et fonctionnelle
Hors ligne
Merci pour ta réponse. Que penses tu sinon de K-NetLib ?
Hors ligne
je connai pas dsl aufait ta ete voire le topic de mon projet (celui du mmorpg)
Hors ligne
hardcpp :
... aufait ta ete voire le topic de mon projet (celui du mmorpg)
je viens de répondre
Hors ligne
personnellement j'utilise les socket et contrairement a se que l'on dit se n'est pas si difficile que cela
le seul problème qui se pose est que le client est obliger de se reconnecter a la fin de la boucle du serveur ....
se que je suis entrain de faire ^^
Hors ligne
Merci, je vais jeter un coups d'œil
Hors ligne
D'accord avec Magun.
le seul problème qui se pose est que le client est obliger de se reconnecter a la fin de la boucle du serveur
Gné ?
D'ou tu sors ca ?
Hors ligne
si tu veut faire un serveur pour plusieurs client il faut accepter le client a chaque boucle via accept(int sock, struct sockaddr *adresse, socklent_t *longueur);
seul problème sa mais le serveur en attente d'une connexion .... ou alors crée un thread pour cette fonction ... ?
alors jais mal coder mon truc :p
#include <iostream> #include <pthread.h> #include <CompileConfig.h> IrrlichtDevice *device; IGUIListBox *information; SOCKET sock; SOCKADDR_IN sain; SOCKET csock; SOCKADDR_IN csin; char buffer[BUFFERSIZE]; void *socketThread(void*); int main(void) { int width = 600, height = 300; SIrrlichtCreationParameters param; param.AntiAlias = false; param.Bits = 16; param.DriverType = EDT_SOFTWARE; param.Fullscreen = false; param.Stencilbuffer = false; param.WindowSize = dimension2d<s32>(width, height); device = createDeviceEx(param); device->setResizeAble(true); device->setWindowCaption(L"serveur v0.01"); IVideoDriver *driver = device->getVideoDriver(); IGUIEnvironment *guienv = device->getGUIEnvironment(); information = guienv->addListBox(rect<s32>(10,10,width-10,height-10),0,0,true); #if defined (WIN32) WSADATA WSAData; int erreur = WSAStartup(MAKEWORD(2,0), &WSAData); #else int erreur = 0; #endif sock = socket(AF_INET,SOCK_STREAM,0); stringw tx = L"Socket "; tx += sock; tx += L" is open with TCP/IP"; information->addItem(tx.c_str()); sain.sin_addr.s_addr = htonl(INADDR_ANY); sain.sin_family = AF_INET; sain.sin_port = htons(PORT); erreur = bind(sock, (SOCKADDR *) &sain, sizeof(sain)); tx = L"> listen port "; tx += PORT; tx += L" ..."; information->addItem(tx.c_str()); listen(sock,2); information->addItem(L"OK"); information->addItem(L"serveur is now ready"); information->addItem(L""); pthread_t thread; pthread_create(&thread,NULL,socketThread,NULL); while(device->run()) { driver->beginScene(true,true,SColor(100,100,100,100)); guienv->drawAll(); device->sleep(10,true); driver->endScene(); } device->drop(); pthread_cancel(thread); exit(0); } void *socketThread(void*) { while(1) { int sinsize = sizeof(csin); if((csock = accept(sock,(SOCKADDR*)&csin,&sinsize))) { stringw tx = L"> client conected : Sock ( "; tx += csock; tx += L" ), IP ( "; tx += inet_ntoa(csin.sin_addr); tx += L" : "; tx += htons(csin.sin_port); tx += L" )"; information->addItem(tx.c_str()); } recv(csock, buffer, sizeof(buffer), 0); information->addItem(stringw(buffer).c_str()); if(strstr(buffer,"LOG = ")) { char log[50] = ""; char pass[50] = ""; sscanf(buffer,"LOG = %s", &log); recv(csock, buffer, sizeof(buffer), 0); information->addItem(stringw(buffer).c_str()); sscanf(buffer,"PASS = %s", &pass); IXMLReader *readAccount = device->getFileSystem()->createXMLReader("accounts/accounts.xml"); stringw XMLTEXT; bool ok = false; bool ko = false; while(readAccount && readAccount->read()) { switch(readAccount->getNodeType()) { case EXN_TEXT: XMLTEXT = readAccount->getNodeData(); break; case EXN_ELEMENT: if(!strcmp(("account"),stringc(readAccount->getNodeName()).c_str())) if(stringc(log) == stringc(readAccount->getAttributeValue(L"name"))) { information->addItem(stringw(readAccount->getAttributeValue(L"name")).c_str()); ok = true; } if(!strcmp(("Pass"),stringc(readAccount->getNodeName()).c_str())) if(stringc(pass) == stringc(readAccount->getAttributeValue(L"name"))) { information->addItem(stringw(readAccount->getAttributeValue(L"name")).c_str()); ko = true; } break; default: break; } } readAccount->drop(); if(ok && ko) { information->addItem(stringw(buffer).c_str()); sprintf(buffer,"CONNECTION_ESTABLED\n"); send(csock,buffer,sizeof(buffer),0); } else if(ok && !ko) information->addItem(L"UNCORRECTLED_PASSWORD"); else send(csock,"ACCOUNT_NOT_FOUND OR UNCORRECTLED_PASSWORD\n",sizeof(buffer),0); } } }
mais de cette façons le client de peut plus envoyer après avoir déjà envoyer LOG et PASS , je sais pas pourquoi
si je ne reconnecte pas le client après je ne peut plus rien faire de même que le serveur ne peut pas envoyer indéfiniment au client il finie toujours par ne l'envoyer que 3 fois :]
fin bref sa fait qu'une semaine ou 2 que je travaille dessus, et pas a temps plein
Hors ligne
[ cool ça parle technique, je vais apprendre des choses ]
Hors ligne
Vu la structure de ton serveur sa ne peut que foirer il faut tout revoir : je te donne des indice:
-boost::thread
-multi Sources/Header
-Laisse tomber le xml
-Un serveur n'a pas besoin de gui (administration a distance)
-Ton serveur(la machine) va planter des quil il aura u 900 connexion tu crée un thread qui contiens une boucle infini si le client de se déco sa tourne encore
-MutexMutex et encore mutex sinon plantage
-.......
en gros tu peut tout refaire
pour le stockage sont mysql soi fichier soit sqllite
Hors ligne
Euuuu y a mieu que les thread il y a select pour l'asynchrone et ca enlève les problème de thread et les mutex qui sont rappelons le 30fois plus lent que si executé normalement.
Voila la code que j'utilise côté serveur :
int server::run() { int code = select (FD_SETSIZE, &readfs, NULL, NULL, &timeout); switch(code) { case 0: if(m_client) sleep(10); _world.update(); break; case -1: cout << "select() error" << endl; break; default: if (FD_ISSET (sock, &readfs)) { if((NewConnection = accept (sock, (SOCKADDR *) &sin,&recsize)) == INVALID_SOCKET) { closesocket( sock ); return 1; } m_log->_Log("Client connected with socket # %d from %s:%d", NewConnection, inet_ntoa (sin.sin_addr), htons (sin.sin_port)); session = new WorldSession(NewConnection,&_world); _world.addSession(session); m_client++; } else if(FD_ISSET (usock, &readfs)) { SOCKADDR_IN clientAddr = { 0 }; int recsize = sizeof clientAddr; char buffer[1024]; int n = recvfrom (usock, buffer, sizeof buffer - 1, 0, (SOCKADDR *) & clientAddr, (socklen_t*)&recsize); cout << "UDP, n = " << n << " message = " << buffer <<" PORT = " << clientAddr.sin_port << endl; } else { while((session = _world.getNextSession())!= NULL) { if(FD_ISSET(session->m_sock, &readfs)) { if(session->onRead() == 1) { cout << "Client disconnected" << endl; _world.removeSession(session); delete session; m_client--; } break; } } } break; } if(m_client) _world.update(); else sleep(10); } void server::initFD() { FD_ZERO (&readfs); FD_SET (sock, &readfs); FD_SET (usock, &readfs); while((session = _world.getNextSession())!= NULL) { FD_SET (session->m_sock, &readfs); } }
J'accepte des connexion, je recois des paquets TCP et UDP en même puis j'ai 1 thread CLI pour les commandes et 1thread update qui traite les paquets de chaque client.
Dernière modification par yamashi (04-01-2009 19:19:51)
Hors ligne
merci bien je vais tout refaire
pour l'interface graphique étant donner que le serveur seras le pc qui est a coter de moi ses toujours plus simple que de s'embêter a le faire a distance pour le xml
il me semblais que c'était une bonne possibilité pour pas trop s'embêter .... après boost je nais rien contre j'irais revoir
par contre aussi hardcpp le serveur ne va pas planter au bout de 900 connexion ... je n'utilise pas 1 thread par client mais 1 pour tout les clients
enfin puisque tout magniere se n'est pas parfait donc peut-on m'éclairer ?
tmyke en profiteras puisque sa l'intéresse et que c'était sont topic au début :p
telle que je voie que tu ( yamashi ) utilise FD_ISSET et compagnie que je ne connait pas ... sa change quoi concrètement ?
Dernière modification par Magun (04-01-2009 20:24:41)
Hors ligne
FD_ISSET et select permet de tout faire d'un coup.
select attend un message et FD_ISSET est le stockage qui te permet ensuite de retrouvé sur quel socket il y a eu un événement.
Ensuite tu effectue tes opérations sur ton socket.
J'utilise pthread et pour la console graphique personnellement j'ai fait une sorte de telnet comme ca je peux accéder a la console de mon serveur partout et simplement.
Mais mon architecture est bien plus complexe que ca car j'utilise le load balancing donc je fais passé mes paquet a la bonne machine qui renvoie la réponse a envoyer... Puis j'ai fais en sorte que mon serveur ne puisse pas planter car il s'auto récupère si il y a un cycle qui saute ou une erreur dans la mémoire...
Hors ligne
ohhhhh !
bon ben je vais voir se que je peut refaire déjà une class serais bien °°'
je poste quand j'aurais tout refait
avec une rar pour tester et vous me dirais si ses pas trop mal :]
Hors ligne
Pour répondre a tmyke car il est quand même l'auteur du topic voici un code que tu pourrais modifier pour adapter a tes besoins :
#if defined (WIN32) #include <winsock2.h> #define socklen_t int #elif defined (linux) #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket(s) close (s) typedef int SOCKET; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; #endif #include <iostream> #include <list> #include <pthread.h> typedef std::list<SOCKET> sockvec; sockvec m_vec; fd_set readfs; struct timeval timeout; SOCKET sock; SOCKADDR_IN sin; socklen_t recsize; using namespace std; int run() { SOCKET NewConnection; int code = select (FD_SETSIZE, &readfs, NULL, NULL, &timeout); switch(code) { case 0: break; case -1: break; default: if (FD_ISSET (sock, &readfs)) { if((NewConnection = accept (sock, (SOCKADDR *) &sin,&recsize)) == INVALID_SOCKET) { closesocket( sock ); return 1; } m_vec.push_back(NewConnection); cout << "Nouveau client, IP : " << inet_ntoa (sin.sin_addr); } else { for (sockvec::iterator It = m_vec.begin() ; It != m_vec.end() ; It++) { if(FD_ISSET(*It,&readfs)) { char buffer[1500]; int n = recv(*It,buffer,sizeof buffer - 1,0); cout << "Nous avons recu : " << n << " octets" << endl; cout << "Buffer : " << buffer << endl; if(n == SOCKET_ERROR) m_vec.erase(It); } } } break; } } void initFD() { FD_ZERO (&readfs); FD_SET (sock, &readfs); for (sockvec::iterator It = m_vec.begin() ; It != m_vec.end() ; It++) { FD_SET (*It, &readfs); } } int main() { #if defined (WIN32) WSADATA WSAData; int error = WSAStartup(MAKEWORD(2,0), &WSAData); #else int error = 0; #endif recsize = (int) sizeof sin; int sock_err; timeout.tv_sec = 0; timeout.tv_usec = 50; int port; cout << "Port a ecouter : "; cin >> port; if(!error) { /*********************************************************/ /*** TCP **/ /*********************************************************/ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock != INVALID_SOCKET) { // Set the protocol, port, and address information. sin.sin_addr.s_addr = htonl (INADDR_ANY); sin.sin_family = AF_INET; sin.sin_port = htons (port); // Bind the socket. int sock_err = bind (sock, reinterpret_cast<sockaddr *>(&sin), recsize); cout << "TCP socket ouvert a l'écoute de : " << port << endl; if (sock_err != SOCKET_ERROR) { sock_err = listen (sock, 5); while(1) { initFD(); run(); } } closesocket(sock); } #if defined (WIN32) WSACleanup(); #endif } return 0; }
Ce code accepte des connections TCP (autant que tu veux) et affiche le paquet recu ainsi que sa taille jusqu'a ce que le client se déconnecte.
Je n'ai pas gérer le paquet stacking.
Ce code n'est pas très propre...
Donc a toi d'en faire une classe ou de gérer comme bon te semble.
Pour ce qui est d'un client :
#if defined (WIN32) #include <winsock2.h> #define socklen_t int #elif defined (linux) #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket(s) close (s) typedef int SOCKET; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; #endif #include <iostream> void main() { WSADATA WSAData; WSAStartup(MAKEWORD(2,0), &WSAData); SOCKET sock; SOCKADDR_IN sin; char *buffer = new char[255]; char ip[20]; int port; cout << "IP du serveur : "; cin >> ip; cout << "Port du serveur : "; cin >> port; /* Tout est configuré pour se connecter sur IRC, haarlem, Undernet. */ sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_addr.s_addr = inet_addr(ip); sin.sin_family = AF_INET; sin.sin_port = htons(port); connect(sock, (SOCKADDR *)&sin, sizeof(sin)); while(1) { char buffer[1500]; cin >> buffer; send(sock,packet,sizeof packet + 1, 0 ); //recv(sock, buffer, sizeof(buffer), 0); <- fonction si tu veux recevoir } closesocket(sock); WSACleanup(); }
Hors ligne
Merci beaucoup, en tout les cas j'apprends beaucoup à vous lire, et c'est aussi en quelques sortes le coté intéressant de ce sujet
Hors ligne
Pourquoi ne pas utiliser Raknet ? Elle a l'air très puissante cet lib! Quand on voit les mmo qui tournent avec, c'est plutôt un bon argument ?
Est elle dur a prendre en main ?
Hors ligne
euh tu demandera a yamashi moi perso j'en pense que trop lourde et en plsu pas de projet commerciale et je croi que le code source du projet doit etre opensource
Hors ligne
Pourquoi ne pas utiliser Raknet ? Elle a l'air très puissante cet lib! Quand on voit les mmo qui tournent avec, c'est plutôt un bon argument ?
Est elle dur a prendre en main ?
Ce n'est pas pour rien que certain personne comme moi se spécialisent en réseau, c'est compliqué de gérer a grande échelle, je tiens a parler du paquet stacking qui est un énorme problème en réseau TCP, il y a d'autres problème en UDP (packet drop, timeout non gérer, deletion, addition, mauvais ordre...) mais utiliser des librairies comme raknet est une mauvaisé idée, je m'explique :
- Tu parle de puissance mais je pense que le terme approprié est complète.
- Lourd.
- Général donc non optimisé pour une utilisation précise, exemple :
Un jeu du type FPS va utiliser des finit state command qui doivent être envoyé a un certain tick rate donc tu dois mettre en place un système de packet stack que tu envoie tout les x secondes de plus il faut choisir TCP ou UDP ou même raw !
Un jeu mmorpg va fait autant d'update que possible et donc va avoir besoin d'un système qui permet de synchroniser histoire que les joueurs qui ont 300fps ne soit pas favoriser par rapport a ceux qui sont a 60 fps...
Donc il vaut mieu coder ses propre lib pour avoir un controle total et une optimisation des systeme.
Pour ceux qui sont intéréssé par les "gros" serveur mmorpg du type serveur de WoW je suis entrain de faire un tutoriel dessus, avec un peu d'aide de hardcpp quand j'oublie d'expliquer parce que j'ai tendance a être très bref...
Dernière modification par yamashi (06-01-2009 05:25:09)
Hors ligne
Et pour ceux qui veulent voir un serveur mmorpg qui peux tenir des dizaines de milliers de joueurs en simultané avec des possibilités énormes, téléchargez le code source de runuo. www.runuo.com (C'est du c#).
Hors ligne
Le C# c'est pas le mieu pour faire tourner un serveur...
Hors ligne
yamashi :
Le C# c'est pas le mieu pour faire tourner un serveur...
Ben, comme ils n'étaient pas au courant, ils l'ont fait quand même et je connais peu de serveur open source et amateur, tout langages confondu, qui soit non seulement fonctionnel mais en plus arrive a supporter des charges de dizaines de milliers de connexions simultanées.
Et quand on connait ultima online et les énormes possibilités de jeu, la quantité faramineuse d'actions possibles, le fait que les serveurs en production gèrent des centaines de milliers de monstres, d'items, de compagnons, etc, etc... Ben... (Je parle des serveurs qui utilisent runuo).
EAGame propose souvent le téléchargement gratuit du client de son jeu, et accepte l'existence des serveurs comme runuo. Donc pourquoi ne pas tester et te faire une idée ?
Ce serveur, runuo, quand j'ai regardé son source, a donné une claque sévère a mes idées reçues.
J'en suis a penser que le c# est justement le meilleur langage pour faire tourner un serveur mmorpg.
Hors ligne
pourquoi pas l"asm tant qua faire
Hors ligne