www.pudn.com > ChatUseIOCP.rar > DtServerSocket.cpp


#include "StdAfx.h" 
#include ".\dtServerSocket.h" 
#include ".\dtServerSocketClient.h" 
 
Datatal::DtServerSocket::DtServerSocket(void) 
{ 
	m_sdListen = INVALID_SOCKET; 
	m_dwPort = 0; 
	m_dwServerFull = 0; 
	m_nClients = 1; 
	m_nMaxClients = 1; 
} 
 
Datatal::DtServerSocket::~DtServerSocket(void) 
{ 
	StopServer(); 
} 
 
void Datatal::DtServerSocket::StopServer( void ) 
{ 
	m_cs.Lock(); 
	for (size_t i = 0; i < m_paClients.size(); i++)   
	{     
		m_paClients[i]->Disconnect(true); 
	}   
 
	shutdown(m_sdListen, SD_BOTH); 
	closesocket(m_sdListen);   
 
 
	WSACleanup();   
	for (size_t i = 0; i < m_paClients.size(); i++)   
	{     
		delete m_paClients[i];   
	}   
	m_cs.Unlock(); 
} 
 
DWORD Datatal::DtServerSocket::StartServer(DWORD dwListenPort, int nClients, int nMaxClients) 
{ 
	char			szError[512]; 
	DWORD			dwError; 
	SOCKADDR_IN		addr; 
 
	DtLock aLock(m_cs); 
 
	m_nMaxClients = nMaxClients; 
	m_nClients = nClients; 
	m_dwPort = dwListenPort; 
 
 
 
	//Loadup the socket 
	//=============================================================== 
 
	WSADATA wd = {0}; 
	dwError = WSAStartup(MAKEWORD(2, 0), &wd); 
	if (dwError != 0) 
	{ 
		sprintf(szError, "%s; WSAStartup failed, error: %d", GetServerName(), dwError); 
		throw DtServerException(dwError, "StartServer", szError); 
	} 
 
	m_sdListen = socket(AF_INET, SOCK_STREAM, 0); 
	if (m_sdListen == INVALID_SOCKET) 
	{ 
		sprintf(szError, "%s; socket() failed, error: %d", GetServerName(), WSAGetLastError()); 
		throw DtServerException(dwError, "StartServer", szError); 
	} 
 
	addr.sin_family = AF_INET; 
	addr.sin_addr.s_addr = INADDR_ANY; 
	addr.sin_port = htons((short)m_dwPort); 
 
	if (bind(m_sdListen, (SOCKADDR *)&addr, sizeof(addr)) == SOCKET_ERROR) 
	{ 
		sprintf(szError, "%s; bind() failed, error: %d", GetServerName(), WSAGetLastError()); 
		throw DtServerException(dwError, "StartServer", szError); 
	} 
 
	if (listen(m_sdListen, nMaxClients) == SOCKET_ERROR) 
	{ 
		sprintf(szError, "%s; listen() failed, error: %d", GetServerName(), WSAGetLastError()); 
		throw DtServerException(dwError, "StartServer", szError); 
	} 
 
	if (BindIoCompletionCallback((HANDLE)m_sdListen, DoneIO, 0) == SOCKET_ERROR) 
	{ 
		sprintf(szError, "%s; BindIoCompletionCallback() failed, error: %d", GetServerName(), WSAGetLastError()); 
		throw DtServerException(dwError, "StartServer", szError); 
	} 
 
 
 
	//Load clients 
	//================================================================== 
	int nId = 0; 
	for (size_t i = 0; i < m_nClients; i++) 
	{ 
 
		nId = (int)i; 
		DtServerSocketClient* pClient = NULL;		// pClient - The client to load 
		LoadClient(&pClient, nId);					// Call a derived function to load the correct client 
		if (pClient) 
		{ 
			pClient->SetIoCompRoutine(DoneIO);		// Map the client to our io routine 
			pClient->SetListenSocket(m_sdListen);	// We gotto have a listen socket 
			pClient->m_pServer = this; 
			pClient->m_nClientId = nId; 
			pClient->InternalInit(); 
			pClient->Init();						// Init the client. 
		} // if (pClient) 
		else 
			throw DtServerException(0, "Load client failed", "Failed to load a client."); 
 
		m_paClients.push_back(pClient); 
	} 
 
	return 0; 
} 
 
void CALLBACK Datatal::DtServerSocket::DoneIO(DWORD dwErrorCode, 
									  DWORD dwByteCount, 
									  LPOVERLAPPED lpOverlapped) 
{ 
	DtServerSocketClient::OVERLAPPED_PLUS *ov; 
	DtServerSocketClient *pClient; 
 
	ov = (DtServerSocketClient::OVERLAPPED_PLUS *)lpOverlapped; 
	if (ov != NULL) 
		pClient = ov->pClient; 
	else 
		return; 
 
	if (dwErrorCode == 0) 
	{ 
		if (dwByteCount != 0) 
		{ 
 
			if (ov->bCtxWrite) 
			{ 
				while (pClient->WriteOperation()); 
			} 
			else 
			{ 
 
				if (pClient->GetState() == DtServerSocketClient::SSF_ACCEPTING) 
				{ 
					try 
					{ 
						pClient->HandleConnect(); 
					} 
					catch (DtException& ex) 
					{ 
						pClient->m_pServer->WriteLog(LP_HIGH, pClient->GetClientId(), "connect", ex.ToString()); 
						pClient->Disconnect(true); 
						pClient->InternalInit(); 
						pClient->Init(); 
					} 
				} 
 
				while (pClient->ReadOperation(dwByteCount)); 
			} 
		} 
		else 
		{ 
			// Client has disconnected. 
			pClient->Disconnect(true); 
			pClient->InternalInit(); 
			pClient->Init(); 
		} 
	} 
	else 
	{ 
		char szLog[512]; 
		sprintf(szLog, "DoneIO, errorcode: %d, bytes: %d", dwErrorCode, dwByteCount); 
		pClient->m_pServer->WriteLog(LP_NORMAL, pClient->GetClientId(), "misc", szLog); 
		pClient->Disconnect(true); 
		pClient->InternalInit(); 
		pClient->Init(); 
	} 
} 
 
 
void Datatal::DtServerSocket::Maintenance() 
{ 
	DtLock aLock(m_cs); 
 
	bool bAllBusy = true; 
	for (size_t i = 0; i < m_paClients.size(); i++)   
	{ 
 
		// Check all accepting clients if someone is connected. 
		// AcceptEx wont return until a client have sent something, without this check clients may occupy the server without doing anything. 
		if (m_paClients[i]->GetState() == DtServerSocketClient::SSF_ACCEPTING) 
		{ 
			int nConnectTime = m_paClients[i]->GetConnectTime(); 
 
			// check if we are connected  
			if (nConnectTime != 0xFFFFFFFF && nConnectTime > 5) 
			{ 
			 
				m_paClients[i]->Disconnect(true); 
				m_paClients[i]->InternalInit(); 
				m_paClients[i]->Init(); 
			 
			} // if (nConnectTime != 0xFFFFFFFF && nConnectTime > 5) 
 
		} // if (m_paClients[i]->GetState() == DtServerSocketClient::SSF_ACCEPTING) 
 
 
		// Check if all clients are busy 
		if (m_paClients[i]->GetState() != DtServerSocketClient::SSF_CONNECTED) 
			bAllBusy = false; 
	 
	} // for (size_t i = 0; i < m_paClients.size(); i++)   
 
 
	// Server got a free socket again after beeing full. 
	if (m_dwServerFull && !bAllBusy) 
	{ 
		char szLog[128]; 
		sprintf(szLog, "System have been full %d seconds.", (GetTickCount()-m_dwServerFull) / 1000 ); 
		WriteLog(LP_HIGH, DTSERVERID, "Maintenance", szLog); 
		m_dwServerFull = 0; 
	} 
 
 
	// Load a new client if allowed 
	if (bAllBusy)  
	{ 
		if (m_nClients < m_nMaxClients) 
		{ 
			WriteLog(LP_NORMAL, DTSERVERID, "Maintenance", "Server full, loading a new client."); 
 
 
			// Let's load another client. 
			DtServerSocketClient* pClient = NULL;		// pClient - The client to load 
			 
			int nId = (int)m_nClients; 
			LoadClient(&pClient, nId);			 
			if (pClient) 
			{ 
				pClient->SetIoCompRoutine(DoneIO); 
				pClient->SetListenSocket(m_sdListen); 
				pClient->m_pServer = this; 
				pClient->m_nClientId = nId; 
				pClient->InternalInit(); 
				pClient->Init();						// Init the client. 
				m_paClients.push_back(pClient); 
				m_nClients++;	 
			} // if (pClient) 
			else 
			{ 
				WriteLog(LP_HIGH, DTSERVERID, "Maintenance", "Failed to load a new client!"); 
			} 
			printf("Size: %d\n", m_paClients.size()); 
 
		} // if (m_nClients < m_nMaxClients) 
		else 
		{ 
			if (!m_dwServerFull) 
			{ 
				m_dwServerFull = GetTickCount(); 
				WriteLog(LP_NORMAL, DTSERVERID, "Maintenance", "Server full but we may not load another client"); 
			} // if (!m_dwServerFull) 
		} 
		 
	} 
} 
 
void Datatal::DtServerSocket::WriteLog(int nPrio, int nClientId, const char* pszCategory, const char* pszString, ...) const 
{ 
	char		szFormattedString[1024]; 
	va_list		argptr; 
 
	//Initialize  
	memset(szFormattedString, 0, sizeof(szFormattedString)); 
	va_start(argptr, pszString); 
	vsprintf(szFormattedString, pszString, argptr); 
	va_end(argptr); 
 
	OnWriteLog(nPrio, nClientId, pszCategory, szFormattedString); 
}