//WSAEventSelect.h
#include "CInitSocket.h"
typedef struct _SOCKET_OBJ
{
SOCKET sock; //套接字句柄
HANDLE hEvent; //与次套接字相关的事件对象句柄
sockaddr_in addrRemote; //客户端地址信息
_SOCKET_OBJ *pNext; //指向下一个SOCKET_OBJ对象,构成链表
}SOCKET_OBJ,*PSOCKET_OBJ;
typedef struct _THREAD_OBJ
{
HANDLE hEvents[WSA_MAXIMUM_WAIT_EVENTS];//记录当前线程要等待的事件对象的句柄
int nSocketCount; //当前线程处理的套接字的数量
PSOCKET_OBJ pSockHeader; //指向当前线程处理的套接字对象列表表天头
PSOCKET_OBJ pSockTail; //指向表尾
CRITICAL_SECTION cs; //关键代码段,用于同步本结构的访问
_THREAD_OBJ * pNext; //指向下一个对象,练成链表
}THREAD_OBJ,*PTHREAD_OBJ;
PSOCKET_OBJ GetSocketObj(SOCKET sock); //申请一个套接字对象,并初始化
void FreeSocketObj(PSOCKET_OBJ pSocket); //释放一个套接字对象
PTHREAD_OBJ GetThreadObj(); //申请一个线程对象,初始化后加入线程对象列表
void FreeThreadObj(PTHREAD_OBJ pThread); //释放一个线程对象,并将它从线程对象列表中移除
void RebuildArrary(PTHREAD_OBJ pThread); //套接字链表改变的时候,重新组建线程对象的hEvents数组
bool InsertSocketObj(PTHREAD_OBJ pThread,PSOCKET_OBJ pSocket);
void AssignToFreeThread(PSOCKET_OBJ pSocket);
void RemoveSocketObj(PTHREAD_OBJ pThread,PSOCKET_OBJ pSocket);
DWORD WINAPI ServerThread(LPVOID lpParam);
PSOCKET_OBJ FindSocketObj(PTHREAD_OBJ pThread,int nIndex);
bool HandleIO(PTHREAD_OBJ pThread,PSOCKET_OBJ pSocket);
//WSAEventSelect.cpp
#include "WSAEventSelect.h"
#include <iostream>
using namespace std;
extern PTHREAD_OBJ g_pThreadList; //指向线程对象列表表头
extern CRITICAL_SECTION g_cs; //同步对此全局变量的访问
extern LONG g_nTatolConnections; //总共连接数量
extern LONG g_nCurrentConnections; //当前连接数量
PSOCKET_OBJ GetSocketObj(SOCKET sock) //申请一个套接字对象,并初始化
{
PSOCKET_OBJ pSocket=(PSOCKET_OBJ)GlobalAlloc(GPTR,sizeof(SOCKET_OBJ));
if (pSocket!=NULL)
{
pSocket->sock=sock;
pSocket->hEvent=WSACreateEvent();
}
return pSocket;
}
void FreeSocketObj(PSOCKET_OBJ pSocket) //释放一个套接字对象
{
CloseHandle(pSocket->hEvent);
if (pSocket->sock!=INVALID_SOCKET)
{
closesocket(pSocket->sock);
}
GlobalFree(pSocket);
}
PTHREAD_OBJ GetThreadObj() //申请一个线程对象,初始化后加入线程对象列表
{
PTHREAD_OBJ pThread=(PTHREAD_OBJ)GlobalAlloc(GPTR,sizeof(THREAD_OBJ));
if (pThread!=NULL)
{
InitializeCriticalSection(&pThread->cs);
//创建一个事件对象,用于只是该线程的句柄数组是否需要重建
pThread->hEvents[0]=WSACreateEvent();
EnterCriticalSection(&g_cs);
pThread->pNext=g_pThreadList;
g_pThreadList=pThread;
LeaveCriticalSection(&g_cs);
}
return pThread;
}
void FreeThreadObj(PTHREAD_OBJ pThread) //释放一个线程对象,并将它从线程对象列表中移除
{
EnterCriticalSection(&g_cs);
PTHREAD_OBJ p=g_pThreadList;
if (p==pThread)
{
g_pThreadList=p->pNext;
}
else
{
while (p!=NULL&&p->pNext!=pThread)
{
p=p->pNext;
}
if (p!=NULL)
{
p->pNext=pThread->pNext;
}
}
LeaveCriticalSection(&g_cs);
//释放资源
CloseHandle(pThread->hEvents[0]);
DeleteCriticalSection(&pThread->cs);
GlobalFree(pThread);
}
void RebuildArrary(PTHREAD_OBJ pThread) //套接字链表改变的时候,重新组建线程对象的hEvents数组
{
EnterCriticalSection(&pThread->cs);
PSOCKET_OBJ pSocket=pThread->pSockHeader;
int n=1;
while(pSocket!=NULL)
{
pThread->hEvents[n++]=pSocket->hEvent;
pSocket=pSocket->pNext;
}
LeaveCriticalSection(&pThread->cs);
}
PSOCKET_OBJ FindSocketObj(PTHREAD_OBJ pThread,int nIndex) //从nIndex开始搜索
{
PSOCKET_OBJ pSocket=pThread->pSockHeader;
while (--nIndex)
{
if (pSocket==NULL)
{
return NULL;
}
pSocket=pSocket->pNext;
}
return pSocket;
}
bool HandleIO(PTHREAD_OBJ pThread,PSOCKET_OBJ pSocket)
{
WSANETWORKEVENTS NetEvents;
WSAEnumNetworkEvents(pSocket->sock,pSocket->hEvent,&NetEvents);
if (NetEvents.lNetworkEvents & FD_READ)
{
if (NetEvents.iErrorCode[FD_READ_BIT==0])
{
char szText[256];
int nRecv=recv(pSocket->sock,szText,256,0);
if (nRecv>0)
{
szText[nRecv]='\0';
cout<<"接收到数据:"<<szText<<endl;
}
returntrue;
}
}
elseif (NetEvents.lNetworkEvents & FD_WRITE)
{
if (NetEvents.iErrorCode[FD_WRITE_BIT]==0)
{
//do something
returntrue;
}
}
elseif (NetEvents.lNetworkEvents & FD_CLOSE)
{
}
RemoveSocketObj(pThread,pSocket);
FreeSocketObj(pSocket);
returnfalse;
}
DWORD WINAPI ServerThread(LPVOID lpParam)
{
PTHREAD_OBJ pThread=(PTHREAD_OBJ)lpParam;
while (true)
{
int nIndex=WSAWaitForMultipleEvents(pThread->nSocketCount+1,pThread->hEvents,
FALSE,INFINITE,FALSE);
nIndex=nIndex-WSA_WAIT_EVENT_0;
//查看受信事件对象
for(int i=nIndex;i<pThread->nSocketCount+1;i++)
{
nIndex=WSAWaitForMultipleEvents(1,&pThread->hEvents[i],TRUE,INFINITE,FALSE);
if (nIndex==WSA_WAIT_FAILED || nIndex==WSA_WAIT_TIMEOUT)//hEvent[0]受信,重建数组
{
continue;
}
else
{
if (i==0) //hEvent[0]受信,重建数组
{
RebuildArrary(pThread);
if (pThread->nSocketCount==0)
{
FreeThreadObj(pThread);
return0;
}
}
else
{
//查找对应的套接字对象指针,调用HandleIO处理网络事件
PSOCKET_OBJ pSocket=(PSOCKET_OBJ)FindSocketObj(pThread,i);
if (pSocket!=NULL)
{
if (!HandleIO(pThread,pSocket))
{
RebuildArrary(pThread);
}
}
else
{
cout<<"无法找到该套接字对象!\n";
}
}
}
}
}
return0;
}
//向一个线程的套接字列表中插入一个套接字
bool InsertSocketObj(PTHREAD_OBJ pThread,PSOCKET_OBJ pSocket)
{
bool bRet=false;
EnterCriticalSection(&pThread->cs);
if (pThread->nSocketCount<WSA_MAXIMUM_WAIT_EVENTS-1)
{
if (pThread->pSockHeader==NULL)
{
pThread->pSockHeader=pThread->pSockTail=pSocket;
}
else
{
pThread->pSockTail->pNext=pSocket;
pThread->pSockTail=pSocket;
}
pThread->nSocketCount++;
bRet=true;
}
LeaveCriticalSection(&pThread->cs);
if (bRet) //插入成功,说明处理了客户的连接请求
{
InterlockedIncrement(&g_nTatolConnections);
InterlockedIncrement(&g_nCurrentConnections);
}
return bRet;
}
void AssignToFreeThread(PSOCKET_OBJ pSocket)
{
pSocket->pNext=NULL;
EnterCriticalSection(&g_cs);
PTHREAD_OBJ pThread=g_pThreadList;
//试图插入到现存线程
while (pThread!=NULL)
{
if (InsertSocketObj(pThread,pSocket)) break;
pThread=pThread->pNext;
}
if (pThread==NULL)
{
pThread=GetThreadObj();
InsertSocketObj(pThread,pSocket);
CreateThread(NULL,0,ServerThread,pThread,0,NULL);
}
LeaveCriticalSection(&g_cs);
//使第一个事件受信,指使线程重建句柄数组
WSASetEvent(pThread->hEvents[0]);
}
//从给定的线程套接字对象列表中移除一个套接字
void RemoveSocketObj(PTHREAD_OBJ pThread,PSOCKET_OBJ pSocket)
{
EnterCriticalSection(&pThread->cs);
PSOCKET_OBJ pTest=pThread->pSockHeader;
if (pTest==pSocket)
{
if (pThread->pSockHeader==pThread->pSockTail)
{
pThread->pSockTail=pThread->pSockHeader=NULL;
}
else
{
pThread->pSockHeader=pTest->pNext;
}
}
pThread->nSocketCount--;
LeaveCriticalSection(&pThread->cs);
WSASetEvent(pThread->hEvents[0]);
InterlockedDecrement(&g_nCurrentConnections);
InterlockedDecrement(&g_nTatolConnections);
}
//main.cpp
#include "WSAEventSelect.h"
PTHREAD_OBJ g_pThreadList; //指向线程对象列表表头
CRITICAL_SECTION g_cs; //同步对此全局变量的访问
LONG g_nTatolConnections; //总共连接数量
LONG g_nCurrentConnections; //当前连接数量
#include <iostream>
usingnamespace std;
CInitSock initsock;
int main() //主线程
{
USHORT nPort=6000;
//创建监听套接字
SOCKET ListenSocket=socket(AF_INET,SOCK_STREAM,0);
sockaddr_in addrin;
addrin.sin_addr.S_un.S_addr=INADDR_ANY;
addrin.sin_family=AF_INET;
addrin.sin_port=htons(nPort);
if (SOCKET_ERROR==bind(ListenSocket,(LPSOCKADDR)&addrin,sizeof(addrin)))
{
cout<<"套接字绑定失败!\n";
return-1;
}
listen(ListenSocket,200);
//创建事件对象,并关联到监听套接字
WSAEVENT hEvent=WSACreateEvent();
WSAEventSelect(ListenSocket,hEvent,FD_ACCEPT | FD_CLOSE);
InitializeCriticalSection(&g_cs);
//处理客户连接请求,打印状态信息
while (true)
{
int nRet=WaitForSingleObject(hEvent,5000);
if (nRet==WAIT_FAILED)
{
cout<<"等待出错!";
break;
}
elseif (nRet==WSA_WAIT_TIMEOUT)
{
cout<<"TatolConnections:"<<g_nTatolConnections<<endl;
cout<<"CurrentConnections"<<g_nCurrentConnections<<endl;
continue;
}
else//有新的连接未决
{
ResetEvent(hEvent);
while (true)
{
sockaddr_in NewAddr;
int nLen=sizeof(NewAddr);
SOCKET NewSocket=accept(ListenSocket,(sockaddr*)&NewAddr,&nLen);
if (NewSocket==SOCKET_ERROR)
{
break;
}
PSOCKET_OBJ pSocket=GetSocketObj(NewSocket);
pSocket->addrRemote=NewAddr;
WSAEventSelect(pSocket->sock,pSocket->hEvent,FD_READ | FD_CLOSE | FD_WRITE);
AssignToFreeThread(pSocket);
}
}
}
DeleteCriticalSection(&g_cs);
return0;
}