#0 

03-01-2009 09:57:24

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

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... wink


Force et sagesse...

Hors ligne


#1 

03-01-2009 10:49:04

hardcpp
Abonné
Date d'inscription: 26-04-2008
Messages: 229

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


#2 

03-01-2009 11:01:52

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

Merci pour ta réponse. Que penses tu sinon de K-NetLib ?


Force et sagesse...

Hors ligne


#3 

03-01-2009 11:36:16

hardcpp
Abonné
Date d'inscription: 26-04-2008
Messages: 229

je connai pas dsl aufait ta ete voire le topic de mon projet (celui du mmorpg)

Hors ligne


#4 

03-01-2009 11:42:55

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

hardcpp :

... aufait ta ete voire le topic de mon projet (celui du mmorpg)


je viens de répondre wink


Force et sagesse...

Hors ligne


#5 

03-01-2009 11:47:15

hardcpp
Abonné
Date d'inscription: 26-04-2008
Messages: 229

new poste ^^

Hors ligne


#6 

03-01-2009 12:54:24

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 907
Corrections: 2
Site web

personnellement j'utilise les socket et contrairement a se que l'on dit se n'est pas si difficile que cela wink
le seul problème qui se pose est que le client est obliger de se reconnecter a la fin de la boucle du serveur .... hmm
se que je suis entrain de faire ^^

Hors ligne


#7 

03-01-2009 13:21:26

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

Merci, je vais jeter un coups d'œil wink


Force et sagesse...

Hors ligne


#8 

04-01-2009 02:40:21

yamashi
Membre
Date d'inscription: 02-01-2009
Messages: 50

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


#9 

04-01-2009 13:30:56

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 907
Corrections: 2
Site web

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

Code:

#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 hmm
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 smile

Hors ligne


#10 

04-01-2009 17:10:27

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

[    cool ça parle technique, je vais apprendre des choses wink    ]


Force et sagesse...

Hors ligne


#11 

04-01-2009 17:23:03

hardcpp
Abonné
Date d'inscription: 26-04-2008
Messages: 229

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


#12 

04-01-2009 19:15:07

yamashi
Membre
Date d'inscription: 02-01-2009
Messages: 50

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 :

Code:

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


#13 

04-01-2009 20:16:48

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 907
Corrections: 2
Site web

merci bien je vais tout refaire wink

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 ? wink
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


#14 

04-01-2009 20:27:08

yamashi
Membre
Date d'inscription: 02-01-2009
Messages: 50

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


#15 

04-01-2009 20:34:04

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 907
Corrections: 2
Site web

ohhhhh !
smile

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


#16 

05-01-2009 02:33:36

yamashi
Membre
Date d'inscription: 02-01-2009
Messages: 50

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 :

Code:

#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 :

Code:

#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


#17 

05-01-2009 06:13:57

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

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
smile


Force et sagesse...

Hors ligne


#18 

05-01-2009 22:03:03

nikska
Membre
Lieu: Montpellier
Date d'inscription: 12-05-2008
Messages: 36

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


#19 

05-01-2009 23:42:55

hardcpp
Abonné
Date d'inscription: 26-04-2008
Messages: 229

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


#20 

06-01-2009 03:37:55

yamashi
Membre
Date d'inscription: 02-01-2009
Messages: 50

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


#21 

06-01-2009 09:08:50

diOxy
Abonné
Date d'inscription: 10-10-2006
Messages: 153

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


#22 

06-01-2009 16:40:59

yamashi
Membre
Date d'inscription: 02-01-2009
Messages: 50

Le C# c'est pas le mieu pour faire tourner un serveur...

Hors ligne


#23 

06-01-2009 17:10:20

diOxy
Abonné
Date d'inscription: 10-10-2006
Messages: 153

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


#24 

06-01-2009 17:30:36

hardcpp
Abonné
Date d'inscription: 26-04-2008
Messages: 229

pourquoi pas l"asm tant qua faire

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
881 membres
1426 sujets
11116 messages
Dernier membre inscrit: Bidule
19 invités en ligne
Aucun membre connecté
RSS Feed