📄 tcpserver.cpp
字号:
//**********************************************************************
//
// Copyright (C) 2005-2007 Zhang bao yuan(bolidezhang@gmail.com).
// All rights reserved.
//
// This copy of Socketlib is licensed to you under the terms described
// in the LICENSE.txt file included in this distribution.
//
//**********************************************************************
#include ".\tcpserver.h"
#include "SocketEvent.h"
#include "SocketAPI.h"
#include <assert.h>
namespace SL
{
CTcpServer::CTcpServer(void)
: m_bIsStart(false)
, m_nMaxSocketNum(MAX_SOCKET_CONNECTNUM)
, m_nMaxFreePoolNum(MAX_SOCKET_FREENUM)
, m_nDefaultFreePoolNum(10)
, m_hListenSocket(NULL)
{
InitializeCriticalSection(&m_lock);
}
CTcpServer::~CTcpServer(void)
{
Close();
DeleteCriticalSection(&m_lock);
}
inline bool CTcpServer::PostRecv(SOCKET hClientSocket, void *p)
{
//if ( (hClientSocket == INVALID_SOCKET) || (p == NULL) || (!m_bIsStart) )
//{
// return false;
//}
PPER_IO_OPERATION_DATA pPerIoData = (PPER_IO_OPERATION_DATA)p;
//EnterCriticalSection(&(pPerIoData->IoLock));
//重置IO操作数据
DWORD nFlag = 0;
DWORD nRecvByte = 0;
ZeroMemory(&(pPerIoData->Overlapped),sizeof(OVERLAPPED));
//ZeroMemory(pPerIoData->szDataBuffer, m_nRecvBufferSize);
pPerIoData->SocketBuf.buf = pPerIoData->szDataBuffer;
pPerIoData->SocketBuf.len = m_nRecvBufferSize;
pPerIoData->OperType = RECV_POSTED;
//提交PostRecv请求
int nRet = WSARecv(hClientSocket, &(pPerIoData->SocketBuf), 1,
&nRecvByte, &nFlag, &(pPerIoData->Overlapped), NULL);
//LeaveCriticalSection(&(pPerIoData->IoLock));
if ( nRet==SOCKET_ERROR )
{
if ( WSAGetLastError() != WSA_IO_PENDING )
{//接收失败,最有可能是Socket已断开,所以按断开处理
Disconnect(hClientSocket);
return false;
}
}
return true;
}
void CTcpServer::SetConfig(int nMaxSocketNum, int nMaxFreePoolNum, int nDefaultFreePoolNum)
{
m_nMaxSocketNum = nMaxSocketNum;
m_nMaxFreePoolNum = nMaxFreePoolNum;
m_nDefaultFreePoolNum = nDefaultFreePoolNum;
return;
}
void CTcpServer::SetInterface(CAppLog *pAppLog, CSocketEvent *pSocketEvent, CSocketRunner *pSocketRunner)
{
assert(pAppLog != NULL);
assert(pSocketEvent != NULL);
assert(pSocketRunner != NULL);
m_pAppLog = pAppLog;
m_pSocketEvent = pSocketEvent;
m_pSocketRunner = pSocketRunner;
return;
}
inline void CTcpServer::SetBufferSize(int nRecvBufferSize, int nSendBufferSize)
{
if (nRecvBufferSize > 0)
m_nRecvBufferSize = nRecvBufferSize;
return;
}
unsigned int WINAPI CTcpServer::ListenProc(LPVOID lParam)
{
CTcpServer *pSvr = (CTcpServer*)lParam;
SOCKET hClientSocket;
SOCKADDR_IN siClientSocketAddr;
int nClientSocketLen;
char szIPAddr[MAX_IPADDR_LENGTH];
USHORT nPort = 0;
#ifdef SOCKETLIB_WRITE_LOG
char szLog[MAX_LOGBUFFER_LENGTH];
#endif
nClientSocketLen = sizeof(siClientSocketAddr);
DWORD dwStartTime = 0;
DWORD dwAcceptTime = 0;
for (;;)
{
if (pSvr->m_threadListen.IsStop())
{//退出线程
#ifdef SHOW_PRINTFINFO
printf("ListenProc thread exit!\r\n");
#else
#ifdef SOCKETLIB_WRITE_LOG
pSvr->m_pAppLog->WriteLog("ListenProc thread exit!",__FILE__,__LINE__,CAppLog::LOG_LEVEL_7);
#endif
#endif
break;
}
//置0
memset(szIPAddr, 0, sizeof(szIPAddr));
#ifdef SOCKETLIB_WRITE_LOG
memset(szLog, 0, sizeof(szLog));
#endif
//接收客户的请求
hClientSocket = WSAAccept(pSvr->m_hListenSocket,(SOCKADDR*)&siClientSocketAddr,&nClientSocketLen,NULL,0);
if (INVALID_SOCKET == hClientSocket)
{
#ifdef SHOW_PRINTFINFO
printf("WSAAccept invalid socket!\r\n");
#else
#ifdef SOCKETLIB_WRITE_LOG
pSvr->m_pAppLog->WriteLog("WSAAccept invalid socket!",__FILE__,__LINE__,CAppLog::LOG_LEVEL_7);
#endif
#endif
continue;
}
//打印显示信息
CSocketAPI::GetSocketInfo(hClientSocket, szIPAddr, &nPort);
if ( pSvr->m_mapSocketSession.size() >= pSvr->m_nMaxSocketNum )
{
closesocket(hClientSocket);
#ifdef SHOW_PRINTFINFO
printf("Socket: %d, clientip:%s, port: %d, refuse; current online total:%ld \r\n",
hClientSocket, szIPAddr, nPort, pSvr->m_mapSocketSession.size());
#else
#ifdef SOCKETLIB_WRITE_LOG
sprintf(szLog,"ListenSocket:%ld, clientip:%s, port: %d, refuse; current online total:%ld",
pSvr->m_hListenSocket, szIPAddr, nPort, pSvr->m_mapSocketSession.size());
pSvr->m_pAppLog->WriteLog(szLog, __FILE__, __LINE__, CAppLog::LOG_LEVEL_7);
#endif
#endif
continue;
}
//设置新socket的选项(如接收/发送缓冲区的大小或关闭缓冲区等)
//int nBufferLen = RECV_BUFFER_SIZE;
//setsockopt( hSocket, SOL_SOCKET, SO_SNDBUF, (char *) &nBufferLen, sizeof(int) );
//setsockopt( hSocket, SOL_SOCKET, SO_RCVBUF, (char *) &nBufferLen, sizeof(int) );
if ( !pSvr->m_pSocketEvent->OnAccept(pSvr, hClientSocket) )
{
#ifdef SHOW_PRINTFINFO
printf("ListenSocket:%ld, clientip:%s, port:%d, acceptconnect error!\r\n",
pSvr->m_hListenSocket, szIPAddr, nPort);
#else
#ifdef SOCKETLIB_WRITE_LOG
sprintf(szLog,"ListenSocket:%ld, clientip:%s, port:%d, acceptconnect error!",
pSvr->m_hListenSocket, szIPAddr, nPort);
pSvr->m_pAppLog->WriteLog(szLog, __FILE__, __LINE__, CAppLog::LOG_LEVEL_7);
#endif
#endif
closesocket(hClientSocket);
continue;
}
PSOCKET_SESSION pSocketSession = NULL;
//取得空闲Socket的内存
EnterCriticalSection(&(pSvr->m_lock));
if ( !pSvr->m_lstFreePool.empty() )
{
pSocketSession = pSvr->m_lstFreePool.front();
pSocketSession->PerHandle.hSocket = hClientSocket;
pSocketSession->PerHandle.pSocketSource = pSvr;
ZeroMemory(&(pSocketSession->PerIoRecv.Overlapped), sizeof(OVERLAPPED));
ZeroMemory(&(pSocketSession->PerIoSend.Overlapped), sizeof(OVERLAPPED));
//ZeroMemory(pSocketSession->PerIoRecv.szDataBuffer, pSvr->m_nRecvBufferSize);
pSvr->m_lstFreePool.pop_front();
}
LeaveCriticalSection(&(pSvr->m_lock));
if (NULL == pSocketSession)
{//分配Socket I/O操作数据的内存
char *p = (char*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(SOCKET_SESSION)+pSvr->m_nRecvBufferSize) );
if (NULL == p)
{
#ifdef SHOW_PRINTFINFO
printf("ListenProc:: heapAlloc memory error!\r\n");
#else
#ifdef SOCKETLIB_WRITE_LOG
pSvr->m_pAppLog->WriteLog("ListenProc:: heapAlloc memory error!",__FILE__,__LINE__,CAppLog::LOG_LEVEL_7);
#endif
#endif
closesocket(hClientSocket);
continue;
}
pSocketSession = (PSOCKET_SESSION)p;
pSocketSession->PerHandle.hSocket = hClientSocket;
pSocketSession->PerHandle.pSocketSource = pSvr;
pSocketSession->PerIoRecv.szDataBuffer = (p+sizeof(SOCKET_SESSION));
InitializeCriticalSection(&(pSocketSession->PerIoSend.IoLock));
}
//将Socket关联到完成端口,句柄数据在此时被绑定到完成端口
pSvr->m_pSocketRunner->AssociateSocket(hClientSocket, &(pSocketSession->PerHandle));
//加入Socket集合
EnterCriticalSection(&(pSvr->m_lock));
pSvr->m_mapSocketSession[hClientSocket] = pSocketSession;
LeaveCriticalSection(&(pSvr->m_lock));
//由上层初始化Socket(一般为设置Socket附加信息的指针)
pSvr->m_pSocketEvent->OnInitSocket(&(pSocketSession->PerHandle));
//提交首个接收数据请求
//这时如果客户端断开连接,则也可以接收数据时得到通知
DWORD nFlag = 0;
DWORD nRecvByte = 0 ;
pSocketSession->PerIoRecv.SocketBuf.buf = pSocketSession->PerIoRecv.szDataBuffer;
pSocketSession->PerIoRecv.SocketBuf.len = pSvr->m_nRecvBufferSize;
pSocketSession->PerIoRecv.OperType = RECV_POSTED;
WSARecv(hClientSocket,&(pSocketSession->PerIoRecv.SocketBuf),1,
&nRecvByte,&nFlag,&(pSocketSession->PerIoRecv.Overlapped),NULL);
#ifdef SHOW_PRINTFINFO
printf("ListenSocket:%ld, clientip:%s, port:%d, connected; total:%ld\r\n",
pSvr->m_hListenSocket, szIPAddr, nPort, pSvr->m_mapSocketSession.size());
#else
#ifdef SOCKETLIB_WRITE_LOG
sprintf(szLog,"ListenSocket:%ld, clientip:%s, port:%d, connected; total:%ld",
pSvr->m_hListenSocket, szIPAddr, nPort, pSvr->m_mapSocketSession.size());
pSvr->m_pAppLog->WriteLog(szLog, __FILE__, __LINE__, CAppLog::LOG_LEVEL_5);
#endif
#endif
}
return 0;
}
bool CTcpServer::Open(const char *szServerName, unsigned short nPort, int nBacklog)
{
//创建侦听Socket
m_hListenSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET==m_hListenSocket)
{
#ifdef SHOW_PRINTFINFO
printf("Create listen socket failure!\r\n");
#else
#ifdef SOCKETLIB_WRITE_LOG
m_pAppLog->WriteLog("Create listen socket failure!", __FILE__, __LINE__, CAppLog::LOG_LEVEL_7);
#endif
#endif
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -