#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define _AFXDLL
#pragma comment(lib, "Ws2_32.lib") // Socket编程需用的动态链接库
#pragma comment(lib, "Kernel32.lib") // IOCP需要用到的动态链接库
//#include
#define MAX_BUFFER_LEN 2048
#define MAX_POST_ACCEPT 10
// 传递给Worker线程的退出信号
#define EXIT_CODE NULL
// 释放指针和句柄资源的宏
// 释放指针宏
#define RELEASE(x) {if(x != NULL ){delete x;x=NULL;}}
// 释放句柄宏
#define RELEASE_HANDLE(x) {if(x != NULL && x!=INVALID_HANDLE_VALUE){ CloseHandle(x);x = NULL;}}
// 释放Socket宏
#define RELEASE_SOCKET(x) {if(x !=INVALID_SOCKET) { closesocket(x);x=INVALID_SOCKET;}}
// 在完成端口上投递的I/O操作的类型
typedef enum _OPERATION_TYPE
{
ACCEPT_POSTED, // 标志投递的Accept操作
SEND_POSTED, // 标志投递的是发送操作
RECV_POSTED, // 标志投递的是接收操作
NULL_POSTED // 用于初始化,无意义
}OPERATION_TYPE;
CRITICAL_SECTION m_csContextList;
HANDLE m_hShutdownEvent;
HANDLE m_hIOCompletionPort; // 完成端口的句柄
const int m_nThreads = 16;//建立对应的线程数
HANDLE* m_phWorkerThreads = NULL; // 工作者线程的句柄指针
LPFN_ACCEPTEX m_lpfnAcceptEx; // AcceptEx 和 GetAcceptExSockaddrs 的函数指针,用于调用这两个扩展函数
LPFN_GETACCEPTEXSOCKADDRS m_lpfnGetAcceptExSockAddrs;
typedef struct _tagThreadParams_WORKER
{
int nThreadNo; //线程编号
} THREADPARAMS_WORKER, *PTHREADPARAM_WORKER;
THREADPARAMS_WORKER* pThreadParams[m_nThreads] = { NULL };
unsigned __stdcall _WorkerThread(LPVOID lpParam);
//每次套接字操作(如:AcceptEx, WSARecv, WSASend等)对应的数据结构:OVERLAPPED结构(标识本次操作),关联的套接字,缓冲区,操作类型;
typedef struct _PER_IO_CONTEXT
{
OVERLAPPED m_Overlapped; // 每一个重叠网络操作的重叠结构(针对每一个Socket的每一个操作,都要有一个)
SOCKET m_sockAccept; // 这个网络操作所使用的Socket
WSABUF m_wsaBuf; // WSA类型的缓冲区,用于给重叠操作传参数的
char m_szBuffer[MAX_BUFFER_LEN]; // 这个是WSABUF里具体存字符的缓冲区
OPERATION_TYPE m_OpType; // 标识网络操作的类型(对应上面的枚举)
DWORD m_nTotalBytes; //数据总的字节数
DWORD m_nSendBytes; //已经发送的字节数,如未发送数据则设置为0
//构造函数
_PER_IO_CONTEXT()
{
ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
ZeroMemory(m_szBuffer, MAX_BUFFER_LEN);
m_sockAccept = INVALID_SOCKET;
m_wsaBuf.buf = m_szBuffer;
m_wsaBuf.len = MAX_BUFFER_LEN;
m_OpType = NULL_POSTED;
m_nTotalBytes = 0;
m_nSendBytes = 0;
}
//析构函数
~_PER_IO_CONTEXT()
{
if (m_sockAccept != INVALID_SOCKET)
{
closesocket(m_sockAccept);
m_sockAccept = INVALID_SOCKET;
}
}
//重置缓冲区内容
void ResetBuffer()
{
ZeroMemory(m_szBuffer, MAX_BUFFER_LEN);
m_wsaBuf.buf = m_szBuffer;
m_wsaBuf.len = MAX_BUFFER_LEN;
}
} PER_IO_CONTEXT, *PPER_IO_CONTEXT;
typedef struct _PER_SOCKET_CONTEXT
{
SOCKET m_Socket; //连接客户端的socket
SOCKADDR_IN m_ClientAddr; //客户端地址
vector<_PER_IO_CONTEXT*> m_arrayIoContext; //套接字操作,本例是WSARecv和WSASend共用一个PER_IO_CONTEXT
//构造函数
_PER_SOCKET_CONTEXT()
{
m_Socket = INVALID_SOCKET;
memset(&m_ClientAddr, 0, sizeof(m_ClientAddr));
}
//析构函数
~_PER_SOCKET_CONTEXT()
{
if (m_Socket != INVALID_SOCKET)
{
closesocket(m_Socket);
m_Socket = INVALID_SOCKET;
}
// 释放掉所有的IO上下文数据
for (int i = 0; i < m_arrayIoContext.size(); i++)
{
delete m_arrayIoContext.at(i);
}
m_arrayIoContext.clear();
}
//进行套接字操作时,调用此函数返回PER_IO_CONTEX结构
_PER_IO_CONTEXT* GetNewIoContext()
{
_PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;
m_arrayIoContext.push_back(p);
return p;
}
// 从数组中移除一个指定的IoContext
void RemoveContext(_PER_IO_CONTEXT* pContext)
{
for (int i = 0; i < m_arrayIoContext.size(); i++)
{
if (pContext == m_arrayIoContext.at(i))
{
delete pContext;
pContext = NULL;
m_arrayIoContext.erase(m_arrayIoContext.begin() + i);
break;
}
}
}
} PER_SOCKET_CONTEXT, *PPER_SOCKET_CONTEXT;
PER_SOCKET_CONTEXT* m_pListenContext; // 用于监听的Socket的Context信息
vectorm_arrayClientContext; // 客户端Socket的Context信息
void _DeInitialize();
bool _PostAccept(PER_IO_CONTEXT* pAcceptIoContext);
void _RemoveContext(PER_SOCKET_CONTEXT *pSocketContext);
bool _IsSocketAlive(SOCKET s);
bool _DoAccpet(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext);
bool _DoFirstRecvWithoutData(PER_IO_CONTEXT* pIoContext);
void _AddToContextList(PER_SOCKET_CONTEXT *pHandleData);
bool PostRecv(PER_IO_CONTEXT* pIoContext);
bool _AssociateWithIOCP(PER_SOCKET_CONTEXT *pContext);
bool PostWrite(PER_IO_CONTEXT* pIoContext);
bool _DoFirstRecvWithData(PER_IO_CONTEXT* pIoContext);
bool _DoRecv(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext);
bool HandleError(PER_SOCKET_CONTEXT *pContext, const DWORD& dwErr);
void _ClearContextList();
void stop();
int main() {
WSADATA wsaData;
int nResult;
nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// 错误(一般都不可能出现)
if (NO_ERROR != nResult)
{
cout << "初始化winsock失败" << endl;
return 0;
}
// 初始化线程互斥量
InitializeCriticalSection(&m_csContextList);
// 建立系统退出的事件通知
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (NULL == m_hIOCompletionPort)
{
cout << ("建立完成端口失败!错误代码: %d!\n") << endl;
return false;
}
// 为工作者线程初始化句柄
m_phWorkerThreads = new HANDLE[m_nThreads];
// 根据计算出来的数量建立工作者线程
for (int i = 0; i < m_nThreads; i++)
{
pThreadParams[i] = new THREADPARAMS_WORKER;
pThreadParams[i]->nThreadNo = i + 1;
m_phWorkerThreads[i] = (HANDLE)_beginthreadex(0, 0, _WorkerThread, (pThreadParams[i]), 0, NULL);
}
cout << " 建立 _WorkerThread %d 个." << m_nThreads << endl;
// AcceptEx 和 GetAcceptExSockaddrs 的GUID,用于导出函数指针
GUID GuidAcceptEx = { 0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92} };
GUID GuidGetAcceptExSockAddrs = { 0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92} };
// 服务器地址信息,用于绑定Socket
struct sockaddr_in ServerAddress;
// 生成用于监听的Socket的信息
m_pListenContext = new PER_SOCKET_CONTEXT;
// 需要使用重叠IO,必须得使用WSASocket来建立Socket,才可以支持重叠IO操作
m_pListenContext->m_Socket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == m_pListenContext->m_Socket)
{
cout << "初始化Socket失败,错误代码: %d.\n" << WSAGetLastError() << endl;
return false;
}
else
{
cout << ("WSASocket() 完成.\n") << endl;;
}
// 将Listen Socket绑定至完成端口中
if (NULL == CreateIoCompletionPort((HANDLE)m_pListenContext->m_Socket, m_hIOCompletionPort, (DWORD)m_pListenContext, 0))
{
cout << "绑定 Listen Socket至完成端口失败!错误代码: %d/n" << WSAGetLastError() << endl;
RELEASE_SOCKET(m_pListenContext->m_Socket);
return false;
}
else
{
cout << "Listen Socket绑定完成端口 完成.\n" << endl;
}
// 填充地址信息
ZeroMemory((char *)&ServerAddress, sizeof(ServerAddress));
ServerAddress.sin_family = AF_INET;
// 这里可以绑定任何可用的IP地址,或者绑定一个指定的IP地址
//ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
ServerAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
ServerAddress.sin_port = htons(6000);
// 绑定地址和端口
if (SOCKET_ERROR == bind(m_pListenContext->m_Socket, (struct sockaddr *) &ServerAddress, sizeof(ServerAddress)))
{
cout << "bind()函数执行错误.\n" << endl;
return false;
}
else
{
cout << "bind() 完成.\n" << endl;
}
// 开始进行监听
if (SOCKET_ERROR == listen(m_pListenContext->m_Socket, SOMAXCONN))
{
cout << "Listen()函数执行出现错误.\n" << endl;
return false;
}
else
{
cout << "Listen() 完成.\n" << endl;
}
// 使用AcceptEx函数,因为这个是属于WinSock2规范之外的微软另外提供的扩展函数
// 所以需要额外获取一下函数的指针,
// 获取AcceptEx函数指针
DWORD dwBytes = 0;
if (SOCKET_ERROR == WSAIoctl(
m_pListenContext->m_Socket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&m_lpfnAcceptEx,
sizeof(m_lpfnAcceptEx),
&dwBytes,
NULL,
NULL))
{
cout << "WSAIoctl 未能获取AcceptEx函数指针。错误代码: %d\n" << WSAGetLastError() << endl;
_DeInitialize();
return false;
}
// 获取GetAcceptExSockAddrs函数指针,也是同理
if (SOCKET_ERROR == WSAIoctl(
m_pListenContext->m_Socket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidGetAcceptExSockAddrs,
sizeof(GuidGetAcceptExSockAddrs),
&m_lpfnGetAcceptExSockAddrs,
sizeof(m_lpfnGetAcceptExSockAddrs),
&dwBytes,
NULL,
NULL))
{
cout << "WSAIoctl 未能获取GuidGetAcceptExSockAddrs函数指针。错误代码: %d\n" << WSAGetLastError() << endl;
_DeInitialize();
return false;
}
// 为AcceptEx 准备参数,然后投递AcceptEx I/O请求
//创建10个套接字,投递AcceptEx请求,即共有10个套接字进行accept操作;
for (int i = 0; i < MAX_POST_ACCEPT; i++)
{
// 新建一个IO_CONTEXT
PER_IO_CONTEXT* pAcceptIoContext = m_pListenContext->GetNewIoContext();
if (false == _PostAccept(pAcceptIoContext))
{
m_pListenContext->RemoveContext(pAcceptIoContext);
return false;
}
}
cout << "投递 %d 个AcceptEx请求完毕" << MAX_POST_ACCEPT << endl;
WaitForMultipleObjects(m_nThreads, m_phWorkerThreads, 0, INFINITE);
stop();
system("pause");
return 0;
}
unsigned __stdcall _WorkerThread(LPVOID lpParam)
{
THREADPARAMS_WORKER* pParam = (THREADPARAMS_WORKER*)lpParam;
int nThreadNo = (int)pParam->nThreadNo;
cout << "工作者线程启动,ID: %d." << nThreadNo << endl;
OVERLAPPED *pOverlapped = NULL;
PER_SOCKET_CONTEXT *pSocketContext = NULL;
DWORD dwBytesTransfered = 0;
//循环处理请求,直到接收到Shutdown信息为止
while (WAIT_OBJECT_0 != WaitForSingleObject(m_hShutdownEvent, 0))
{
BOOL bReturn = GetQueuedCompletionStatus(m_hIOCompletionPort, &dwBytesTransfered, (PULONG_PTR)&pSocketContext, &pOverlapped, INFINITE);
//接收EXIT_CODE退出标志,则直接退出
if (EXIT_CODE == (DWORD)pSocketContext)
{
break;
}
//返回值为0,表示出错
if (!bReturn)
{
DWORD dwErr = GetLastError();
// 显示一下提示信息
if (!HandleError(pSocketContext, dwErr))
{
break;
}
continue;
}
else
{
// 读取传入的参数
PER_IO_CONTEXT* pIoContext = CONTAINING_RECORD(pOverlapped, PER_IO_CONTEXT, m_Overlapped);
// 判断是否有客户端断开了
if ((0 == dwBytesTransfered) && (RECV_POSTED == pIoContext->m_OpType || SEND_POSTED == pIoContext->m_OpType))
{
cout << "客户端 %s:%d 断开连接." << inet_ntoa(pSocketContext->m_ClientAddr.sin_addr) << ntohs(pSocketContext->m_ClientAddr.sin_port) << endl;
// 释放掉对应的资源
_RemoveContext(pSocketContext);
continue;
}
else
{
switch (pIoContext->m_OpType)
{
// Accept
case ACCEPT_POSTED:
{
pIoContext->m_nTotalBytes = dwBytesTransfered;
_DoAccpet(pSocketContext, pIoContext);
}
break;
// RECV
case RECV_POSTED:
{
pIoContext->m_nTotalBytes = dwBytesTransfered;
_DoRecv(pSocketContext, pIoContext);
}
break;
case SEND_POSTED:
{
pIoContext->m_nSendBytes += dwBytesTransfered;
if (pIoContext->m_nSendBytes < pIoContext->m_nTotalBytes)
{
//数据未能发送完,继续发送数据
pIoContext->m_wsaBuf.buf = pIoContext->m_szBuffer + pIoContext->m_nSendBytes;
pIoContext->m_wsaBuf.len = pIoContext->m_nTotalBytes - pIoContext->m_nSendBytes;
PostWrite(pIoContext);
}
else
{
PostRecv(pIoContext);
}
}
break;
default:
// 不应该执行到这里
cout << "_WorkThread中的 pIoContext->m_OpType 参数异常.\n" << endl;
break;
} //switch
}//if
}//if
}//while
cout << "工作者线程 %d 号退出.\n" << nThreadNo << endl;
// 释放线程参数
RELEASE(lpParam);
return 0;
}
void _DeInitialize()
{
// 删除客户端列表的互斥量
DeleteCriticalSection(&m_csContextList);
// 关闭系统退出事件句柄
RELEASE_HANDLE(m_hShutdownEvent);
// 释放工作者线程句柄指针
for (int i = 0; i < m_nThreads; i++)
{
RELEASE_HANDLE(m_phWorkerThreads[i]);
}
RELEASE(m_phWorkerThreads);
// 关闭IOCP句柄
RELEASE_HANDLE(m_hIOCompletionPort);
// 关闭监听Socket
RELEASE(m_pListenContext);
cout << "释放资源完毕.\n" << endl;
}
bool _PostAccept(PER_IO_CONTEXT* pAcceptIoContext)
{
// 准备参数
DWORD dwBytes = 0;
pAcceptIoContext->m_OpType = ACCEPT_POSTED;
WSABUF *p_wbuf = &pAcceptIoContext->m_wsaBuf;
OVERLAPPED *p_ol = &pAcceptIoContext->m_Overlapped;
// 为以后新连入的客户端先准备好Socket( 这个是与传统accept最大的区别 )
pAcceptIoContext->m_sockAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == pAcceptIoContext->m_sockAccept)
{
cout << "创建用于Accept的Socket失败!错误代码: %d" << WSAGetLastError() << endl;
return false;
}
// 投递AcceptEx
if (FALSE == m_lpfnAcceptEx(m_pListenContext->m_Socket, pAcceptIoContext->m_sockAccept, p_wbuf->buf, p_wbuf->len - ((sizeof(SOCKADDR_IN) + 16) * 2),
sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, &dwBytes, p_ol))
{
if (WSA_IO_PENDING != WSAGetLastError())
{
cout << "投递 AcceptEx 请求失败,错误代码: %d" << WSAGetLastError() << endl;
return false;
}
}
return true;
}
bool HandleError(PER_SOCKET_CONTEXT *pContext, const DWORD& dwErr)
{
// 如果是超时了,就再继续等吧
if (WAIT_TIMEOUT == dwErr)
{
// 确认客户端是否还活着...
if (!_IsSocketAlive(pContext->m_Socket))
{
cout << "检测到客户端异常退出!" << endl;
_RemoveContext(pContext);
return true;
}
else
{
cout << "网络操作超时!重试中..." << endl;
return true;
}
}
// 可能是客户端异常退出了
else if (ERROR_NETNAME_DELETED == dwErr)
{
cout << "检测到客户端异常退出!" << endl;
_RemoveContext(pContext);
return true;
}
else
{
cout << "完成端口操作出现错误,线程退出。错误代码:%d" << dwErr;
return false;
}
}
void _RemoveContext(PER_SOCKET_CONTEXT *pSocketContext)
{
EnterCriticalSection(&m_csContextList);
for (int i = 0; i < m_arrayClientContext.size(); i++)
{
if (pSocketContext == m_arrayClientContext.at(i))
{
RELEASE(pSocketContext);
m_arrayClientContext.erase(m_arrayClientContext.begin() + i);
break;
}
}
LeaveCriticalSection(&m_csContextList);
}
bool _IsSocketAlive(SOCKET s)
{
int nByteSent = send(s, "", 0, 0);
if (-1 == nByteSent)
return false;
return true;
}
bool _DoAccpet(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext)
{
if (pIoContext->m_nTotalBytes > 0)
{
//客户接入时,第一次接收dwIOSize字节数据
_DoFirstRecvWithData(pIoContext);
}
else
{
//客户端接入时,没有发送数据,则投递WSARecv请求,接收数据
_DoFirstRecvWithoutData(pIoContext);
}
// 5. 使用完毕之后,把Listen Socket的那个IoContext重置,然后准备投递新的AcceptEx
pIoContext->ResetBuffer();
return _PostAccept(pIoContext);
}
bool _DoFirstRecvWithoutData(PER_IO_CONTEXT* pIoContext)
{
//为新接入的套接字创建PER_SOCKET_CONTEXT结构,并绑定到完成端口
PER_SOCKET_CONTEXT* pNewSocketContext = new PER_SOCKET_CONTEXT;
SOCKADDR_IN ClientAddr;
int Len = sizeof(ClientAddr);
getpeername(pIoContext->m_sockAccept, (sockaddr*)&ClientAddr, &Len);
pNewSocketContext->m_Socket = pIoContext->m_sockAccept;
memcpy(&(pNewSocketContext->m_ClientAddr), &ClientAddr, sizeof(SOCKADDR_IN));
//将该套接字绑定到完成端口
if (false == _AssociateWithIOCP(pNewSocketContext))
{
RELEASE(pNewSocketContext);
return false;
}
//投递WSARecv请求,接收数据
PER_IO_CONTEXT* pNewIoContext = pNewSocketContext->GetNewIoContext();
//此时是AcceptEx未接收到客户端第一次发送的数据,所以这里调用PostRecv,接收来自客户端的数据
if (false == PostRecv(pNewIoContext))
{
pNewSocketContext->RemoveContext(pNewIoContext);
return false;
}
//如果投递成功,那么就把这个有效的客户端信息,加入到ContextList中去(需要统一管理,方便释放资源)
_AddToContextList(pNewSocketContext);
return true;
}
void _AddToContextList(PER_SOCKET_CONTEXT *pHandleData)
{
EnterCriticalSection(&m_csContextList);
m_arrayClientContext.push_back(pHandleData);
LeaveCriticalSection(&m_csContextList);
}
bool PostRecv(PER_IO_CONTEXT* pIoContext)
{
// 初始化变量
DWORD dwFlags = 0;
DWORD dwBytes = 0;
WSABUF *p_wbuf = &pIoContext->m_wsaBuf;
OVERLAPPED *p_ol = &pIoContext->m_Overlapped;
pIoContext->ResetBuffer();
pIoContext->m_OpType = RECV_POSTED;
pIoContext->m_nSendBytes = 0;
pIoContext->m_nTotalBytes = 0;
// 初始化完成后,,投递WSARecv请求
int nBytesRecv = WSARecv(pIoContext->m_sockAccept, p_wbuf, 1, &dwBytes, &dwFlags, p_ol, NULL);
// 如果返回值错误,并且错误的代码并非是Pending的话,那就说明这个重叠请求失败了
if ((SOCKET_ERROR == nBytesRecv) && (WSA_IO_PENDING != WSAGetLastError()))
{
cout << "投递第一个WSARecv失败!" << endl;
return false;
}
return true;
}
// 将句柄(Socket)绑定到完成端口中
bool _AssociateWithIOCP(PER_SOCKET_CONTEXT *pContext)
{
// 将用于和客户端通信的SOCKET绑定到完成端口中
HANDLE hTemp = CreateIoCompletionPort((HANDLE)pContext->m_Socket, m_hIOCompletionPort, (DWORD)pContext, 0);
if (NULL == hTemp)
{
cout << "执行CreateIoCompletionPort()出现错误.错误代码:%d" << GetLastError() << endl;
return false;
}
return true;
}
bool _DoFirstRecvWithData(PER_IO_CONTEXT* pIoContext)
{
SOCKADDR_IN* ClientAddr = NULL;
SOCKADDR_IN* LocalAddr = NULL;
int remoteLen = sizeof(SOCKADDR_IN), localLen = sizeof(SOCKADDR_IN);
//1. 首先取得连入客户端的地址信息
m_lpfnGetAcceptExSockAddrs(pIoContext->m_wsaBuf.buf, pIoContext->m_wsaBuf.len - ((sizeof(SOCKADDR_IN) + 16) * 2),
sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, (LPSOCKADDR*)&LocalAddr, &localLen, (LPSOCKADDR*)&ClientAddr, &remoteLen);
//显示客户端信息
cout << "客户额 %s:%d 信息:%s." << inet_ntoa(ClientAddr->sin_addr) << ntohs(ClientAddr->sin_port) << pIoContext->m_wsaBuf.buf << endl;
//2.为新接入的套接创建PER_SOCKET_CONTEXT,并将该套接字绑定到完成端口
PER_SOCKET_CONTEXT* pNewSocketContext = new PER_SOCKET_CONTEXT;
pNewSocketContext->m_Socket = pIoContext->m_sockAccept;
memcpy(&(pNewSocketContext->m_ClientAddr), ClientAddr, sizeof(SOCKADDR_IN));
// 参数设置完毕,将这个Socket和完成端口绑定(这也是一个关键步骤)
if (false == _AssociateWithIOCP(pNewSocketContext))
{
RELEASE(pNewSocketContext);
return false;
}
//3. 继续,建立其下的IoContext,用于在这个Socket上投递第一个Recv数据请求
PER_IO_CONTEXT* pNewIoContext = pNewSocketContext->GetNewIoContext();
pNewIoContext->m_OpType = SEND_POSTED;
pNewIoContext->m_sockAccept = pNewSocketContext->m_Socket;
pNewIoContext->m_nTotalBytes = pIoContext->m_nTotalBytes;
pNewIoContext->m_nSendBytes = 0;
pNewIoContext->m_wsaBuf.len = pIoContext->m_nTotalBytes;
memcpy(pNewIoContext->m_wsaBuf.buf, pIoContext->m_wsaBuf.buf, pIoContext->m_nTotalBytes); //复制数据到WSASend函数的参数缓冲区
//此时是第一次接收数据成功,所以这里投递PostWrite,向客户端发送数据
if (false == PostWrite(pNewIoContext))
{
pNewSocketContext->RemoveContext(pNewIoContext);
return false;
}
//4. 如果投递成功,那么就把这个有效的客户端信息,加入到ContextList中去(需要统一管理,方便释放资源)
_AddToContextList(pNewSocketContext);
return true;
}
bool PostWrite(PER_IO_CONTEXT* pIoContext)
{
// 初始化变量
DWORD dwFlags = 0;
DWORD dwSendNumBytes = 0;
WSABUF *p_wbuf = &pIoContext->m_wsaBuf;
OVERLAPPED *p_ol = &pIoContext->m_Overlapped;
pIoContext->m_OpType = SEND_POSTED;
//投递WSASend请求 -- 需要修改
int nRet = WSASend(pIoContext->m_sockAccept, &pIoContext->m_wsaBuf, 1, &dwSendNumBytes, dwFlags,
&pIoContext->m_Overlapped, NULL);
// 如果返回值错误,并且错误的代码并非是Pending的话,那就说明这个重叠请求失败了
if ((SOCKET_ERROR == nRet) && (WSA_IO_PENDING != WSAGetLastError()))
{
cout << "投递WSASend失败!" << endl;
return false;
}
return true;
}
bool _DoRecv(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext)
{
//输出接收的数据
SOCKADDR_IN* ClientAddr = &pSocketContext->m_ClientAddr;
cout << "收到 %s:%d 信息:%s" << inet_ntoa(ClientAddr->sin_addr) << ntohs(ClientAddr->sin_port) << pIoContext->m_wsaBuf.buf << endl;
//发送数据
pIoContext->m_nSendBytes = 0;
pIoContext->m_nTotalBytes = pIoContext->m_nTotalBytes;
pIoContext->m_wsaBuf.len = pIoContext->m_nTotalBytes;
pIoContext->m_wsaBuf.buf = pIoContext->m_szBuffer;
return PostWrite(pIoContext);
}
void stop()
{
if (m_pListenContext != NULL && m_pListenContext->m_Socket != INVALID_SOCKET)
{
// 激活关闭消息通知
SetEvent(m_hShutdownEvent);
for (int i = 0; i < m_nThreads; i++)
{
// 通知所有的完成端口操作退出
PostQueuedCompletionStatus(m_hIOCompletionPort, 0, (DWORD)EXIT_CODE, NULL);
}
// 等待所有的客户端资源退出
WaitForMultipleObjects(m_nThreads, m_phWorkerThreads, TRUE, INFINITE);
// 清除客户端列表信息
_ClearContextList();
// 释放其他资源
_DeInitialize();
}
}
void _ClearContextList()
{
EnterCriticalSection(&m_csContextList);
for (int i = 0; i < m_arrayClientContext.size(); i++)
{
delete m_arrayClientContext.at(i);
}
m_arrayClientContext.clear();
LeaveCriticalSection(&m_csContextList);
}