⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpserver.cpp

📁 Socketlib: 一个轻量级的C++ 封装Socket C API 网络编程框架。 它简化了Socket异步事件分派、进程间Socket通信的并发OO网络应用和服务的开发。 目前
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//**********************************************************************
//
// 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 + -