begin process at 2010 02 10 13:08:44
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Réseaux & Internet

 > EXEMPLE DE SERVEUR (MULTI-CLIENTS) TCP (WIN32 / VC++) (11 SEPT 2003 : MAJ)

EXEMPLE DE SERVEUR (MULTI-CLIENTS) TCP (WIN32 / VC++) (11 SEPT 2003 : MAJ)


 Information sur la source

Note :
9,5 / 10 - par 8 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Réseaux & Internet Niveau :Débutant Date de création :13/01/2003 Date de mise à jour :11/09/2003 18:15:57 Vu / téléchargé :14 881 / 854

Auteur : BlackGoddess

Ecrire un message privé
Commentaire sur cette source (55)
Ajouter un commentaire et/ou une note

 Description

ceci est donc une tite classe (faite avec vc++6 puis fini ac le 7)
pour faire un serveur TCP.
il peut accepter plusieurs clients simultanément.
on peut paramétrer le port bien sur et le nbr max de connexions.
lorsque qu'un client de connecte, se deconnecte ou envoit un message, on récupère ces infos avec une "message-queue" (SERVER::GetServerMessage)
on peut virer un client avec SERVER::Kick
voila ...    

Source

  • Network.h
  • #define SERVERSTAT_STOPPED 0
  • #define SERVERSTAT_RUNNING 1
  • #define SERVERSTAT_FATALERR 2
  • #define SERVERERR_SUCCESS 0
  • #define SERVERERR_BADCALLPARAM 1
  • #define SERVERERR_THREAD 2
  • #define SERVERERR_WS 3
  • #define MESSTYPE_RECV 1
  • #define MESSTYPE_NEW 2
  • #define MESSTYPE_QUIT 3
  • typedef struct MESSAGE
  • {
  • DWORD ClientID;
  • DWORD MessageType;
  • void* Data;
  • DWORD cbData;
  • } MESSAGE, *PMESSAGE;
  • typedef struct MESSAGENODE
  • {
  • PMESSAGE Message;
  • MESSAGENODE* pNext;
  • } MESSAGENODE, *PMESSAGENODE;
  • typedef struct CLIENT
  • {
  • DWORD ClientID;
  • HANDLE Event;
  • SOCKET Sock;
  • } CLIENT, *PCLIENT;
  • typedef struct CLIENTNODE
  • {
  • PCLIENT pClient;
  • CLIENTNODE* pNext;
  • } CLIENTNODE, *PCLIENTNODE;
  • typedef class CNetServer
  • {
  • public:
  • CNetServer(HANDLE hEventNewMess = NULL);
  • ~CNetServer(void);
  • void SetNewMessEvent(HANDLE hEvent = NULL) {hNewMess = hEvent;}
  • DWORD Start(WORD wServerPort, DWORD dwMaxConnec = 0, BOOL ResetMessQueue = TRUE);
  • DWORD Stop(BOOL DelMessQueue = FALSE);
  • PMESSAGE GetServerMessage(void); // resultat a détruire avec delete
  • BOOL Send(void* Data, DWORD cbData, DWORD ClientID = 0); // 0 pour tous
  • BOOL Kick(DWORD ClientID = 0); // 0 pour tous, utilisé a la fermeture du serveur
  • WORD GetServerPort(void);
  • DWORD GetStatus(void);
  • DWORD GetMaxConnec(void);
  • void SetMaxConnec(DWORD dwMaxConnec = 0); // 0 pour aucune limite
  • void setoptDelClientMessOnPart(BOOL opt);
  • BOOL getoptDelClientMessOnPart();
  • void setoptMessOnClientNew(BOOL opt);
  • BOOL getoptMessOnClientNew();
  • void setoptMessOnClientPart(BOOL opt);
  • BOOL getoptMessOnClientPart();
  • private:
  • DWORD Status;
  • WORD ServerPort;
  • DWORD MaxConnec;
  • void SetStatus(DWORD dwStatus);
  • // on utilise une critical section pour toutes les variables vu qu'elles ne sont
  • // pas utilisées tres fréquement
  • CRITICAL_SECTION VarCS;
  • HANDLE hNewMess;
  • // thread
  • static DWORD WINAPI ThreadEntry(CNetServer* MyServ);
  • HANDLE hThread;
  • HANDLE heThreadClose;
  • // MessQueue
  • BOOL DelClientMessOnPart;
  • BOOL MessOnClientNew;
  • BOOL MessOnClientPart;
  • BOOL AddServerMessage(PMESSAGE Message);
  • void DeleteMessageQueue(void);
  • CRITICAL_SECTION MessageQueueCS;
  • PMESSAGENODE MessageQueueFront;
  • PMESSAGENODE MessageQueueBack;
  • void DelMessID(DWORD ClientID);
  • // WS
  • SOCKET ListenSock;
  • HANDLE ListenEvent;
  • // ClientList
  • DWORD ClientCounter;
  • BOOL AddClient(PCLIENT Client);
  • void DelClient(PCLIENT Client);
  • PCLIENT GetClientByID(DWORD ClientID);
  • CRITICAL_SECTION ClientListCS;
  • PCLIENTNODE ClientList;
  • DWORD GetNextClientID(void);
  • DWORD GetNbClients(void);
  • HANDLE heClientListChange;
  • // help func
  • DWORD inline RetFatalErr(DWORD Err);
  • } CNetServer, *pCNetServer;
  • Network.cpp
  • #include <Winsock2.h>
  • #include "NetWork.h"
  • #pragma comment(lib, "Ws2_32.lib")
  • #include <float.h> // pour _logb pour les erreurs de sockets
  • #define InVarCS EnterCriticalSection(&VarCS)
  • #define OutVarCS LeaveCriticalSection(&VarCS)
  • DWORD inline CNetServer::RetFatalErr(DWORD Err)
  • {
  • SetStatus(SERVERSTAT_FATALERR);
  • return Err;
  • }
  • CNetServer::CNetServer(HANDLE hEventNewMess)
  • {
  • WSADATA wsaData;
  • WSAStartup(MAKEWORD(2,0), &wsaData);
  • InitializeCriticalSection(&VarCS);
  • InitializeCriticalSection(&MessageQueueCS);
  • InitializeCriticalSection(&ClientListCS);
  • heClientListChange = CreateEvent(NULL, FALSE, FALSE, NULL);
  • heThreadClose = CreateEvent(NULL, FALSE, FALSE, NULL);
  • hThread = NULL;
  • SetStatus(SERVERSTAT_STOPPED);
  • MessageQueueFront = NULL;
  • MessageQueueBack = NULL;
  • hNewMess = hEventNewMess;
  • ClientCounter = 0;
  • ClientList = NULL;
  • ListenSock = INVALID_SOCKET;
  • ListenEvent = NULL;
  • DelClientMessOnPart = FALSE;
  • MessOnClientNew = TRUE;
  • MessOnClientPart = TRUE;
  • }
  • CNetServer::~CNetServer(void)
  • {
  • Stop();
  • if(ListenSock != INVALID_SOCKET)
  • {
  • shutdown(ListenSock, SD_BOTH);
  • if(ListenEvent) { WSACloseEvent(ListenEvent); ListenEvent = NULL; }
  • closesocket(ListenSock);
  • ListenSock = INVALID_SOCKET;
  • }
  • Kick();
  • if(hThread)
  • {
  • TerminateThread(hThread, 0); // ceci ne devrait pas arriver
  • CloseHandle(hThread);
  • }
  • DeleteMessageQueue();
  • DeleteCriticalSection(&VarCS);
  • DeleteCriticalSection(&MessageQueueCS);
  • DeleteCriticalSection(&ClientListCS);
  • CloseHandle(heClientListChange);
  • CloseHandle(heThreadClose);
  • WSACleanup();
  • }
  • void CNetServer::setoptDelClientMessOnPart(BOOL opt)
  • {
  • InVarCS;
  • DelClientMessOnPart = opt;
  • OutVarCS;
  • }
  • BOOL CNetServer::getoptDelClientMessOnPart()
  • {
  • InVarCS;
  • BOOL ret = DelClientMessOnPart;
  • OutVarCS;
  • return ret;
  • }
  • void CNetServer::setoptMessOnClientNew(BOOL opt)
  • {
  • InVarCS;
  • MessOnClientNew = opt;
  • OutVarCS;
  • }
  • BOOL CNetServer::getoptMessOnClientNew()
  • {
  • InVarCS;
  • BOOL ret = MessOnClientNew;
  • OutVarCS;
  • return ret;
  • }
  • void CNetServer::setoptMessOnClientPart(BOOL opt)
  • {
  • InVarCS;
  • MessOnClientPart = opt;
  • OutVarCS;
  • }
  • BOOL CNetServer::getoptMessOnClientPart()
  • {
  • InVarCS;
  • BOOL ret = MessOnClientPart;
  • OutVarCS;
  • return ret;
  • }
  • WORD CNetServer::GetServerPort(void)
  • {
  • InVarCS;
  • WORD ret = ServerPort;
  • OutVarCS;
  • return ret;
  • }
  • DWORD CNetServer::GetStatus(void)
  • {
  • InVarCS;
  • DWORD ret = Status;
  • OutVarCS;
  • return ret;
  • }
  • DWORD CNetServer::GetMaxConnec(void)
  • {
  • InVarCS;
  • DWORD ret = MaxConnec;
  • OutVarCS;
  • return ret;
  • }
  • void CNetServer::SetMaxConnec(DWORD dwMaxConnec)
  • {
  • InVarCS;
  • MaxConnec = dwMaxConnec;
  • OutVarCS;
  • }
  • void CNetServer::SetStatus(DWORD dwStatus)
  • {
  • InVarCS;
  • Status = dwStatus;
  • OutVarCS;
  • }
  • DWORD CNetServer::Start(WORD wServerPort, DWORD dwMaxConnec, BOOL ResetMessQueue)
  • {
  • if(GetStatus() != SERVERSTAT_STOPPED) return SERVERERR_BADCALLPARAM;
  • if(ResetMessQueue) DeleteMessageQueue();
  • InVarCS;
  • ServerPort = wServerPort;
  • MaxConnec = dwMaxConnec;
  • OutVarCS;
  • ListenSock = socket(AF_INET,SOCK_STREAM,0);
  • if(ListenSock==INVALID_SOCKET) return RetFatalErr(SERVERERR_WS);
  • sockaddr_in sain;
  • sain.sin_family = AF_INET;
  • sain.sin_port = htons(ServerPort);
  • sain.sin_addr.s_addr = INADDR_ANY;
  • if(bind(ListenSock, (struct sockaddr *) &sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR) return RetFatalErr(SERVERERR_WS);
  • if (listen(ListenSock, SOMAXCONN)==SOCKET_ERROR) return RetFatalErr(SERVERERR_WS);
  • ListenEvent = WSACreateEvent();
  • WSAEventSelect(ListenSock, ListenEvent, FD_ACCEPT);
  • // on crée le thread de messages
  • DWORD ThreadId;
  • hThread = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)ThreadEntry, this, 0, &ThreadId);
  • if(hThread == NULL) return RetFatalErr(SERVERERR_THREAD);
  • SetStatus(SERVERSTAT_RUNNING);
  • return SERVERERR_SUCCESS;
  • }
  • DWORD CNetServer::Stop(BOOL DelMessQueue)
  • {
  • if(GetStatus() != SERVERSTAT_RUNNING) return SERVERERR_BADCALLPARAM;
  • // on ferme le thread de messages
  • SetEvent(heThreadClose);
  • if(WaitForSingleObject(hThread, 5000) == WAIT_TIMEOUT) TerminateThread(hThread, 0);
  • CloseHandle(hThread);
  • hThread = NULL;
  • // on ferme les sockets
  • shutdown(ListenSock, SD_BOTH);
  • WSACloseEvent(ListenEvent);
  • ListenEvent = NULL;
  • closesocket(ListenSock);
  • ListenSock = INVALID_SOCKET;
  • Kick();
  • if(DelMessQueue) DeleteMessageQueue();
  • SetStatus(SERVERSTAT_STOPPED);
  • return SERVERERR_SUCCESS;
  • }
  • BOOL CNetServer::Send(void* Data, DWORD cbData, DWORD ClientID)
  • {
  • DWORD dwStatus = GetStatus();
  • if(dwStatus == SERVERSTAT_FATALERR) return FALSE;
  • if(dwStatus == SERVERSTAT_STOPPED) return FALSE;
  • if(Data == NULL) return FALSE;
  • if(cbData < 1) return FALSE;
  • int SizeOpt;
  • DWORD cbMaxSize;
  • SizeOpt = sizeof(cbMaxSize);
  • getsockopt(ListenSock, SOL_SOCKET, SO_RCVBUF, (char*)&(cbMaxSize), &SizeOpt);
  • if(cbData > cbMaxSize) return FALSE;
  • PCLIENT Client;
  • BOOL bRet = TRUE;
  • if(ClientID == 0)
  • {
  • EnterCriticalSection(&ClientListCS);
  • for(PCLIENTNODE CurNode = ClientList; CurNode != NULL; CurNode = CurNode->pNext)
  • if(send(CurNode->pClient->Sock, (char*)Data, cbData, 0) == SOCKET_ERROR) bRet = FALSE;
  • LeaveCriticalSection(&ClientListCS);
  • } else {
  • Client = GetClientByID(ClientID);
  • if(Client == NULL) return FALSE;
  • EnterCriticalSection(&ClientListCS);
  • if(send(Client->Sock, (char*)Data, cbData, 0) == SOCKET_ERROR) bRet = FALSE;
  • LeaveCriticalSection(&ClientListCS);
  • }
  • return bRet;
  • }
  • BOOL CNetServer::Kick(DWORD ClientID)
  • {
  • PCLIENT Client;
  • BOOL bRet = TRUE;
  • if(ClientID == 0)
  • {
  • EnterCriticalSection(&ClientListCS);
  • for(PCLIENTNODE CurNode = ClientList; CurNode != NULL; CurNode = CurNode->pNext)
  • {
  • shutdown(CurNode->pClient->Sock, SD_BOTH);
  • WSACloseEvent(CurNode->pClient->Event);
  • closesocket(CurNode->pClient->Sock);
  • DelClient(CurNode->pClient);
  • }
  • LeaveCriticalSection(&ClientListCS);
  • } else {
  • Client = GetClientByID(ClientID);
  • if(Client == NULL) return FALSE;
  • EnterCriticalSection(&ClientListCS);
  • shutdown(Client->Sock, SD_BOTH);
  • WSACloseEvent(Client->Event);
  • closesocket(Client->Sock);
  • DelClient(Client);
  • LeaveCriticalSection(&ClientListCS);
  • }
  • return bRet;
  • }
  • // MessageQueue
  • BOOL CNetServer::AddServerMessage(PMESSAGE Message)
  • {
  • EnterCriticalSection(&MessageQueueCS);
  • if(MessageQueueFront == NULL)
  • {
  • MessageQueueFront = new MESSAGENODE;
  • MessageQueueFront->Message = Message;
  • MessageQueueFront->pNext = NULL;
  • MessageQueueBack = NULL;
  • }
  • else if(MessageQueueFront->pNext == NULL)
  • {
  • MessageQueueBack = new MESSAGENODE;
  • MessageQueueBack->Message = Message;
  • MessageQueueBack->pNext = NULL;
  • MessageQueueFront->pNext = MessageQueueBack;
  • } else {
  • PMESSAGENODE NewNode = new MESSAGENODE;
  • NewNode->Message = Message;
  • NewNode->pNext = NULL;
  • MessageQueueBack->pNext = NewNode;
  • MessageQueueBack = NewNode;
  • }
  • LeaveCriticalSection(&MessageQueueCS);
  • if(hNewMess) SetEvent(hNewMess);
  • return TRUE;
  • }
  • PMESSAGE CNetServer::GetServerMessage(void)
  • {
  • EnterCriticalSection(&MessageQueueCS);
  • PMESSAGENODE pRetNode;
  • if(MessageQueueFront == NULL)
  • {
  • pRetNode = NULL;
  • } else {
  • pRetNode = MessageQueueFront;
  • MessageQueueFront = pRetNode->pNext;
  • if(MessageQueueFront == NULL)
  • {
  • MessageQueueBack = NULL;
  • } else if(MessageQueueFront->pNext == NULL)
  • {
  • MessageQueueBack = NULL;
  • }
  • }
  • LeaveCriticalSection(&MessageQueueCS);
  • if(pRetNode == NULL) return NULL;
  • PMESSAGE pRet = pRetNode->Message;
  • delete pRetNode;
  • return pRet;
  • }
  • void CNetServer::DeleteMessageQueue(void)
  • {
  • PMESSAGE pMess;
  • while((pMess = GetServerMessage()) != NULL)
  • {
  • if(pMess->Data && pMess->cbData) delete[] pMess->Data;
  • delete pMess;
  • }
  • }
  • void CNetServer::DelMessID(DWORD ClientID)
  • {
  • EnterCriticalSection(&MessageQueueCS);
  • PMESSAGENODE pMessNode;
  • PMESSAGENODE pTmpNode;
  • // tant que le 1er convient
  • while(MessageQueueFront)
  • {
  • if(MessageQueueFront->Message->ClientID == ClientID)
  • {
  • if(MessageQueueFront->Message->Data && MessageQueueFront->Message->cbData) delete[] MessageQueueFront->Message->Data;
  • delete MessageQueueFront->Message;
  • MessageQueueFront = MessageQueueFront->pNext;
  • if(MessageQueueFront == NULL)
  • {
  • // il y avait qu'un message
  • MessageQueueBack = NULL;
  • LeaveCriticalSection(&MessageQueueCS);
  • return;
  • }
  • } else break;
  • }
  • if(MessageQueueFront)
  • {
  • // on parcourt le queue de message
  • for(pMessNode = MessageQueueFront; pMessNode->pNext != NULL; pMessNode = pMessNode->pNext)
  • {
  • if(pMessNode->pNext->Message->ClientID == ClientID)
  • {
  • pTmpNode = pMessNode->pNext;
  • pMessNode->pNext = pMessNode->pNext->pNext;
  • if(pTmpNode->Message->Data && pTmpNode->Message->cbData) delete[] pTmpNode->Message->Data;
  • delete pTmpNode->Message;
  • delete pTmpNode;
  • if(pMessNode->pNext == NULL) // c t le dernier
  • {
  • MessageQueueBack = pMessNode;
  • LeaveCriticalSection(&MessageQueueCS);
  • return;
  • }
  • }
  • }
  • }
  • LeaveCriticalSection(&MessageQueueCS);
  • }
  • // ClientList
  • // !!! ATTENTION !!! il faut owner la ClientListCS avant d'appeler cette fonction !!!
  • BOOL CNetServer::AddClient(PCLIENT Client)
  • {
  • PCLIENTNODE NewNode = new CLIENTNODE;
  • NewNode->pClient = Client;
  • NewNode->pNext = ClientList;
  • ClientList = NewNode;
  • SetEvent(heClientListChange);
  • return TRUE;
  • }
  • // !!! ATTENTION !!! il faut owner la ClientListCS avant d'appeler cette fonction !!!
  • void CNetServer::DelClient(PCLIENT Client)
  • {
  • // si c le 1er
  • if(ClientList == NULL)
  • return;
  • if(!memcmp(ClientList->pClient, Client, sizeof(CLIENT)))
  • {
  • PCLIENTNODE DelNode = ClientList;
  • ClientList = ClientList->pNext;
  • delete DelNode->pClient;
  • delete DelNode;
  • SetEvent(heClientListChange);
  • return;
  • }
  • // si c le 2eme et plus
  • PCLIENTNODE CurNode = ClientList;
  • while(CurNode->pNext != NULL)
  • {
  • if(!memcmp(CurNode->pNext->pClient, Client, sizeof(CLIENT)))
  • {
  • PCLIENTNODE DelNode = ClientList->pNext;
  • CurNode->pNext = CurNode->pNext->pNext;
  • delete DelNode->pClient;
  • delete DelNode;
  • SetEvent(heClientListChange);
  • break;
  • }
  • CurNode = CurNode->pNext;
  • }
  • }
  • PCLIENT CNetServer::GetClientByID(DWORD ClientID)
  • {
  • EnterCriticalSection(&ClientListCS);
  • PCLIENT pRet = NULL;
  • PCLIENTNODE CurNode = ClientList;
  • while(CurNode != NULL)
  • {
  • if(CurNode->pClient->ClientID == ClientID)
  • {
  • pRet = new CLIENT;
  • if(pRet == NULL)
  • {
  • LeaveCriticalSection(&ClientListCS);
  • return NULL;
  • }
  • memcpy(pRet, CurNode->pClient, sizeof(CLIENT));
  • break;
  • }
  • CurNode = CurNode->pNext;
  • }
  • LeaveCriticalSection(&ClientListCS);
  • return pRet;
  • }
  • DWORD CNetServer::GetNextClientID(void)
  • {
  • EnterCriticalSection(&ClientListCS);
  • ClientCounter++;
  • DWORD dwRet = ClientCounter;
  • LeaveCriticalSection(&ClientListCS);
  • return ClientCounter;
  • }
  • DWORD CNetServer::GetNbClients(void)
  • {
  • DWORD i = 0;
  • EnterCriticalSection(&ClientListCS);
  • for(PCLIENTNODE CurNode = ClientList; CurNode !=NULL; CurNode = CurNode->pNext) i++;
  • LeaveCriticalSection(&ClientListCS);
  • return i;
  • }
  • DWORD WINAPI CNetServer::ThreadEntry(CNetServer* MyServ)
  • {
  • WSANETWORKEVENTS EventResult;
  • PCLIENT Client;
  • DWORD ClientID;
  • PMESSAGE Message;
  • PCLIENTNODE CurNode;
  • int SizeOpt;
  • char* RecvDataBuf;
  • DWORD cbRecvDataBuf;
  • HANDLE* TabEvents;
  • int cbTabEvents;
  • int i;
  • DWORD WaitRes;
  • bool bMustClose = false;
  • while(!bMustClose)
  • {
  • // on construit le tableau des evenements a attendre
  • cbTabEvents = 3;
  • EnterCriticalSection(&MyServ->ClientListCS);
  • for(CurNode = MyServ->ClientList; CurNode != NULL; CurNode = CurNode->pNext)
  • cbTabEvents++;
  • TabEvents = new HANDLE[cbTabEvents];
  • i=3;
  • for(CurNode = MyServ->ClientList; CurNode != NULL; CurNode = CurNode->pNext)
  • {
  • TabEvents[i] = CurNode->pClient->Event;
  • i++;
  • }
  • LeaveCriticalSection(&MyServ->ClientListCS);
  • TabEvents[0] = MyServ->heThreadClose;
  • TabEvents[1] = MyServ->heClientListChange;
  • TabEvents[2] = MyServ->ListenEvent;
  • WaitRes = WSAWaitForMultipleEvents(cbTabEvents, TabEvents, FALSE, WSA_INFINITE, FALSE);
  • delete TabEvents;
  • switch(WaitRes)
  • {
  • case WSA_WAIT_EVENT_0:
  • {
  • bMustClose = true;
  • }
  • break;
  • case WSA_WAIT_EVENT_0+1:
  • // on fait rien, c t juste pour rafraichir la liste des evenements a attendre
  • break;
  • case WSA_WAIT_EVENT_0+2:
  • {
  • WSAEnumNetworkEvents(MyServ->ListenSock, MyServ->ListenEvent, &EventResult);
  • if(EventResult.lNetworkEvents == FD_ACCEPT)
  • {
  • if( (!(MyServ->GetNbClients() > MyServ->GetMaxConnec())) | (MyServ->GetMaxConnec() == 0) )
  • {
  • Client = new CLIENT;
  • ClientID = MyServ->GetNextClientID();
  • Client->ClientID = ClientID;
  • Client->Sock = accept(MyServ->ListenSock, NULL, NULL);
  • Client->Event = WSACreateEvent();
  • WSAEventSelect(Client->Sock, Client->Event, FD_READ | FD_CLOSE);
  • MyServ->AddClient(Client);
  • if(MyServ->getoptMessOnClientNew())
  • {
  • Message = new MESSAGE;
  • Message->ClientID = ClientID;
  • Message->MessageType = MESSTYPE_NEW;
  • Message->cbData = 0;
  • Message->Data = NULL;
  • MyServ->AddServerMessage(Message);
  • }
  • }
  • }
  • }
  • break;
  • default:
  • {
  • // on récupère le client en question
  • i=3;
  • for(CurNode = MyServ->ClientList; CurNode != NULL; CurNode = CurNode->pNext)
  • {
  • if(WSA_WAIT_EVENT_0+i == WaitRes)
  • break;
  • else
  • i++;
  • }
  • WSAEnumNetworkEvents(CurNode->pClient->Sock, CurNode->pClient->Event, &EventResult);
  • switch(EventResult.lNetworkEvents)
  • {
  • case FD_READ:
  • {
  • if (EventResult.iErrorCode[(int) _logb(EventResult.lNetworkEvents)]) // erreur
  • {
  • WSACloseEvent(CurNode->pClient->Event);
  • closesocket(CurNode->pClient->Sock);
  • ClientID = CurNode->pClient->ClientID;
  • MyServ->DelClient(CurNode->pClient);
  • if(MyServ->getoptDelClientMessOnPart()) MyServ->DelMessID(ClientID);
  • if(MyServ->getoptMessOnClientPart())
  • {
  • Message = new MESSAGE;
  • Message->ClientID = ClientID;
  • Message->MessageType = MESSTYPE_QUIT;
  • Message->cbData = 0;
  • Message->Data = NULL;
  • MyServ->AddServerMessage(Message);
  • }
  • } else {
  • Message = new MESSAGE;
  • SizeOpt = sizeof(cbRecvDataBuf);
  • getsockopt(CurNode->pClient->Sock, SOL_SOCKET, SO_RCVBUF, (char*)&(cbRecvDataBuf), &SizeOpt);
  • RecvDataBuf = new char[cbRecvDataBuf];
  • if((Message->cbData = recv(CurNode->pClient->Sock, RecvDataBuf, cbRecvDataBuf, 0)) == SOCKET_ERROR) {MyServ->Status = SERVERSTAT_FATALERR; return 0;}
  • Message->Data = (void*)new char[Message->cbData];
  • memcpy(Message->Data, RecvDataBuf, Message->cbData);
  • Message->ClientID = CurNode->pClient->ClientID;
  • Message->MessageType = MESSTYPE_RECV;
  • MyServ->AddServerMessage(Message);
  • }
  • }
  • break;
  • case FD_CLOSE:
  • {
  • WSACloseEvent(CurNode->pClient->Event);
  • closesocket(CurNode->pClient->Sock);
  • ClientID = CurNode->pClient->ClientID;
  • MyServ->DelClient(CurNode->pClient);
  • if(MyServ->getoptDelClientMessOnPart()) MyServ->DelMessID(ClientID);
  • if(MyServ->getoptMessOnClientPart())
  • {
  • Message = new MESSAGE;
  • Message->ClientID = ClientID;
  • Message->MessageType = MESSTYPE_QUIT;
  • Message->cbData = 0;
  • Message->Data = NULL;
  • MyServ->AddServerMessage(Message);
  • }
  • }
  • break;
  • }
  • }
  • break;
  • } // switch
  • } // while
  • return 0;
  • }
Network.h

#define SERVERSTAT_STOPPED			0
#define SERVERSTAT_RUNNING			1
#define SERVERSTAT_FATALERR			2

#define SERVERERR_SUCCESS			0
#define SERVERERR_BADCALLPARAM		1
#define SERVERERR_THREAD			2
#define SERVERERR_WS				3

#define MESSTYPE_RECV				1
#define MESSTYPE_NEW				2
#define MESSTYPE_QUIT				3

typedef struct MESSAGE
{
	DWORD ClientID;
	DWORD MessageType;
	void* Data;
	DWORD cbData;
} MESSAGE, *PMESSAGE;

typedef struct MESSAGENODE
{
	PMESSAGE Message;
	MESSAGENODE* pNext;
} MESSAGENODE, *PMESSAGENODE;

typedef struct CLIENT
{
	DWORD ClientID;
	HANDLE Event;
	SOCKET Sock;
} CLIENT, *PCLIENT;

typedef struct CLIENTNODE
{
	PCLIENT pClient;
	CLIENTNODE* pNext;
} CLIENTNODE, *PCLIENTNODE;

typedef class CNetServer
{
public:

	CNetServer(HANDLE hEventNewMess = NULL);
	~CNetServer(void);

	void SetNewMessEvent(HANDLE hEvent = NULL) {hNewMess = hEvent;}
	
	DWORD Start(WORD wServerPort, DWORD dwMaxConnec = 0, BOOL ResetMessQueue = TRUE);
	DWORD Stop(BOOL DelMessQueue = FALSE);

	PMESSAGE GetServerMessage(void); // resultat a détruire avec delete
	BOOL Send(void* Data, DWORD cbData, DWORD ClientID = 0); // 0 pour tous
	BOOL Kick(DWORD ClientID = 0); // 0 pour tous, utilisé a la fermeture du serveur

	WORD GetServerPort(void);
	DWORD GetStatus(void);
	DWORD GetMaxConnec(void);
	void SetMaxConnec(DWORD dwMaxConnec = 0); // 0 pour aucune limite

	void setoptDelClientMessOnPart(BOOL opt);
	BOOL getoptDelClientMessOnPart();
	void setoptMessOnClientNew(BOOL opt);
	BOOL getoptMessOnClientNew();
	void setoptMessOnClientPart(BOOL opt);
	BOOL getoptMessOnClientPart();

private:
	DWORD Status;
	WORD ServerPort;
	DWORD MaxConnec;

	void SetStatus(DWORD dwStatus);

	// on utilise une critical section pour toutes les variables vu qu'elles ne sont
	// pas utilisées tres fréquement
	CRITICAL_SECTION VarCS;

	HANDLE hNewMess;

	// thread
	static DWORD WINAPI ThreadEntry(CNetServer* MyServ);
	HANDLE hThread;
	HANDLE heThreadClose;

	// MessQueue
	BOOL DelClientMessOnPart;
	BOOL MessOnClientNew;
	BOOL MessOnClientPart;

	BOOL AddServerMessage(PMESSAGE Message);
	void DeleteMessageQueue(void);
	CRITICAL_SECTION MessageQueueCS;
	PMESSAGENODE MessageQueueFront;
	PMESSAGENODE MessageQueueBack;
	void DelMessID(DWORD ClientID);
	
	// WS
	SOCKET ListenSock;
	HANDLE ListenEvent;
	
	// ClientList
	DWORD ClientCounter;
	BOOL AddClient(PCLIENT Client);
	void DelClient(PCLIENT Client);
	PCLIENT GetClientByID(DWORD ClientID);
	CRITICAL_SECTION ClientListCS;
	PCLIENTNODE ClientList;
	DWORD GetNextClientID(void);
	DWORD GetNbClients(void);
	HANDLE heClientListChange;

	// help func
	DWORD inline RetFatalErr(DWORD Err);

} CNetServer, *pCNetServer;

Network.cpp

#include <Winsock2.h>
#include "NetWork.h"
#pragma comment(lib, "Ws2_32.lib")
#include <float.h> // pour _logb pour les erreurs de sockets

#define InVarCS EnterCriticalSection(&VarCS)
#define OutVarCS LeaveCriticalSection(&VarCS)

DWORD inline CNetServer::RetFatalErr(DWORD Err)
{
	SetStatus(SERVERSTAT_FATALERR);
	return Err;
}

CNetServer::CNetServer(HANDLE hEventNewMess)
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,0), &wsaData);

	InitializeCriticalSection(&VarCS);
	InitializeCriticalSection(&MessageQueueCS);
	InitializeCriticalSection(&ClientListCS);
	heClientListChange = CreateEvent(NULL, FALSE, FALSE, NULL);
	heThreadClose = CreateEvent(NULL, FALSE, FALSE, NULL);
	hThread = NULL;

	SetStatus(SERVERSTAT_STOPPED);

	MessageQueueFront = NULL;
	MessageQueueBack = NULL;
	hNewMess = hEventNewMess;

	ClientCounter = 0;
	ClientList = NULL;

	ListenSock = INVALID_SOCKET;
	ListenEvent = NULL;

	DelClientMessOnPart = FALSE;
	MessOnClientNew = TRUE;
	MessOnClientPart = TRUE;

}

CNetServer::~CNetServer(void)
{
	Stop();

	if(ListenSock != INVALID_SOCKET)
	{
		shutdown(ListenSock, SD_BOTH);
		if(ListenEvent) { WSACloseEvent(ListenEvent); ListenEvent = NULL; }
		closesocket(ListenSock);
		ListenSock = INVALID_SOCKET;
	}

	Kick();

	if(hThread)
	{
		TerminateThread(hThread, 0); // ceci ne devrait pas arriver
		CloseHandle(hThread);
	}

	DeleteMessageQueue();

	DeleteCriticalSection(&VarCS);
	DeleteCriticalSection(&MessageQueueCS);
	DeleteCriticalSection(&ClientListCS);
	CloseHandle(heClientListChange);
	CloseHandle(heThreadClose);

	WSACleanup();
}

void CNetServer::setoptDelClientMessOnPart(BOOL opt)
{
	InVarCS;
	DelClientMessOnPart = opt;
	OutVarCS;
}

BOOL CNetServer::getoptDelClientMessOnPart()
{
	InVarCS;
	BOOL ret = DelClientMessOnPart;
	OutVarCS;
	return ret;
}

void CNetServer::setoptMessOnClientNew(BOOL opt)
{
	InVarCS;
	MessOnClientNew = opt;
	OutVarCS;
}

BOOL CNetServer::getoptMessOnClientNew()
{
	InVarCS;
	BOOL ret = MessOnClientNew;
	OutVarCS;
	return ret;
}

void CNetServer::setoptMessOnClientPart(BOOL opt)
{
	InVarCS;
	MessOnClientPart = opt;
	OutVarCS;
}

BOOL CNetServer::getoptMessOnClientPart()
{
	InVarCS;
	BOOL ret = MessOnClientPart;
	OutVarCS;
	return ret;
}

WORD CNetServer::GetServerPort(void)
{
	InVarCS;
	WORD ret = ServerPort;
	OutVarCS;
	return ret;
}

DWORD CNetServer::GetStatus(void)
{
	InVarCS;
	DWORD ret = Status;
	OutVarCS;
	return ret;
}

DWORD CNetServer::GetMaxConnec(void)
{
	InVarCS;
	DWORD ret = MaxConnec;
	OutVarCS;
	return ret;
}
void CNetServer::SetMaxConnec(DWORD dwMaxConnec)
{
	InVarCS;
	MaxConnec = dwMaxConnec;
	OutVarCS;
}

void CNetServer::SetStatus(DWORD dwStatus)
{
	InVarCS;
	Status = dwStatus;
	OutVarCS;
}

DWORD CNetServer::Start(WORD wServerPort, DWORD dwMaxConnec, BOOL ResetMessQueue)
{
	if(GetStatus() != SERVERSTAT_STOPPED) return SERVERERR_BADCALLPARAM;

	if(ResetMessQueue) DeleteMessageQueue();
	
	InVarCS;
	ServerPort = wServerPort;
	MaxConnec = dwMaxConnec;
	OutVarCS;

    ListenSock = socket(AF_INET,SOCK_STREAM,0);
    if(ListenSock==INVALID_SOCKET) return RetFatalErr(SERVERERR_WS);
    
    sockaddr_in sain;
    sain.sin_family = AF_INET;
    sain.sin_port = htons(ServerPort);
    sain.sin_addr.s_addr = INADDR_ANY;

    if(bind(ListenSock, (struct sockaddr *) &sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR) return RetFatalErr(SERVERERR_WS);
    if (listen(ListenSock, SOMAXCONN)==SOCKET_ERROR) return RetFatalErr(SERVERERR_WS);

	ListenEvent = WSACreateEvent();
	WSAEventSelect(ListenSock, ListenEvent, FD_ACCEPT);

	// on crée le thread de messages
	DWORD ThreadId;
	hThread = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)ThreadEntry, this, 0, &ThreadId);
	if(hThread == NULL) return RetFatalErr(SERVERERR_THREAD);

	SetStatus(SERVERSTAT_RUNNING);

	return SERVERERR_SUCCESS;
}

DWORD CNetServer::Stop(BOOL DelMessQueue)
{
	if(GetStatus() != SERVERSTAT_RUNNING) return SERVERERR_BADCALLPARAM;

	// on ferme le thread de messages
	SetEvent(heThreadClose);
	if(WaitForSingleObject(hThread, 5000) == WAIT_TIMEOUT) TerminateThread(hThread, 0);
	CloseHandle(hThread);
	hThread = NULL;

	// on ferme les sockets
	shutdown(ListenSock, SD_BOTH);
	WSACloseEvent(ListenEvent);
	ListenEvent = NULL;
	closesocket(ListenSock);
	ListenSock = INVALID_SOCKET;

	Kick();

	if(DelMessQueue) DeleteMessageQueue();

	SetStatus(SERVERSTAT_STOPPED);

	return SERVERERR_SUCCESS;
}

BOOL CNetServer::Send(void* Data, DWORD cbData, DWORD ClientID)
{
	DWORD dwStatus = GetStatus();
	if(dwStatus == SERVERSTAT_FATALERR) return FALSE;
	if(dwStatus == SERVERSTAT_STOPPED) return FALSE;
	
	if(Data == NULL) return FALSE;
	if(cbData < 1) return FALSE;

	int SizeOpt;
	DWORD cbMaxSize;
	SizeOpt = sizeof(cbMaxSize);
	getsockopt(ListenSock, SOL_SOCKET, SO_RCVBUF, (char*)&(cbMaxSize), &SizeOpt);

	if(cbData > cbMaxSize) return FALSE;

	PCLIENT Client;
	BOOL bRet = TRUE;

	if(ClientID == 0)
	{
		EnterCriticalSection(&ClientListCS);
		for(PCLIENTNODE CurNode = ClientList; CurNode != NULL; CurNode = CurNode->pNext)
			if(send(CurNode->pClient->Sock, (char*)Data, cbData, 0) == SOCKET_ERROR) bRet = FALSE;
		LeaveCriticalSection(&ClientListCS);
	} else {
		Client = GetClientByID(ClientID);
		if(Client == NULL) return FALSE;

		EnterCriticalSection(&ClientListCS);
		if(send(Client->Sock, (char*)Data, cbData, 0) == SOCKET_ERROR) bRet = FALSE;
		LeaveCriticalSection(&ClientListCS);
	}
	
	return bRet;
}

BOOL CNetServer::Kick(DWORD ClientID)
{
	PCLIENT Client;
	BOOL bRet = TRUE;

	if(ClientID == 0)
	{
		EnterCriticalSection(&ClientListCS);
		for(PCLIENTNODE CurNode = ClientList; CurNode != NULL; CurNode = CurNode->pNext)
		{
			shutdown(CurNode->pClient->Sock, SD_BOTH);
			WSACloseEvent(CurNode->pClient->Event);
			closesocket(CurNode->pClient->Sock);
			DelClient(CurNode->pClient);
		}
		LeaveCriticalSection(&ClientListCS);
	} else {
		Client = GetClientByID(ClientID);
		if(Client == NULL) return FALSE;

		EnterCriticalSection(&ClientListCS);

		shutdown(Client->Sock, SD_BOTH);
		WSACloseEvent(Client->Event);
		closesocket(Client->Sock);
		DelClient(Client);

		LeaveCriticalSection(&ClientListCS);
	}
	
	return bRet;

}

// MessageQueue
BOOL CNetServer::AddServerMessage(PMESSAGE Message)
{
	EnterCriticalSection(&MessageQueueCS);

	if(MessageQueueFront == NULL)
	{
		MessageQueueFront = new MESSAGENODE;
		MessageQueueFront->Message = Message;
		MessageQueueFront->pNext = NULL;
		MessageQueueBack = NULL;
	} 
	else if(MessageQueueFront->pNext == NULL)
	{
		MessageQueueBack = new MESSAGENODE;
		MessageQueueBack->Message = Message;
		MessageQueueBack->pNext = NULL;
		MessageQueueFront->pNext = MessageQueueBack;

	} else {
		PMESSAGENODE NewNode = new MESSAGENODE;
		NewNode->Message = Message;
		NewNode->pNext = NULL;
		MessageQueueBack->pNext = NewNode;
		MessageQueueBack = NewNode;
	}

	LeaveCriticalSection(&MessageQueueCS);
	
	if(hNewMess) SetEvent(hNewMess);

	return TRUE;
}

PMESSAGE CNetServer::GetServerMessage(void)
{
	EnterCriticalSection(&MessageQueueCS);
	
	PMESSAGENODE pRetNode;

	if(MessageQueueFront == NULL)
	{
		pRetNode = NULL;
	} else {
		pRetNode = MessageQueueFront;
		MessageQueueFront = pRetNode->pNext;

		if(MessageQueueFront == NULL)
		{
			MessageQueueBack = NULL;
		} else if(MessageQueueFront->pNext == NULL)
		{
			MessageQueueBack = NULL;
		}
	}
	
	LeaveCriticalSection(&MessageQueueCS);

	if(pRetNode == NULL) return NULL;

	PMESSAGE pRet = pRetNode->Message;
	delete pRetNode;
	return pRet;
}

void CNetServer::DeleteMessageQueue(void)
{
	PMESSAGE pMess;
	while((pMess = GetServerMessage()) != NULL)
	{
		if(pMess->Data && pMess->cbData) delete[] pMess->Data;
		delete pMess;
	}
}

void CNetServer::DelMessID(DWORD ClientID)
{
	EnterCriticalSection(&MessageQueueCS);

	PMESSAGENODE pMessNode;
	PMESSAGENODE pTmpNode;
	// tant que le 1er convient
	while(MessageQueueFront)
	{
		if(MessageQueueFront->Message->ClientID == ClientID)
		{
			if(MessageQueueFront->Message->Data && MessageQueueFront->Message->cbData) delete[] MessageQueueFront->Message->Data;
			delete MessageQueueFront->Message;

			MessageQueueFront = MessageQueueFront->pNext;
			if(MessageQueueFront == NULL)
			{
				// il y avait qu'un message
				MessageQueueBack = NULL;
				LeaveCriticalSection(&MessageQueueCS);
				return;
			}
		} else break;
	}
	
	if(MessageQueueFront)
	{
		// on parcourt le queue de message
		for(pMessNode = MessageQueueFront; pMessNode->pNext != NULL; pMessNode = pMessNode->pNext)
		{
			if(pMessNode->pNext->Message->ClientID == ClientID)
			{
				pTmpNode = pMessNode->pNext;
				pMessNode->pNext = pMessNode->pNext->pNext;
	
				if(pTmpNode->Message->Data && pTmpNode->Message->cbData) delete[] pTmpNode->Message->Data;
				delete pTmpNode->Message;
				delete pTmpNode;
	
				if(pMessNode->pNext == NULL) // c t le dernier
				{
					MessageQueueBack = pMessNode;
					LeaveCriticalSection(&MessageQueueCS);
					return;
				}
			}
		}
	}

	LeaveCriticalSection(&MessageQueueCS);
}
// ClientList
// !!! ATTENTION !!! il faut owner la ClientListCS avant d'appeler cette fonction !!!
BOOL CNetServer::AddClient(PCLIENT Client)
{
	PCLIENTNODE NewNode = new CLIENTNODE;

	NewNode->pClient = Client;
	NewNode->pNext = ClientList;
	ClientList = NewNode;
	
	SetEvent(heClientListChange);

	return TRUE;
}

// !!! ATTENTION !!! il faut owner la ClientListCS avant d'appeler cette fonction !!!
void CNetServer::DelClient(PCLIENT Client)
{
	// si c le 1er
	if(ClientList == NULL) 
		return;

	if(!memcmp(ClientList->pClient, Client, sizeof(CLIENT)))
	{
		PCLIENTNODE DelNode = ClientList;
		ClientList = ClientList->pNext;
		delete DelNode->pClient;
		delete DelNode;
		SetEvent(heClientListChange);
		return;
	}
	
	// si c le 2eme et plus
	PCLIENTNODE CurNode = ClientList;
	while(CurNode->pNext != NULL)
	{
		if(!memcmp(CurNode->pNext->pClient, Client, sizeof(CLIENT)))
		{
			PCLIENTNODE DelNode = ClientList->pNext;
			CurNode->pNext = CurNode->pNext->pNext;
			delete DelNode->pClient;
			delete DelNode;
			SetEvent(heClientListChange);
			break;
		}

		CurNode = CurNode->pNext;
	}
}

PCLIENT CNetServer::GetClientByID(DWORD ClientID)
{
	EnterCriticalSection(&ClientListCS);
	
	PCLIENT pRet = NULL;

	PCLIENTNODE CurNode = ClientList;
	while(CurNode != NULL)
	{
		if(CurNode->pClient->ClientID == ClientID)
		{
			pRet = new CLIENT;
			if(pRet == NULL)
			{
				LeaveCriticalSection(&ClientListCS);
				return NULL;
			}
			memcpy(pRet, CurNode->pClient, sizeof(CLIENT));
			break;
		}

		CurNode = CurNode->pNext;
	}

	LeaveCriticalSection(&ClientListCS);

	return pRet;
}

DWORD CNetServer::GetNextClientID(void)
{
	EnterCriticalSection(&ClientListCS);
	ClientCounter++;
	DWORD dwRet = ClientCounter;
	LeaveCriticalSection(&ClientListCS);
	return ClientCounter;
}

DWORD CNetServer::GetNbClients(void)
{
	DWORD i = 0;
	EnterCriticalSection(&ClientListCS);
	for(PCLIENTNODE CurNode = ClientList; CurNode !=NULL; CurNode = CurNode->pNext) i++;
	LeaveCriticalSection(&ClientListCS);
	return i;
}

DWORD WINAPI CNetServer::ThreadEntry(CNetServer* MyServ)
{
	WSANETWORKEVENTS EventResult;
	PCLIENT Client;
	DWORD ClientID;
	PMESSAGE Message;
	PCLIENTNODE CurNode;

	int SizeOpt;
	char* RecvDataBuf;
	DWORD cbRecvDataBuf;

	HANDLE* TabEvents;
	int cbTabEvents;
	int i;
	DWORD WaitRes;

	bool bMustClose = false;
	while(!bMustClose)
	{
		// on construit le tableau des evenements a attendre
		cbTabEvents = 3;

		EnterCriticalSection(&MyServ->ClientListCS);
		
		for(CurNode = MyServ->ClientList; CurNode != NULL; CurNode = CurNode->pNext)
			cbTabEvents++;
		
		TabEvents = new HANDLE[cbTabEvents];

		i=3;
		for(CurNode = MyServ->ClientList; CurNode != NULL; CurNode = CurNode->pNext)
		{
			TabEvents[i] = CurNode->pClient->Event;
			i++;
		}

		LeaveCriticalSection(&MyServ->ClientListCS);

		TabEvents[0] = MyServ->heThreadClose;
		TabEvents[1] = MyServ->heClientListChange;
		TabEvents[2] = MyServ->ListenEvent;
		
		WaitRes = WSAWaitForMultipleEvents(cbTabEvents, TabEvents, FALSE, WSA_INFINITE, FALSE);

		delete TabEvents;

		switch(WaitRes)
		{
		case WSA_WAIT_EVENT_0:
			{
				bMustClose = true;
			}
			break;

		case WSA_WAIT_EVENT_0+1:
			// on fait rien, c t juste pour rafraichir la liste des evenements a attendre
			break;

		case WSA_WAIT_EVENT_0+2:
			{
				WSAEnumNetworkEvents(MyServ->ListenSock, MyServ->ListenEvent, &EventResult);
				if(EventResult.lNetworkEvents == FD_ACCEPT)
				{
					if( (!(MyServ->GetNbClients() > MyServ->GetMaxConnec())) | (MyServ->GetMaxConnec() == 0) )
					{
						Client = new CLIENT;
						ClientID = MyServ->GetNextClientID();
						Client->ClientID = ClientID;
						Client->Sock = accept(MyServ->ListenSock, NULL, NULL);
						Client->Event = WSACreateEvent();
						WSAEventSelect(Client->Sock, Client->Event, FD_READ | FD_CLOSE);
						MyServ->AddClient(Client);
						
						if(MyServ->getoptMessOnClientNew())
						{
							Message = new MESSAGE;
							Message->ClientID = ClientID;
							Message->MessageType = MESSTYPE_NEW;
							Message->cbData = 0;
							Message->Data = NULL;
							MyServ->AddServerMessage(Message);
						}
					}
				}
			}
			break;

		default:
			{
				// on récupère le client en question
				i=3;
				for(CurNode = MyServ->ClientList; CurNode != NULL; CurNode = CurNode->pNext)
				{
					if(WSA_WAIT_EVENT_0+i == WaitRes) 
						break;
					else
						i++;
				}

				WSAEnumNetworkEvents(CurNode->pClient->Sock, CurNode->pClient->Event, &EventResult);
				switch(EventResult.lNetworkEvents)
				{
				case FD_READ:
					{
						if (EventResult.iErrorCode[(int) _logb(EventResult.lNetworkEvents)]) // erreur
						{
							WSACloseEvent(CurNode->pClient->Event);
							closesocket(CurNode->pClient->Sock);
							ClientID = CurNode->pClient->ClientID;
							MyServ->DelClient(CurNode->pClient);
							
							if(MyServ->getoptDelClientMessOnPart()) MyServ->DelMessID(ClientID);
							
							if(MyServ->getoptMessOnClientPart())
							{
								Message = new MESSAGE;
								Message->ClientID = ClientID;
								Message->MessageType = MESSTYPE_QUIT;
								Message->cbData = 0;
								Message->Data = NULL;
								MyServ->AddServerMessage(Message);
							}
						} else {
							Message = new MESSAGE;
							SizeOpt = sizeof(cbRecvDataBuf);
							getsockopt(CurNode->pClient->Sock, SOL_SOCKET, SO_RCVBUF, (char*)&(cbRecvDataBuf), &SizeOpt);
							RecvDataBuf = new char[cbRecvDataBuf];
							if((Message->cbData = recv(CurNode->pClient->Sock, RecvDataBuf, cbRecvDataBuf, 0)) == SOCKET_ERROR) {MyServ->Status = SERVERSTAT_FATALERR; return 0;}
							Message->Data = (void*)new char[Message->cbData];
							memcpy(Message->Data, RecvDataBuf, Message->cbData);
							Message->ClientID = CurNode->pClient->ClientID;
							Message->MessageType = MESSTYPE_RECV;
							MyServ->AddServerMessage(Message);
						}
					}
					break;
				case FD_CLOSE:
					{
						WSACloseEvent(CurNode->pClient->Event);
						closesocket(CurNode->pClient->Sock);
						ClientID = CurNode->pClient->ClientID;
						MyServ->DelClient(CurNode->pClient);
						
						if(MyServ->getoptDelClientMessOnPart()) MyServ->DelMessID(ClientID);
						
						if(MyServ->getoptMessOnClientPart())
						{
							Message = new MESSAGE;
							Message->ClientID = ClientID;
							Message->MessageType = MESSTYPE_QUIT;
							Message->cbData = 0;
							Message->Data = NULL;
							MyServ->AddServerMessage(Message);
						}
					}
					break;
				}
			}
			break;

		} // switch
	} // while
	return 0;
}

 Conclusion

il me semble qu'il reste qd mm 2-3 tits bugs (g un peu testé mais pas a fond)
notament il y en a un pour l'ID Client, lorsque par exemple le 2 se barre et qu'il y a un 3 le 3 devient 2 ou un truc comme ca.

Si jms vous trouvez des bugs, ou des solutions aux bugs, mci de me les faire parvenir (ds.blackgoddess@ifrance.com), si vs avez des questions n'hesitez pas non plus :)

j'espere que ca pourra vous servir :)
bonne prog
@+

7 mai 2003 / 16h30 : MAJ

voila, puisque les nouvelles fonctionalités dont j'ai parlé ci-dessous vont être beaucoup plus longues que prévues, j'ai corrigés le bug des ressources (en fait j'ai refait la moitié de la classe) et je la remets donc.
Merci de me signaler d'autres bugs :)    

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip STATCKTRACE : GARDER LA TRACE DE LA PILE D'APPEL
Source avec Zip ENCAPSULATION D'UNE PARTIE DE L'API SOCKET PORTABLE
Source avec Zip HOOKING SOUS NT AVEC CREATEREMOTETHREAD (VC++7, COMPILABLE A...
Source avec Zip CLASSE POUR TRAVAILLER AVEC DES GRANDS NOMBRES ENTIERS
Source avec Zip BOT IRC

 Sources de la même categorie

Source avec Zip TIM_RESEAU, CLASSES POUR RESEAU COMPLET par williamallas
Source avec Zip INTERNET IP FINDER TROUVER VOS ADRESSE IP (INTERNET) par xmustapha
Source avec Zip CLIENT/SERVEUR AVEC TSOCKETSERVER & TCLIENTSOCKET par xmustapha
Source avec Zip REMOTE SHELL GEN par ganjarasta
PROXY IRC SIMPLE (WINDOWS/WINSOCK) par _michel

Commentaires et avis

Commentaire de 24Karas le 13/01/2003 23:38:17

ça à l'air pa mal du tou : FELICITATION :)
g pa testé mais je m'empresse de le faire ...
Bon courage pour la suite
                                                   @++        24KaraS

Commentaire de BlackGoddess le 14/01/2003 08:22:06

merci :)
ah ! oui c possible que je me sois aussi un peu embrouiller avec les CriticalSection...

Commentaire de LordBob le 14/01/2003 18:27:31

ca orrai été bien ke tu mettre tous les fichier du projet pour Vc++ dans ton zip...

Commentaire de BlackGoddess le 14/01/2003 19:11:53

wep, dsl je ferais ca la prochaine fois

Commentaire de NerOcrO le 15/01/2003 16:26:07

Merci ma couille, j'attendais ça depuis longtemps.

Commentaire de BlackGoddess le 15/01/2003 17:23:55

np ;)

Commentaire de deedje le 30/01/2003 09:36:45

Salut,

As-tu un exemple d'utilisation de ta classe ? C'est quand même plus facile pour comprendre le fonctionnement....
Merci :))

Commentaire de BlackGoddess le 30/01/2003 20:51:03

ds le zip, main.cpp contient un exemple non ?

Commentaire de HotSpot le 23/02/2003 23:16:35

salut ...
J'ai vu ton code et il me pose un petit problème ..... L'utilisation des resources system en effet ce dernier parait vraiment tres mais tres gourmant ..... autre chose si t'a une doc sur les threads et ses fonctions telles que CriticalSection passe les moi ... merci !!!

Commentaire de BlackGoddess le 24/02/2003 09:22:13

oui oui oui je me suis rendu compte recemment de ce gros bug : en fait, au lieu d'attendre un evenement, le thread de fond tourne en boucle, d'ou son enorme utilisation du temps processeur, des je corrige la source, je la repose.

Commentaire de BlackGoddess le 24/02/2003 09:29:34

sinon, pour les criticals sections, je 'texplique en gros le principe, pour l'utilisation de chaque fonctions (4 au total, plus une 5eme sous win2k/xp), go MSDN

donc, une critical section sert pour le multithread, pour eviter qu'un thread accede à un emplacement mémoire en mm tps qu'un autre.

par exemple ds ce source, le status du serveur peut etre lu/changé par les fonctions du serveur (qui ne sont p-e pas toutes executé par le mm thread), et le thread de gestion des sockets. ainsi, quand un thread veut lire en changer cette variable, il demande à "owner" la critical section. un seul thread peut "owner" la critical section en mm tps, aussi si un autre l'own deja, le thread attend (EnterCriticalSection ne retourne que qd elle a pu owner la CS). donc, une fois que le thread own la critical section, il sait qu'il est le seul a pouvoir accéder à la variable, donc pas de risque de lecture/ecriture simultanée. une fois qu'il a fini, il rend l'own de la critical section avec LeaveCriticalSection, pour qu'un autre thread puisse a son tour l'owner.
voila :)
sinon, g entendu parler des mutex aussi du mm style, sauf que la ca peut aussi fonctionner entre processus, et pas seulement entre threads d'un mm processus.

Commentaire de HotSpot le 24/02/2003 22:00:44

merci .. pour les mutex et les samphores je suis au courant ...
sinon merci pour cette breve explication (lol) et sinon utilise les event pour corriger cette source .. bon courage ... ;)

Commentaire de BlackGoddess le 25/02/2003 10:19:59

oui oui bien sur j'avais fait une tite classe client sur le mm modele, et mon client claquait absolument toutes les ressources de mon tit ordi (celui de test), jmen suis rendu compte et corrigé ac les events, je fais faire pareil pour le serveur :)

Commentaire de adrien78 le 15/03/2003 09:54:04

Slt, térrible ton code, il va me permettre de faire bcp de trucs, thx,
cependant, est ce qu' il est possible que tu mettes online un chti client ? histoire de voir comment le tt fonctionne...

Commentaire de grosiflex le 14/04/2003 20:37:56

bah perso, merci pour le source, et les explications sur entercriticalsection();
dechire je galere un peu sur le thread, ce source est franchement cool pour ca, je met 10 directe, car tu t'es bien casser le cul je trouve franchment MERCI !!!

Commentaire de BlackGoddess le 14/04/2003 22:53:43

de rien lol, ca fait plaisir des critiques pareilles lol :p

sinon je taff en ce moment sur la correction du bug des ressources par les events ...

Commentaire de krom le 24/04/2003 10:06:58

bon, déjà le 24/04 et pas de correction, si tu taffes encore dessus, préviens nous.
merci

Commentaire de krom le 24/04/2003 10:07:07

bon, déjà le 24/04 et pas de correction, si tu taffes encore dessus, préviens nous.
merci

Commentaire de krom le 26/04/2003 11:58:02

lu,
désolé pr l'impertinence de ma remarque, ce n'est pas tout à fait ce que je voulais dire.
je suis avec intérêt l'évolution de ce serveur.
dès que tu auras progressé, fais le nous savoir.
bonne chance pour le développement et n'hésite pas à demander un coup de main.
++

Commentaire de bapt1080 le 29/04/2003 09:53:49

pas mal!
j'avais fait un serveur http en java mais c plus facile avec java
mais comme mon langage de prédilection est le c++ sa le fais bien que tu es fais sa, sa va m'aider a faire très vite des applis en reseau.
je vais chercher pour les events, j'avait pas trop eu de mal avec sa sur mon serveur...
@+

Commentaire de BlackGoddess le 02/05/2003 16:23:00

voila, je viens de finir de coder une classe pour travailler avec des grands entiers, qui va m'etre utile pour le cryptage dont je parlais plus haut :
http://www.cppfrance.com/article.aspx?Val=1775

Commentaire de BlackGoddess le 07/05/2003 16:34:36

MAJ (correction des bugs)

Commentaire de Klephte le 20/05/2003 09:33:41

Ta technique de programmation est originale donc merci pour ce bel effort.
Juste une remarque, si tu permets, j'ai eu l'occasion de développer un serveur IP et pour éviter l'utilisation d'un nombre de thread égal au nombre de clients j'avais,à l'époque, utilisé la technique des "I/O Completion Ports" qui donne les résultats tout à fait exceptionnels.

Commentaire de BlackGoddess le 20/05/2003 09:44:40

I/O Completion Ports ok je me pencherais de ce coté (note qd meme que je n'utilise pas un nombre de thread egale au nombre de client, mais juste un thread en tache de fond pour gerer les evenements des sockets)
Merci de la remarque :)

Commentaire de BlackGoddess le 20/05/2003 09:45:28

(notez aussi que mon commentaire précédent est truffé de fautes d'orthographe)

Commentaire de carat le 10/06/2003 08:27:21

Salut BlackGoddess,

Ton serveur est nickel, tu as juste oublié un petit détail: quand un client se déconnecte, n'oublie pas de nettoyer les éventuels messages qu'il aurait pu y laisser, sinon tu risques de remplir, à la longue, ta mémoire inutilement!

Bien a toi, hooo dieu! ;-)

Commentaire de BlackGoddess le 10/06/2003 09:35:06

pouarf dieu, la blague :p ...
merci pour le 'petit détail' :) je corrigerais qd j'aurais le tps :)

Commentaire de BlackGoddess le 23/06/2003 18:02:36

MAJ mineure : on peut maintenant configurer pour nettoyer les messages comme disait carat (je l'ai mis en optionnel car par exemple si le client envoit une requete puis se deconnecte, le serveur peut vouloir la traiter malgré la déconnexion), et aussi configurer pour mettre/enlever un message au depart/arrivée d'un client.

Commentaire de BlackGoddess le 24/06/2003 12:53:27

dsl, boulette dans le code de la dernier MAJ, CNetServer::DelMessID etait completement foireuse, c'est corrigé :)

Commentaire de BlackGoddess le 24/06/2003 14:04:25

adrien 78

http://www.cppfrance.com/article.aspx?Val=1567
c'est un exemple de bot irc, il utilise une classe qui peut faire client de ce serveur.

Commentaire de ptimine le 10/09/2003 22:34:46

Respect pour tes compétences. Ce code est bien ficellé ! :) Je vais m'en inspirer pour percer les secrets de la prog reseau et, puisque tu les utilise avec pertinance, les threads également, je ne les connais pas encore.

C'est cool d'aider tant de gens par ton travail sur ce code !

Commentaire de carat le 11/09/2003 10:38:12

Salut BlackGoddess, c'est encore moi... je dois te paraître embetant mais y'a encore un prob :-)

Faudrait une solution pour gérer les timeout sur les connex clients, car qd un client plante, son "fantôme" reste malgré tout connecté pour le serveur. Ca devient très embetant si le serveur tourne non-stop... à la longue... fin au risque de me répeter, tu risques de remplir ta mémoire inutilement lol... et surtout.. blablabla 'fin tu vois la merde quoi ;-)

Commentaire de BlackGoddess le 11/09/2003 17:56:05

pour le cryptage, on verra ca plus tard, j'ai pas le niveau de maths appliqués pour ca pour l'instant ... si qq1 a un lien util (les algos je les comprends, mais je n'arrive pas encore a travailler convenablement sur les grands entiers...)

sinon, pour le fantôme, je vais jeter un coup d'oeil ...

Commentaire de fyleo le 28/09/2003 13:51:52

slt déjà je te félicite pour cette source vraiment très bien faite et aussi parce que j'ai remarquer un problème d'accès avec le thread
le log du debugguer :

'test.exe' : Chargé 'E:Visual Studio Projects estRelease est.exe', Les symboles ont été chargés.
'test.exe' : Chargé 'C:WINDOWSsystem32
tdll.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32kernel32.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32ws2_32.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32msvcrt.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32ws2help.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32advapi32.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32
pcrt4.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32mswsock.dll', Aucun symbole n'a été chargé.
'test.exe' : Chargé 'C:WINDOWSsystem32wshtcpip.dll', Aucun symbole n'a été chargé.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception non gérée à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Exception de première chance à 0x004014a4 dans test.exe:0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000.
Le thread 'Thread Win32' (0x8d4) s'est arrêté avec le code -1073741510 (0xc000013a).
Le thread 'Thread Win32' (0xbc8) s'est arrêté avec le code -1073741510 (0xc000013a).
Le programme '[2544] test.exe: Natif' s'est arrêté avec le code -1073741510 (0xc000013a).
voila et encore bravo!!!

Commentaire de fyleo le 28/09/2003 13:56:51

j'ai oublier de dire la ligne ou ca bugguais ^^
c la ligne 614 de network.cpp
dans la fonction "CNetServer::ThreadEntry(CNetServer* MyServ)"
et dans le cas ou ca bug MyServ = 0x0000003e ^^

Commentaire de BlackGoddess le 29/09/2003 00:51:56

euh ... qq1 d'autre a un truc semblable ? sinon pense bien a mettre tes libs en multithread ds ton compilo

Commentaire de carat le 29/09/2003 08:54:24

Fyleo, d'après ce que je vois dans ton log, les chemins d'accès de tes librairies sont foireux!, il manque un  !!!! Vérifie déjà ça!

Commentaire de carat le 29/09/2003 08:57:32

Zut g oublié que ct de l'html :-)
Je disais donc, il n'y a aucun backslash! Mais je retire ce que j'ai dis car c le site qui les a enlevé, sorry!

Commentaire de fyleo le 29/09/2003 17:54:55

ba en fait j'ai réussi a avoir cette erreur en testant le serveur avec un programme qui connecte plusieur client a la suite (sans les déconnecter) et au bout du 60 iéme le programme a fait cette erreur mais ca peut très bien être du a ce ke les connexion se sont fait trop rapidement pour le programme ^^ mais sinon le serveur marche ss pb

Commentaire de BlackGoddess le 29/09/2003 18:21:36

euh ... alors en fait, la fameuse limite des 64 intervient ici ... WSAWaitForMultipleEvents ne peut pas prendre en compte plus de 64 events ... si on enleve les 3 evenements clientlistchange, heclose, et celui du socket qui ecoute, il doit etre possible de supporter 61 clients ... c'est une decouverte que j'ai faite il y a pas longtemps ...

Commentaire de maitrez le 20/11/2003 17:45:17

Salut, j'ai intégré ce code à mon prog et çamarche vraiment bien, par contre, j'ai une question: quand j'utilise la commande Send du Serveur, je suis obligé de la lancer 2 fois de suite, je comprends pas trop pourquoi, est-ce que quelqu'un aurait eu le même problème et aurait trouvé une solution, ou suis-je le seul dans ce cas là?

Un autre truc, je suis obligé de mettre une pause entre 2 Send à des clients différents... Sleep 100, sinon mon 2ieme message n'est pas envoyé...

Voili voilou,
Merci de vos réponses
A+
MzF

Commentaire de BlackGoddess le 20/11/2003 19:09:25

euh ... bizarre les send ... ca m'avait semblé simple a utiliser =&gt; g pas tres bien fait gaffe a ca :p, je vais me documenter sur ces fonctions...

Commentaire de maitrez le 21/11/2003 00:53:54

Simple, je suis d'accord ;) mais ça fonctionne bizarrement... est-ce que c'est du à mon client qui prend pas mal de ressources... je sais pas trop.... c'est possible. Ou est-ce que c'est du au fait que j'envoie des char[256] ?
That Is the question....

En tout cas, ça fonctionne pas mal, merci pour ce code ;)

MzF

Commentaire de maitrez le 21/11/2003 00:58:36

D'ailleurs, à ce sujet, pourrais-tu mettre un exemple de client, pour qu'on sache comme l'écrire? parce que je pense que mes temps de réponse pas tip top sont dus à ça...
Enfin, si c'est possible.... je sais que c'est pas beau de réclamer ;)

MzF

Commentaire de BlackGoddess le 21/11/2003 01:39:47

http://www.cppfrance.com/code.aspx?ID=10537
cf netword.h et network.cpp (et status.h et status.cpp)
normalement ca devrait bien tourner ensemble.

(j'y ai d'ailleurs répondu deja un peu plus haut ...)

sinon je grace a la magnifique source de BigInt qui a été posé récement je suis en train d'implémenter la possibilité de créer une connexion cryptée, puis je pense aussi rééecrire cette source, ainsi qu'un client en utilisant les std::string du c++ et la stl (std::vector, p-e d'autres).

Commentaire de BlackGoddess le 21/11/2003 15:52:11

sinon, pour eviter la limitation à 62 clients, je vois deux possibilités :

- créer une fenetre (invisible, juste pour ses messages) et faire passer les "evenements" des sockets asynchrones par cette fenetre. avantage : un seul thread créé, limitation du nombre de clients théoriquement a la limite de la machine/système
inconvenient : une application qui utiliserait ce module pour sa gestion du reseau serait plus facilement attacable avec un "hook" de la "callback" de la fenetre (facile a réaliser), ce qui permettrait de recevoir les messages des sockets.

- créer un gestion de thread qui crée un thread tout les 64 clients qui attendent chacun les evenements de 64 sockets.
avantage : plus difficilement attacable a ma connaissance.
inconvenient : ca peut devenir tres lourd s'il y a beaucoup de clients ...

qq1 saurait quelle méthode choisir, ou verrait une autre possibilité ?
merci :)

Commentaire de olecossois le 16/03/2004 10:31:40

A quand la version qui dépasse les 60 clients, vraiment on l'attend ce serait vraiment cool

En tout cas ça fonctionne trop bien avec 60 clients

Vraiment très bon code

je mets 10/10

Commentaire de FreeYo le 10/06/2004 16:59:52

Une mine d'or !!!!

Un grand grand merci !

Commentaire de Stood le 12/08/2004 12:25:25

salut, dis moi blackgoddess, la limite des 64 clients ne viendrait pas de la variable FD_SETSIZE ?

[url=http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/select_2.asp]winsock functions: select()[/url]

je cite "Four macros are defined in the header file Winsock2.h for manipulating and checking the descriptor sets. The variable FD_SETSIZE determines the maximum number of descriptors in a set. (The default value of FD_SETSIZE is 64, which can be modified by defining FD_SETSIZE to another value before including Winsock2.h.)"

Commentaire de CptLuthor le 13/11/2004 22:39:59

salut

Quand on est conecter avec ton client et ton server, peut t on se voi en reseau avec un pot, c a d par exemple se voir dans les jeux  ?

Commentaire de vinceVD le 26/05/2005 15:07:15

Salut je viens aussi de me truover bloquer a cause de la limite de 64connex, au début je croyé qe ct a cause de XP SP2 mais apparament non.J'ai vu les deux méthode que tu as proposé et je voudrait savoir si quelqu'un a testé une de ces soluces ou tout simplement a réussi a contourner le pb. Merci de vos réponse

Commentaire de vinceVD le 26/05/2005 15:07:36

Salut je viens aussi de me truover bloquer a cause de la limite de 64connex, au début je croyé qe ct a cause de XP SP2 mais apparament non.J'ai vu les deux méthode que tu as proposé et je voudrait savoir si quelqu'un a testé une de ces soluces ou tout simplement a réussi a contourner le pb. Merci de vos réponse

Commentaire de BlackGoddess le 27/05/2005 10:47:04

Stood > pour le FD_SETSIZE, on peut en effet changer la valeur.
Malheureusement cette valeur est statique, définie a la compilation.
Je ne connais pas l'implémentation des fd_set, mais je suppose que ca doit etre un tableau. Aussi définir une trop grande valeur par rapport au nombre de clients potentiels pourrait nuire aux performances par exemple.
Ca ne permet donc pas une gestion souple du nombre de clients :(

Commentaire de psyjc le 20/01/2007 20:54:46

Salut blackgoddess.
je me suis inspiré de ton code pour coder un serveur multi clients sur un seul thread mais je le problème qui a été évoqué ci dessus : wsawaitformultipleevent boucle et bouffe 100% proc. comment a tu fais pour régler ce problème et être bloquant dans l'attente d'un évènement ?
Merci d'avance?

Commentaire de psyjc le 20/01/2007 21:06:38

J'ai trouvé.. (ca m'apprendra a pas chercher...)

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix


HTC Magic

Entre 429€ et 429€

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,484 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales