#include "StdAfx.h"
#include "TCP.h"
#include "AutoLock.h"
CTCP::CTCP(TCP::PFNPutTip pfnPutTip, void * pThis)
: m_SocketBuf(pfnPutTip, pThis)
, m_ContextBuf(pfnPutTip, pThis)
{
m_pfnPutTip = pfnPutTip;
m_pThis = pThis;
}
CTCP::~CTCP(void)
{
}
/******************************************************************************
初始化
******************************************************************************/
void CTCP::Init(void)
{
//初始化套接字缓冲区
m_SocketBuf.Init();
//初始化上下文缓冲区
m_ContextBuf.Init();
m_hIOCP = NULL;
m_uiThreadCnt = 0;
m_pThreadSem = NULL;
m_pfnAcceptEx = NULL;
m_pfnConnectEx = NULL;
m_pfnGetAcceptExSockaddrs = NULL;
//启动并创建IOCP
_StartupCreateIOCP();
//启动IOCP线程
_StartupIOCPThread();
//加载扩展函数
_LoadExFunc();
}
/******************************************************************************
绑定
******************************************************************************/
bool CTCP::Bind(SOCKET & socket, unsigned short usPort)
{
//创建套接字
if (usPort <= 0)
{
_PutTip("", TCP::BIND_PORT_INVALID);
return false;
}
socket = m_SocketBuf.Create(usPort);
if (socket == INVALID_SOCKET)
{
return false;
}
return true;
}
/******************************************************************************
监听
******************************************************************************/
void CTCP::Listen(SOCKET socket, ContextBuf::PFNAccept pfnAccept, void * pThis)
{
//关联套接字
if (m_hIOCP == NULL
|| socket == INVALID_SOCKET)
{
_PutTip("", TCP::LISTEN_ASSOCIATE_SOCKET_PARAM);
return;
}
if (CreateIoCompletionPort((HANDLE)socket, m_hIOCP, socket, 0) != m_hIOCP)
{
_PutTip("", TCP::LISTEN_ASSOCIATE_SOCKET_FAIL);
return;
}
//监听套接字
if (listen(socket, SOMAXCONN) != 0)
{
_PutTip("", TCP::LISTEN_LISTEN_FAIL);
return;
}
//分配接受上下文
if (pfnAccept == NULL
|| pThis == NULL)
{
_PutTip("", TCP::LISTEN_ALLOC_PARAM);
return;
}
ContextBuf::SAcceptContext * pAcceptContext =
m_ContextBuf.AllocAccept(pfnAccept, pThis);
//设置套接字有效
_SetSocketValid(socket, pAcceptContext);
//投递接受请求
_PostAccept(socket, pAcceptContext);
}
/******************************************************************************
接收
******************************************************************************/
void CTCP::Recv(SOCKET socket, ContextBuf::PFNRecv pfnRecv, void * pThis)
{
//分配接收上下文
if (pfnRecv == NULL
|| pThis == NULL)
{
_PutTip("", TCP::RECV_ALLOC_PARAM);
return;
}
ContextBuf::SRecvContext * pRecvContext =
m_ContextBuf.AllocRecv(pfnRecv, pThis);
//设置套接字有效
_SetSocketValid(socket, pRecvContext);
//投递接收请求
_PostRecv(socket, pRecvContext);
}
/******************************************************************************
连接
******************************************************************************/
void CTCP::Conn(SOCKET & socket, unsigned long ulIP, unsigned short usPort
, ContextBuf::PFNConn pfnConn, void * pThis)
{
//创建套接字
socket = m_SocketBuf.Create(0);
//关联套接字
if (socket == INVALID_SOCKET
|| m_hIOCP == NULL)
{
_PutTip("", TCP::CONN_ASSOCIATE_SOCKET_PARAM);
return;
}
if (CreateIoCompletionPort((HANDLE)socket, m_hIOCP, socket, 0) != m_hIOCP)
{
_PutTip("", TCP::CONN_ASSOCIATE_SOCKET_FAIL);
return;
}
//填写地址信息
if (ulIP == 0
|| usPort <= 0
|| usPort >= 65535)
{
_PutTip("", TCP::CONN_ADDR_INVALID);
return;
}
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = ulIP;
addr.sin_port = htons(usPort);
//分配连接上下文
if (pfnConn == NULL
|| pThis == NULL)
{
_PutTip("", TCP::CONN_ALLOC_PARAM);
return;
}
ContextBuf::SConnContext * pConnContext =
m_ContextBuf.AllocConn(pfnConn, pThis);
//投递连接请求
_PostConn(socket, addr, pConnContext);
}
/******************************************************************************
发送
******************************************************************************/
void CTCP::Send(SOCKET socket, void * pData, unsigned int uiDataSize)
{
//分配发送上下文
if (pData == NULL
|| uiDataSize <= 0)
{
_PutTip("", TCP::SEND_ALLOC_PARAM);
return;
}
ContextBuf::SSendContext * pSendContext =
m_ContextBuf.AllocSend(pData, uiDataSize);
//投递发送请求
if (socket == INVALID_SOCKET
|| pSendContext == NULL
|| pSendContext->buf.buf == NULL
|| pSendContext->buf.len <= 0)
{
_PutTip("", TCP::SEND_SEND_PARAM);
return;
}
if (WSASend(socket, &pSendContext->buf, 1
, NULL, 0, &pSendContext->overlap, NULL) != 0)
{
//获取错误码
int iErr = WSAGetLastError();
//已经断开
if (iErr == WSAECONNRESET
|| iErr == WSAECONNABORTED)
{
//释放上下文
m_ContextBuf.Free(pSendContext);
return;
}
if (iErr != WSA_IO_PENDING)
{
string strErr = "";
//把错误码接入错误串
char acBuf[12] = {0};
_itoa_s(iErr, acBuf, sizeof(acBuf), 10);
strErr += acBuf;
strErr += ".";
//输出提示
_PutTip("", TCP::SEND_SEND_FAIL, strErr);
return;
}
}
}
/******************************************************************************
关闭
******************************************************************************/
void CTCP::Close(SOCKET socket)
{
//套接字有效互斥锁
CAutoLock lock(&m_csSocketValid, m_pfnPutTip, m_pThis);
//从套接字有效表中删除
if (socket == INVALID_SOCKET)
{
_PutTip("", TCP::CLOSE_SOCKET_INVALID);
return;
}
try
{
m_mapSocketValid.erase(socket);
}
catch (...)
{
_PutTip("", TCP::CLOSE_ERASE_EXCEPTION);
return;
}
//关闭套接字
m_SocketBuf.Close(socket);
}
/******************************************************************************
停止
******************************************************************************/
void CTCP::Stop(void)
{
//退出IOCP线程
_ExitIOCPThread();
//清空套接字缓冲区
m_SocketBuf.Clear();
//清空上下文缓冲区
m_ContextBuf.Clear();
//清理网络
_CleanupNet();
}
/******************************************************************************
启动并创建IOCP
******************************************************************************/
void CTCP::_StartupCreateIOCP(void)
{
//启动套接字
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
_PutTip("", TCP::STARTUP_CREATE_IOCP_STARTUP_FAIL);
return;
}
//判断套接字版本
if (LOBYTE(wsaData.wVersion) != 2
|| HIBYTE(wsaData.wVersion) != 2)
{
_PutTip("", TCP::STARTUP_CREATE_IOCP_VER_ERR);
return;
}
//创建IOCP
m_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (m_hIOCP == NULL)
{
_PutTip("", TCP::STARTUP_CREATE_IOCP_CREATE_FAIL);
return;
}
}
/******************************************************************************
启动IOCP线程
******************************************************************************/
void CTCP::_StartupIOCPThread(void)
{
//获取CPU数量
SYSTEM_INFO si;
GetSystemInfo(&si);
//CPU数量的线程数
m_uiThreadCnt = si.dwNumberOfProcessors;
//新建线程信号量
if (m_uiThreadCnt <= 0)
{
_PutTip("", TCP::STARTUP_IOCP_THREAD_THREAD_CNT_INVALID);
return;
}
try
{
m_pThreadSem = new CSemaphore(m_uiThreadCnt, m_uiThreadCnt);
}
catch (...)
{
_PutTip("", TCP::STARTUP_IOCP_THREAD_NEW_SEM_EXCEPTION);
return;
}
if (m_pThreadSem == NULL)
{
_PutTip("", TCP::STARTUP_IOCP_THREAD_NEW_SEM_NULL);
return;
}
//启动线程
for (int i = 0; i < (int)m_uiThreadCnt; i++)
{
//线程信号量加锁
if (!m_pThreadSem->Lock())
{
_PutTip("", TCP::STARTUP_IOCP_THREAD_SEM_LOCK_FAIL);
return;
}
//启动IOCP工作线程
CWinThread * pThread = AfxBeginThread(_threadIOCPWork, this);
if (pThread == NULL)
{
_PutTip("", TCP::STARTUP_IOCP_THREAD_BEGIN_