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
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
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
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
Pages: 1