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);
}