下面这个重叠模型在运行的时候接收3500个以上的连接就不再接收了,各位看看小弟哪里搞错了//Overlapped类声明
///************************************************************************/
/* 出错处理宏                                                           */
/************************************************************************/
#define PrintfWinSockError(x) cout<<(x)<<endl\
<<"出错代码:"<<WSAGetLastError()<<endl\
<<"出错文件:"<<__FILE__<<endl\
<<"出错行:"<<__LINE__<<endl\#define PrintfError(x) cout<<(x)<<endl\
<<"出错代码:"<<GetLastError()<<endl\
<<"出错文件:"<<__FILE__<<endl\
<<"出错行:"<<__LINE__<<endl\
/************************************************************************/
/* 运行时头文件                                                         */
/************************************************************************/
#include "stdafx.h"#include <WinSock2.h> //Sock库
#pragma comment(lib,"ws2_32")#include <MSWSock.h> //扩展函数
#pragma comment(lib,"mswsock")#include <iostream> //C++输入/输出函数
using namespace std;
/************************************************************************/
/* 结构定义                                                             */
/************************************************************************/
#define BUFFER_SIZE 1024
typedef struct tagListenObj
{
SOCKET sClient;
char lpOutputBuffer[BUFFER_SIZE];
DWORD dwDataLength;
DWORD dwAddrLength;
DWORD dwByte;
WSAOVERLAPPED overlapped; tagListenObj *Next;
}LISTENOBJ,*PLISTENOBJ;
/************************************************************************/
/* 类定义                                                               */
/************************************************************************/class Coverlapped
{
public:
Coverlapped(SOCKADDR_IN sockaddrinfo, int connectcount);
~Coverlapped();
BOOL start();
private:
friend DWORD WINAPI ListenProc(LPVOID lpParam);
PLISTENOBJ GetListenObj();
void FreeListenObj(PLISTENOBJ pTemp);
private:
BOOL bQuitFlag; //程序退出标志
SOCKET m_slisten; //监听套接字
int m_nConnectCount; //并发接受连接数
CRITICAL_SECTION m_cs;
int m_nThreadId;
int m_sockCount;
};//OverLapped类声明
//#include "stdafx.h"#include <stdlib.h>#include "Overlapped.h"/************************************************************************/
/* 构造函数                                                             */
/************************************************************************/
Coverlapped::Coverlapped(SOCKADDR_IN sockaddrinfo, int connectcount)
{
WSADATA wsadata;
if(0 != WSAStartup(MAKEWORD(2,2),&wsadata))
PrintfWinSockError("初始化Winsock库失败!"); if (INVALID_SOCKET == (m_slisten = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED)))
PrintfWinSockError("创建监听套接字失败!"); if(SOCKET_ERROR == bind(m_slisten,(SOCKADDR*)&sockaddrinfo,sizeof(sockaddrinfo)))
PrintfWinSockError("监听套接字绑定失败!"); if(SOCKET_ERROR == listen(m_slisten,connectcount))
PrintfWinSockError("监听出错!");

//变量初始化
m_nConnectCount = connectcount;
bQuitFlag = FALSE;
m_nThreadId = 0;
m_sockCount = 0;
InitializeCriticalSection(&m_cs);
}
/************************************************************************/
/* 析构函数                                                             */
/************************************************************************/
Coverlapped::~Coverlapped()
{
if (m_slisten != INVALID_SOCKET)
{
closesocket(m_slisten);
}
DeleteCriticalSection(&m_cs);
WSACleanup();
}
/************************************************************************/
/* 开始接收客户端连接,创建监听线程                                      */
/************************************************************************/
BOOL Coverlapped::start()
{
int nThreadCount; div_t result = div(m_nConnectCount,64); if (result.rem == 0)
nThreadCount = result.quot;
else
nThreadCount = result.quot + 1; cout<<"需要创建"<<nThreadCount<<"个监听线程!"<<endl;

while(nThreadCount--)
{
if(NULL == CreateThread(NULL,0,ListenProc,this,0,NULL))
{
PrintfError("创建监听线程出错!");
return FALSE;
}
} return TRUE;
}
/************************************************************************/
/* 监听线程                                                             */
/************************************************************************/
DWORD WINAPI ListenProc(LPVOID lpParam)
{
Coverlapped *classthis = (Coverlapped*)lpParam;
int ThreadID;
EnterCriticalSection(&classthis->m_cs);
ThreadID = classthis->m_nThreadId++;
LeaveCriticalSection(&classthis->m_cs); int nCount = WSA_MAXIMUM_WAIT_EVENTS; //监听套接字小于64
int nIndex = 0;
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];

PLISTENOBJ pListenObjTemp;
PLISTENOBJ pHead,pTail,pTemp; //监听套接字列表
pHead = pTail = pTemp = NULL; while(nCount)
{
pListenObjTemp = classthis->GetListenObj(); //申请监听套接字对象
if(pListenObjTemp == NULL)
continue;
int nRet = AcceptEx(classthis->m_slisten, //发送接收请求
pListenObjTemp->sClient,
pListenObjTemp->lpOutputBuffer,
pListenObjTemp->dwDataLength,
pListenObjTemp->dwAddrLength,
pListenObjTemp->dwAddrLength,
&pListenObjTemp->dwByte,
&pListenObjTemp->overlapped);

if(nRet == FALSE)
{
if(ERROR_IO_PENDING != WSAGetLastError())
{
delete pListenObjTemp;
PrintfWinSockError("接受新连接出错!");
continue;
}
} if(pHead == NULL) //把监听套接字加入列表
pHead = pTail = pListenObjTemp;
else
{
pTail->Next = pListenObjTemp;
pTail = pListenObjTemp;
}
EventArray[nIndex++] = pListenObjTemp->overlapped.hEvent;
--nCount;
} while(TRUE)
{
if(classthis->bQuitFlag == TRUE) //如果程序退出,释放资源
{
while(pHead != NULL)
{
pTemp = pHead;
pHead = pHead->Next;
classthis->FreeListenObj(pTemp);
}
return 0;
} int nRet = WSAWaitForMultipleEvents(WSA_MAXIMUM_WAIT_EVENTS,EventArray,FALSE,WSA_INFINITE,FALSE);
if(nRet == WSA_WAIT_FAILED)
continue;
nRet = nRet - WSA_WAIT_EVENT_0;
for (int i = nRet;i < WSA_MAXIMUM_WAIT_EVENTS;i++)
{
nRet = WSAWaitForMultipleEvents(1,&EventArray[i],TRUE,1000,FALSE);
if (/*nRet == WSA_WAIT_FAILED && */nRet == WSA_WAIT_TIMEOUT)
{
continue;
}
else
{
//索引出受信套接字对象
pTemp = pHead;
while(pTemp != NULL && pTemp->overlapped.hEvent != EventArray[i])
pTemp = pTemp->Next;
if(pTemp != NULL)
{
//AddClientProc(pTemp->sClient);//把接受到的套接字加入处理线程
EnterCriticalSection(&classthis->m_cs);
cout<<"线程:"<<ThreadID<<"收到第:"<<classthis->m_sockCount++<<"个连接!"<<endl;
LeaveCriticalSection(&classthis->m_cs);
//重新在这个监听套接字对象上发送接收请求
pTemp->sClient = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
WSAResetEvent(pTemp->overlapped.hEvent);
AcceptEx(classthis->m_slisten,
pTemp->sClient,
pTemp->lpOutputBuffer,
pTemp->dwDataLength,
pTemp->dwAddrLength,
pTemp->dwAddrLength,
&pTemp->dwByte,
&pTemp->overlapped);
EventArray[i] = pTemp->overlapped.hEvent;
}
}
}
}
return 0;
}
/************************************************************************/
/* 申请监听对象                                                         */
/************************************************************************/
PLISTENOBJ Coverlapped::GetListenObj()
{
PLISTENOBJ pNewListenObj = new LISTENOBJ;
if(pNewListenObj == NULL)
return NULL;
pNewListenObj->sClient = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
if (pNewListenObj->sClient == INVALID_SOCKET)
{
delete pNewListenObj;
PrintfWinSockError("GetListenObj WSASocket!");
return NULL;
}
pNewListenObj->dwDataLength = BUFFER_SIZE - ((sizeof(SOCKADDR_IN)+16)*2);
pNewListenObj->dwAddrLength = sizeof(SOCKADDR_IN)+16;
pNewListenObj->overlapped.hEvent = WSACreateEvent();
if (pNewListenObj->overlapped.hEvent == WSA_INVALID_EVENT)
{
closesocket(pNewListenObj->sClient);
delete pNewListenObj;
PrintfWinSockError("GetListObj WSACreateEvent!");
return NULL;
}
pNewListenObj->Next = NULL; return pNewListenObj;
}
/************************************************************************/
/* 释放监听套接字对象                                                   */
/************************************************************************/
void Coverlapped::FreeListenObj(PLISTENOBJ pTemp)
{
if(pTemp->sClient != INVALID_SOCKET)
closesocket(pTemp->sClient);
CloseHandle(pTemp->overlapped.hEvent);
delete pTemp;
}// Overlapped.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"#include <stdlib.h>#include "Overlapped.h"int _tmain(int argc, _TCHAR* argv[])
{
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(4567);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); Coverlapped overlapped(addr,1000);
overlapped.start(); getchar();
return 0;
}

解决方案 »

  1.   

    Coverlapped::Coverlapped(SOCKADDR_IN sockaddrinfo, int connectcount)
    第二个参数指定了最大连接,这个值大于3500就可以了。
    该类通过 connectcount/64 来确定需要的线程数量。另外,该类的 ListenProc 写得不好,效率较低。
    通常大家都会用链表记录已链接的Socket或是可用的Socket资源,
    但最好只用链表记录个索引就行了。 int nRet = WSAWaitForMultipleEvents(WSA_MAXIMUM_WAIT_EVENTS,EventArray,FALSE,WSA_INFINITE,FALSE);
            if(nRet == WSA_WAIT_FAILED)
                continue;
            nRet = nRet - WSA_WAIT_EVENT_0;
            
    for (int i = nRet;i < WSA_MAXIMUM_WAIT_EVENTS;i++)
            {
                nRet = WSAWaitForMultipleEvents(1,&EventArray[i],TRUE,1000,FALSE);

    }这里是效率低的地方,没有理解 WSAWaitForMultipleEvents 的用法。