windows下封装一个soket服务器类(事件模型)

---------------------------------MySocketServer.h-------------------------------------------------

#ifndef __MYSOCKETSERVER_H__
#define __MYSOCKETSERVER_H__
#include <WINSOCK2.H>


typedef void (*TMsgProFun)(char *pMsg,int &ilen); 


class CSockeServer
{
public:
static CSockeServer *GetInstance(TMsgProFun MsgPro = NULL);
~CSockeServer();
char * StartServer(u_short port = 5150,const char *strIp = NULL); //开启服务,失败返回相应的错误log。正确返回NULL(如果开启了服务则一般不会返回)。
static void RegisterMsgFun(TMsgProFun MsgPro);//用来注册消息处理函数,对接收到的消息进行相应的处理。
static void Close();
private:
CSockeServer(){};
static DWORD __stdcall WorkerThread(LPVOID lpParam); 
static DWORD __stdcall AcceptThread(LPVOID lpParam); //accept线程,监听链接请求
static void  Cleanup(int index); 
private:
static int ms_iTotalConn; 
static SOCKET ms_CliSocketArr[MAXIMUM_WAIT_OBJECTS]; 
static WSAEVENTms_CliEventArr[MAXIMUM_WAIT_OBJECTS]; 
const static intMsg_Size;
static TMsgProFun   pMsgProcFun;
static char         LogBuf[1024]; //打印log
static SOCKET       ms_sListen;
static HANDLE       ms_HandThread[2];
static CSockeServer *ms_pSingleServer;
static HANDLE       ms_hSemaphore;
static bool         ms_bEndThread;
};




#endif

---------------------------------MySocketServer.cpp-------------------------------------------------

#include "MySocketServer.h"
#include <stdio.h>


#pragma comment(lib,"ws2_32.lib") 


#define LISTENNUM 10 //最大监听数


 int          CSockeServer::ms_iTotalConn     = 0; 
 SOCKET       CSockeServer::ms_CliSocketArr[MAXIMUM_WAIT_OBJECTS]; 
 WSAEVENT     CSockeServer::ms_CliEventArr[MAXIMUM_WAIT_OBJECTS]; 
 const int    CSockeServer::Msg_Size          = 2048;
 TMsgProFun   CSockeServer::pMsgProcFun  = NULL;
 SOCKET       CSockeServer::ms_sListen        = 0;
 CSockeServer *CSockeServer::ms_pSingleServer = NULL;
 HANDLE  CSockeServer::ms_HandThread[2];
 char         CSockeServer::LogBuf[1024];
 HANDLE       CSockeServer::ms_hSemaphore     = NULL;
 bool         CSockeServer::ms_bEndThread     = false;
 
 CSockeServer *CSockeServer::GetInstance(TMsgProFun MsgPro)
 {
if (NULL == ms_pSingleServer)
ms_pSingleServer = new CSockeServer();


ms_hSemaphore = CreateSemaphore(NULL,1,1,NULL);
RegisterMsgFun(MsgPro);


return ms_pSingleServer;
 }


 void CSockeServer::RegisterMsgFun(TMsgProFun MsgPro)
 {
WaitForSingleObject(ms_hSemaphore,INFINITE);
pMsgProcFun = MsgPro;
ReleaseSemaphore(ms_hSemaphore,1,NULL);
 }


 CSockeServer::~CSockeServer()
 {


if (0 != ms_iTotalConn)
{
Close();
}


//关闭信号量句柄
if (NULL != ms_hSemaphore)
{
CloseHandle(ms_hSemaphore);
ms_hSemaphore = NULL;
}


if (NULL != ms_pSingleServer)
{
delete ms_pSingleServer;
ms_pSingleServer = NULL;
}
 }


char * CSockeServer::StartServer(u_short port,const char *strIp)
{
WSADATA     wsaData;        
SOCKADDR_IN local; 
DWORD       dwThreadId; 
int         iaddrSize = sizeof(SOCKADDR_IN); 


ms_bEndThread = false;
// Initialize Windows Socket library 
WSAStartup(0x0202, &wsaData); 
// Create listening socket 
ms_sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
if (SOCKET_ERROR == ms_sListen)
{
sprintf_s(LogBuf,1024,"Create socket fail! Errode:%d",GetLastError());
return LogBuf;
}

// Bind 
if (NULL == strIp)
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
else 
local.sin_addr.S_un.S_addr = inet_addr(strIp);
local.sin_family  = AF_INET; 
local.sin_port  = htons(port); 


if (SOCKET_ERROR == bind(ms_sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN)))
{
sprintf_s(LogBuf,1024,"bind fail! Errode:%d",GetLastError());
return LogBuf;
}


// Listen 
if (SOCKET_ERROR == listen(ms_sListen, LISTENNUM))
{
sprintf_s(LogBuf,1024,"listen fail! Errode:%d",GetLastError());
return LogBuf;
}

if (NULL == pMsgProcFun)
{
sprintf_s(LogBuf,1024,"%s","No registration function,please register it,and try agin.");
return LogBuf;
}


// Create worker thread 
ms_HandThread[0] = CreateThread(NULL,0,WorkerThread,NULL,0,&dwThreadId); 
ms_HandThread[1] = CreateThread(NULL,0,AcceptThread,NULL,0,&dwThreadId);
     
return NULL;
 } 


DWORD CSockeServer::AcceptThread(LPVOID lpParam)
{
SOCKET      sClient; 
int         iaddrSize = sizeof(SOCKADDR_IN); 
SOCKADDR_IN client; 


while (TRUE) 

// Accept a connection 
sClient = accept(ms_sListen, (struct sockaddr *)&client, &iaddrSize); 
if (ms_bEndThread)
return 0;
//sprintf(buf,"Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); 
// Associate socket with network event 
ms_CliSocketArr[ms_iTotalConn] = sClient; 
ms_CliEventArr[ms_iTotalConn]  = WSACreateEvent(); 
WSAEventSelect(ms_CliSocketArr[ms_iTotalConn],ms_CliEventArr[ms_iTotalConn],FD_READ | FD_CLOSE); 
ms_iTotalConn++; 

return 0;
}


DWORD CSockeServer::WorkerThread(LPVOID lpParam)
{
int              ret, index; 
WSANETWORKEVENTS NetworkEvents; 
char             szMessage[Msg_Size]; 


while (TRUE) 

ret = WSAWaitForMultipleEvents(ms_iTotalConn, ms_CliEventArr, FALSE, 1000, FALSE); 
if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT) 

continue; 

if (ms_bEndThread) //结束线程
return 0;


index = ret - WSA_WAIT_EVENT_0; 
WSAEnumNetworkEvents(ms_CliSocketArr[index], ms_CliEventArr[index], &NetworkEvents); 
if (NetworkEvents.lNetworkEvents & FD_READ) 

// Receive message from client 
ret = recv(ms_CliSocketArr[index], szMessage, Msg_Size, 0); 
if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)) 

Cleanup(index); 

else 

szMessage[ret] = '\0';
WaitForSingleObject(ms_hSemaphore,INFINITE); //线程同步保护
pMsgProcFun(szMessage,ret);
ReleaseSemaphore(ms_hSemaphore,1,NULL);
send(ms_CliSocketArr[index], szMessage, strlen(szMessage), 0);




if (NetworkEvents.lNetworkEvents & FD_CLOSE) 

Cleanup(index); 


return 0; 
}


void  CSockeServer::Cleanup(int index)
{
  closesocket(ms_CliSocketArr[index]); 
  WSACloseEvent(ms_CliEventArr[index]); 
if (index < ms_iTotalConn - 1) 

ms_CliSocketArr[index] = ms_CliSocketArr[ms_iTotalConn - 1]; 
ms_CliEventArr[index] = ms_CliEventArr[ms_iTotalConn - 1]; 
 


  ms_iTotalConn--; 
}


void CSockeServer::Close()
{
//关闭socket服务
for (int index = ms_iTotalConn-1;index >= 0;index--)
{
Cleanup(index);
}


//关闭线程
if (NULL != ms_HandThread[0] || NULL != ms_HandThread[1])
{
CloseHandle(ms_HandThread[0]);
CloseHandle(ms_HandThread[1]);
ms_bEndThread = true;
Sleep(3000);
ms_HandThread[0] = ms_HandThread[1] = NULL;
}


WSACleanup();
}


参考文献:http://bk6.blog.163.com/blog/static/24498560201021635453185/

你可能感兴趣的:(windows下封装一个soket服务器类(事件模型))