[reseau] Gestion multi-thread
Proposé par maitrelame12545

le dimanche 04 mars 2007 à 04h 01mn 40s

5890 visualisations



Bonjour !
J'aimerais vous introduire a la creation d'un serveur multi-thread avec winsock2.

Je vais essayer d'etre le plus clair possible !

Tout d'abord cree un projet sous votre compilateur.
Vous devez linker la lib : ibws2_32.apour que cela marche.

voici le main :

Code:

 
#include "serveur.h" 
#include <iostream> 
 
using namespace std;

int main()
{
//on cree le serveur et nous gerons les erreurs
    serveur *MyServer = new serveur(1000);
    if(MyServer->init()!=0){
        cerr << "ne peut initialiser le serveur"<< endl;
        return 1;
    }
 //On lance le serveur afin d'attendre les connexions et aussi gerer les fonctions des clients
    if(MyServer->start()!=0){
        cerr << "ne peut demarrer le serveur"<< endl;
        return 1;
    }
    
    return 0;
}

serveur.cpp

Code:

#include <winsock2.h>//On link winsock
#include "serveur.h"

#define _MAX_HOST_LENGTH_ 100
//taille maximum de l'adresse du serveur


serveur::serveur(int p){
    port    = p;
    running    = false;
}

int serveur::init(){
    struct in_addr  MyAddress;//Votre ip
    struct hostent  *host;
    char HostName[_MAX_HOST_LENGTH_];//Le nom sous lequel vous serez identifier
    WSADATA          wsaData;
//WSADATA correspond a tous les paramettre du serveur


//Si l'initialisation des paramettre echoue on quitte
    if(WSAStartup(MAKEWORD(2,2), &wsaData ) != 0 )
        {
        cerr <<"WSAStartup a echoue "<< endl;
        return 1;
    }
//Si la fonction qui permet de connaitre votre ip echoue on quitte
    if( gethostname( HostName, _MAX_HOST_LENGTH_ ) == SOCKET_ERROR ){
        cerr<< "gethostname() a rencontre l'erreur "<< WSAGetLastError()  << endl;
        return 1;
    }
//Si le nom de l'hote ne peut pas etre trouver on quitte
    if( (host = gethostbyname( HostName ) ) == NULL){
        cerr <<"gethostbyname() a rencontre l'erreur "<< WSAGetLastError()<< endl;
        return 1;
    }

    memcpy( &MyAddress.s_addr, host->h_addr_list[0], sizeof( MyAddress.s_addr ) );
//On met en memoire l'hote, et l'ip du serveur

    ServerAddr.sin_family = AF_INET;//L'adresse du serveur
    ServerAddr.sin_port = htons( port );//Le port du serveur
    ServerAddr.sin_addr.s_addr = inet_addr( inet_ntoa( MyAddress ) );
//Les paramettre hostName et IP

    cout <<"Serveur correctement initialise" << endl;
    return 0;
}

//Fonction de lancement
int serveur::start (){
    SOCKADDR_IN            ClientAddr;// Adresse du client
    int                              ClientAddrLen; // Taille de don adresse
    HANDLE                      hProcessThread; //Processus du client
    SOCKET                      NewConnection; // Nouvelle connexion
    struct thread_param         p;//Strucure dans serveur.h

     initMysql();//J'utilise l'api mysql donc j'utilise ma fonction d'initialisation.
//Vous devez l'enlevez dans vos programme car c'est une fonction personaliser

    if( ( ListeningSocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ){
        cerr << "ne peut creer la socket. Erreur n° " << WSAGetLastError()<< endl;
        WSACleanup();
        return 1;
    }//Si le socket du client est invalid ou contient un mauvais paramettre on vide les paramettre et on tue la connexion

    if( bind( ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof( ServerAddr ) ) == SOCKET_ERROR ){
        cerr << "bind a echoue avec l'erreur " << WSAGetLastError() << endl;
        cerr << "Le port est peut-etre deja utilise par un autre processus " << endl;
        closesocket( ListeningSocket );
        WSACleanup();
        return 1;
    }// Si les infos de connexion ne sont pas correcte on netoie et on tue la connexion

    if( listen( ListeningSocket, 5 ) == SOCKET_ERROR ){
        cerr << "listen a echoue avec l'erreur " << WSAGetLastError() << endl;
        closesocket( ListeningSocket );
        WSACleanup();
        return 1;
    }// Si l'acquistion des paramettre ou une erreur sur le flux de transmission se produit on tue la connexion

    cout << "serveur demarre : a l'ecoute du port " << port << endl;
    running = true;
//On informe sur le port ecouter
    ClientAddrLen = sizeof( ClientAddr );
//On donne la taille des adresses

    while(running){
        if((NewConnection = accept( ListeningSocket, (SOCKADDR *) &ClientAddr, &ClientAddrLen)) == INVALID_SOCKET){
            cerr  << "accept a echoue avec l'erreur " << WSAGetLastError() << endl;;
            closesocket( ListeningSocket );
            WSACleanup();
            return 1;
        }//Tant que le serveur est en route on accepte les connexion sauf si une erreur se produit

        p.ser = this;//Paramettre du serveur
        p.soc = NewConnection;//Creation du socket

        cout << "client connecte ::  IP : " <<inet_ntoa( ClientAddr.sin_addr )<< " ,port = " <<ntohs( ClientAddr.sin_port ) << endl;
// Informe de la connexion d'un client

        hProcessThread = CreateThread(NULL, 0,&serveur::ThreadLauncher, &p,0,NULL);
        if ( hProcessThread == NULL ){
            cerr << "CreateThread a echoue avec l'erreur " <<GetLastError()<< endl;
        }//on creer le processus du client
    }

    return 0;
}

int serveur::pause (){
    running = false;
    cout << "Serveur en pause" << endl;
    closesocket( ListeningSocket );
    return 0;
}

/* ======================================================================== */
/* ========================== thread proc ================================= */
/* ======================================================================== */

//Code relatif au serveur
DWORD serveur::ClientThread(SOCKET soc){
    cout << "thread client demarre" << endl;
    send(soc, "salut", 6, 0);//j'envoie un message d'acceuil
    recv(soc, buffer, sizeof(buffer), 0);//Je reois un message venant du client
//buffer est dans la classe serveur
    cout << buffer << endl;//J'affiche le buffer
       return 0;
}

serveur.h

Code:

#ifndef __serveur_h__ 
#define __serveur_h__ 

#include <winsock2.h>
#include <iostream>

using namespace std;

class serveur;

/////////////Classe paramettre des processus thread//////////////////////
struct thread_param{
       serveur* ser;
       SOCKET soc;
};


class serveur{
    private: 
        /////////////////////////////Donne sur le serveur//////////////////////////
        int           port;
        SOCKET          ListeningSocket;
        bool          running;  
        SOCKADDR_IN   ServerAddr;   
        DWORD         ClientThread(SOCKET);  
    public:                                                  
        serveur(int);
        int                 init();
        int                 start ();  
        int                 pause ();
        static DWORD WINAPI ThreadLauncher(void *p){
            struct thread_param *Obj = reinterpret_cast<struct thread_param*>(p);               
            serveur *s = Obj->ser;                          
            return s->ClientThread(Obj->soc);       
        }
        char buffer[255];

}; 



#endif

Voila j'espere que cela vous auras plus !

Prochain tuto : Un client !
suivant tuto : API MYSQL
Dernier tuto : OpenAL


#1 

04-03-2007 11:49:21

khayyam
Membre
Date d'inscription: 04-03-2007
Messages: 25
Site web

Salut,

Si déjà tu veux écrire un tuto sur les serveurs multithreads avec winsock 2 en repompant un code, essaie de mettre les infos qui vont avec pour que le tuto puisse être compris.

http://khayyam.developpez.com/articles/ … tithreads/

Hors ligne


#2 

04-03-2007 17:45:35

maitrelame12545
Membre
Date d'inscription: 28-11-2006
Messages: 51

Ton code est si bien taper que je voix pas comment faire mieu...
A part virer les les messages d'erreur difficille de faire mieu...
Je voulais te demander si tu voulais pas partciper avec moi pour faire le tuto de irrlicht.

Je viens de finir d'ecrire la partie sur les translations.

A+


Codeur elewendyl

Hors ligne


#3 

10-10-2009 14:41:47

TUpac
Habitué
Date d'inscription: 08-09-2009
Messages: 387
Corrections: 1

Bon tuto, même si c'est un peu léger pour quelqu'un qui n'a jamais touché au reseau.
En tout cas ce genre de serveur est bien utile mais il ne faut pas l'utiliser dans un projet de serveur de jeu.
En effet, pour des test ça marche bien mais c'est extrèmement gourmand en CPU.
Il vaut mieux utiliser deux ou trois threads contenant des sockets multiplexés par select().


"Si vous ne partagez pas votre stabilité avec les pauvres, les pauvres partageront leur instabilité avec vous."

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
Analysé par
872 membres
1423 sujets
11109 messages
Dernier membre inscrit: Glider
7 invités en ligne
Aucun membre connecté
RSS Feed

[ Générée en 0.092 sec., 11 requêtes exécutées ]