#include "stdafx.h"
#include "NetServer.h"
/***********************************************************************************
静态函数:初始化winsock库
***********************************************************************************/
BOOL CNetServer::InitSock(BYTE minVer, BYTE maxVer)
{
WSADATA WsaData;
if (0 != WSAStartup(MAKEWORD(minVer, maxVer), &WsaData))
{
return FALSE;
}
return TRUE;
}
/***********************************************************************************
静态函数: 释放清除winsock库
***********************************************************************************/
void CNetServer::CleanSock()
{
WSACleanup();
}
//////////////////////////////////////////////////////////////////////////
CNetServer::CNetServer():
m_bStartServer(FALSE),
m_sListen(INVALID_SOCKET),
m_hListenThread(NULL)
{
}
CNetServer::~CNetServer()
{
Stop();
}
/***********************************************************************************
开始服务, 绑定端口, 监听接受连接
***********************************************************************************/
BOOL CNetServer::Start(int nPort)
{
if (m_bStartServer)
{
return FALSE;
}
// 创建监听套节字,绑定到本地端口,进入监听模式
m_sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKADDR_IN si;
si.sin_family = AF_INET;
si.sin_port = ::ntohs(nPort);
si.sin_addr.S_un.S_addr = INADDR_ANY;
if(::bind(m_sListen, (sockaddr*)&si, sizeof(si)) == SOCKET_ERROR)
{
m_bStartServer = FALSE;
return FALSE;
}
::listen(m_sListen, 10);
m_hListenThread = CreateThread(NULL, 0, ListenThreadProc, this, 0, NULL);
ASSERT(m_hListenThread);
m_bStartServer = TRUE;
return TRUE;
}
/***********************************************************************************
停止服务,结束监听和工作线程
***********************************************************************************/
void CNetServer::Stop()
{
if (!m_bStartServer)
{
return;
}
m_bStartServer = FALSE;
//退出监听线程
if (INVALID_SOCKET != m_sListen)
{
closesocket(m_sListen);
m_sListen = INVALID_SOCKET;
}
if (m_hListenThread)
{
WaitForSingleObject(m_hListenThread, INFINITE);
CloseHandle(m_hListenThread);
m_hListenThread = NULL;
}
//退出所有工作线程并释放相关资源
list<PTHREAD_OBJ>::iterator iterOuter;
InnerLock lock(m_cs_Send);
{
InnerLock lock(m_cs_ThreadObjList);
for (iterOuter = m_ThreadObjList.begin(); iterOuter != m_ThreadObjList.end(); ++iterOuter)
{
PTHREAD_OBJ pThreadObj = *iterOuter;
pThreadObj->dwEventCount = 2;
SetEvent(pThreadObj->hRebuildEvent);
FreeThreadObj(pThreadObj);
}
m_ThreadObjList.clear();
}
{
InnerLock lock(m_cs_ConnectionList);
m_ConnectionList.clear();
}
}
/***********************************************************************************
创建缓冲区对象
***********************************************************************************/
CNetServer::BUFFER_OBJ* CNetServer::AllocBufferObj(SOCKET s, DWORD dwSize)
{
PBUFFER_OBJ pBufferObj = new BUFFER_OBJ;
if (NULL == pBufferObj)
{
return NULL;
}
pBufferObj->pData = new char[dwSize];
if (NULL == pBufferObj->pData)
{
return NULL;
}
ZeroMemory(pBufferObj->pData, dwSize);
pBufferObj->s = s;
pBufferObj->dwSize = dwSize;
pBufferObj->ol.hEvent = WSACreateEvent();
return pBufferObj;
}
/***********************************************************************************
释放缓冲区对象
***********************************************************************************/
void CNetServer::FreeBufferObj(PBUFFER_OBJ pBufferObj)
{
if (NULL == pBufferObj)
{
return;
}
if (pBufferObj->s != INVALID_SOCKET)
{
closesocket(pBufferObj->s);
pBufferObj->s = INVALID_SOCKET;
}
if (pBufferObj->ol.hEvent)
{
WSACloseEvent(pBufferObj->ol.hEvent);
pBufferObj->ol.hEvent = NULL;
}
delete []pBufferObj->pData;
delete pBufferObj;
}
/***********************************************************************************
查找得到某个缓冲区对象
入口
pThreadObj:关联的线程对象
hEvent: 匹配事件对象
出口
若查找成功,则返回对应的缓冲区对象; 否则返回空指针
***********************************************************************************/
CNetServer::BUFFER_OBJ* CNetServer::GetBufferObj(PTHREAD_OBJ pThreadObj, HANDLE hEvent)
{
ASSERT(pThreadObj);
PBUFFER_OBJ pBufferObj = NULL;
list<PBUFFER_OBJ>::iterator iter;
InnerLock lock(pThreadObj->cs);
list<PBUFFER_OBJ> &BufferObjList = pThreadObj->BufferObjList;
for (iter = BufferObjList.begin(); iter != BufferObjList.end(); ++iter)
{
if ((*iter)->ol.hEvent == hEvent)
{
pBufferObj = *iter;
break;
}
}
return pBufferObj;
}
/***********************************************************************************
查找得到某个缓冲区对象
入口
strIP: 匹配IP地址
nPort: 匹配端口
出口
若查找成功, 则返回对应的缓冲区对象; 否则返回空指针
***********************************************************************************/
CNetServer::BUFFER_OBJ* CNetServer::GetBufferObj(const string& strIP, int nPort)
{
list<PBUFFER_OBJ>::iterator iter;
PBUFFER_OBJ pBufferObj = NULL;
InnerLock lock(m_cs_ConnectionList);
for (iter = m_ConnectionList.begin(); iter!= m_ConnectionList.end(); ++iter)
{
if ((*iter)->addr.sin_addr.s_addr == inet_addr(strIP.c_str()) && (*iter)->addr.sin_port == htons(nPort))
{
pBufferObj = *iter;
break;
}
}
return pBufferObj;
}
/***********************************************************************************
插入缓冲区对象到连接列表, 支持多线程同步
由于为避免同步socket,简化操作, 采用双向连接,即读数据一个连接, 写数据一个连接
因此连接列表所维持的缓冲区对象是与发送操作, 连接操作相关联的。
***********************************************************************************/
void CNetServer::InsertBufferObjToConnectList(PBUFFER_OBJ pBufferObj)
{
ASSERT(pBufferObj);
ASSERT(pBufferObj->nIoType == IO_WRITE || pBufferObj->nIoType == IO_CONNECT);
InnerLock lock(m_cs_ConnectionList);
m_ConnectionList.push_back(pBufferObj);
}
/***********************************************************************************
从连接列表移除缓冲区对象, 支持多线程同步
由于为避免同步socket,简化操作, 采用双向连接,即读数据一个连接, 写数据一个连接
因此连接列表所维持的缓冲区对象是与发送操作, 连接操作相关联的。
***********************************************************************************/
void CNetServer::RemoveBufferObjFromConnectList(PBUFFER_OBJ pBufferObj)
{
ASSERT(pBufferObj);
ASSERT(pBufferObj->nIoType == IO_WRITE || pBufferObj->nIoType == IO_CONNECT);
InnerLock lock(m_cs_ConnectionList);
m_ConnectionList.remove(pBufferObj);
}
/***********************************************************************************
创建并初始化线程对象
***********************************************************************************/
CNetServer::THREAD_OBJ* CNetServer::AllocThreadObj()
{
PTHREAD_OBJ pThreadObj = new THREAD_OBJ;
if (NULL == pThreadObj)
{
return NULL;
}
pThreadObj->EventArray[0] = pThreadObj->hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
pThreadObj->EventArray[1] = pThreadObj->hRebuildEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pThreadObj->dwEventCount = 2;
pThreadObj->pNetServer = this;
return pThreadObj;
}
/***********************************************************************************
释放线程对象
入口
pThreadObj: 要释放的线程对象
描述
先结束对象关联的IO线程
再释放该线程关联的所有缓冲区对象
******************************************************************************
重叠IO模型实现的网络通讯类
4星 · 超过85%的资源 需积分: 9 191 浏览量
2009-02-12
18:02:09
上传
评论
收藏 7KB RAR 举报
qinshubo1984
- 粉丝: 5
- 资源: 25
- 1
- 2
前往页