[reseau] Gestion multi-thread

Proposé par maitrelame12545

le 04 March 2007 à 03h 01mn 40s

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

 
#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
#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
#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 10:49:21

khayyam
Membres
Date d'inscription:
Messages: 25
IP: 90.13.179.126
Courriel  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/cpp/multithreads/

Hors ligne


#2 

04-03-2007 16:45:35

maitrelame12545
Membres
Avatar de maitrelame12545
Date d'inscription:
Messages: 51
IP: 76.80.53.159
Courriel

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+

Hors ligne


#3 

10-10-2009 12:41:47

TUpac
Membres
Avatar de TUpac
Date d'inscription:
Messages: 387
IP: 88.168.3.38
Courriel

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().

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Préférences cookies
Corrections
irrlicht
irrklang
irredit
irrxml
Propulsé par Django
xhtml 1.0
css 2.1
884 membres
1440 sujets
11337 messages
Dernier membre inscrit: Saidov17
160 invités en ligne
membre en ligne: -
RSS Feed