www.pudn.com > ChatUseIOCP.rar > DtServerSocketClient.h
#pragma once
#include "DtServerSocket.h"
/*
/// You may redefine the size if you want to.
#ifndef SERVER_IN_BUFFER_SIZE
#define SERVER_IN_BUFFER_SIZE 4096
#endif
/// You may redefine the size if you want to.
#ifndef SERVER_OUT_BUFFER_SIZE
#define SERVER_OUT_BUFFER_SIZE 4096
#else
#endif
*/
/// You may redefine the size if you want to.
#ifndef SERVER_WORK_BUFFER_SIZE
#define SERVER_WORK_BUFFER_SIZE 1024
#endif
/// uncomment this define to use WSARecv
//#define SERVER_USE_WSARECV
namespace Datatal
{
//////////////////////////////////////////////////////////////////////////
///
///
/// @class DtServerSocketClient
/// @version 1.0
/// @author Jonas Gauffin
/// @homepage http://www.gauffin.org/cpp
///
/// @brief Baseclass for the server clients - Part of the IOCP Server framework.
///
/// @since 2003-05-10 jg File created
/// @since 2003-08-01 jg Major rebuild of the class.
/// @since 2003-08-09 jg Using ReadFile instead of WSARecv, class works much better.
/// @since 2003-08-18 jg Outbuffer are a linked list instead, less buffer copying.
///
//////////////////////////////////////////////////////////////////////////
class DtServerSocketClient
{
friend class DtServerSocket;
public:
enum SERVER_STATE_FLAGS
{
SSF_DEAD,
SSF_SHUTTING_DOWN,
SSF_ACCEPTING,
SSF_CONNECTED,
};
/// bCtxWrite is true for all write operations.
struct OVERLAPPED_PLUS : public WSAOVERLAPPED
{
DtServerSocketClient* pClient; //Pointer to client
bool bCtxWrite;
OVERLAPPED_PLUS()
{
pClient = NULL;
bCtxWrite = false;
}
};
/// Container for our outbuffers.
struct Outbuffer
{
char* pBuffer;
DWORD dwSize;
Outbuffer* pNext;
};
/// Linked list with all our outbuffers.
struct OutbufferList
{
Outbuffer* pFirst;
Outbuffer* pLast;
OutbufferList()
{
pFirst = NULL;
pLast = NULL;
}
void Append(char* pBuffer, DWORD dwSize)
{
if (!pBuffer || !dwSize) throw std::invalid_argument("pBuffer and nSize cannot be NULL");
Outbuffer* pNewNode = new Outbuffer;
pNewNode->pBuffer = pBuffer;
pNewNode->pNext = NULL;
pNewNode->dwSize = dwSize;
if (pLast)
pLast->pNext = pNewNode;
else
pFirst = pNewNode;
pLast = pNewNode;
}
void RemoveFirst()
{
if (!pFirst) throw std::out_of_range("pFirst is NULL");
Outbuffer* pOld = pFirst;
pFirst = pFirst->pNext;
if (pOld == pLast) pLast = NULL;
delete[] pOld->pBuffer;
delete pOld;
}
};
protected:
int m_nClientId; /// Id of this client
SERVER_STATE_FLAGS m_nState; /// State of this socket
SOCKET m_sdClient; /// Our client socket
SOCKET m_sdListen; /// The listensocket.
OVERLAPPED_PLUS m_ovRead; /// Used to identify read operations
OVERLAPPED_PLUS m_ovWrite; /// used to identify write operations.
sockaddr_in m_LocalAddr; /// Local address
sockaddr_in m_RemoteAddr; /// Remote address
DtServerSocket* m_pServer; /// Pointer to the server that this client belongs to.
LPOVERLAPPED_COMPLETION_ROUTINE m_pfnDoneIORoutine; /// Pointer to the completion function.
// io operations
bool m_bPendingWrite; /// a read is pending
bool m_bPendingRead; /// a write is pending
WSABUF m_wsaInBuf; /// Temporary buffer used for reading
WSABUF m_wsaOutBuf; /// Temporary buffer used for writing
OutbufferList m_lOutBuffers; /// Vector with all outbuffers.
int m_nBufferPos; /// Where in the buffer we are.
DtCriticalSection m_CritRead; /// lock our inbuffer
DtCriticalSection m_CritWrite; /// lock our outbuffer
DtCriticalSection m_cs; /// General critical section
/// Handle connect. Can throw DtException
void HandleConnect();
/// Overlapped write operation.
/// @returns true until a overlapped write or no more data.
bool WriteOperation();
/// Overlapped Read
/// @param dwReadBytes Number of bytes that we have recieived.
/// @returns returns true until there arent any more data to parse.
bool ReadOperation(DWORD dwReadbytes);
/// Initialize the client (make it listen)
void InternalInit();
/// Write a string to the logfile
virtual void OnWriteLog(int nPrio, int nClientId, const char* pszCategory, const char* pszString) const;
void WriteLog(int nPrio, int nClientId, const char* pszCategory, const char* pszString, ...) const;
public:
DtServerSocketClient(void);
~DtServerSocketClient(void);
// Init routines.
// =======================================
/// Set's what listensocket we should use
void SetListenSocket(SOCKET sdListen);
/// Set the completionport routine.
void SetIoCompRoutine(LPOVERLAPPED_COMPLETION_ROUTINE IoFunc);
/// Can be overriden to set additional parameters in the init.
virtual void Init()
{
WriteLog(Datatal::LP_NORMAL, GetClientId(), "Init", "virtual void Init() not implemented.");
};
/// Disconnect a client, you should run Init() afterwards if you want to get new clients...
/// @see Init()
void Disconnect(bool bForce = false);
// Handling functions
// ===========================================
/// Send something to the client.
/// @param data Data to send, buffer will be managed by this class.
/// @param nSize size of data.
/// @returns false if buffer overflow.
bool Send(char* data, int nSize);
// Events
// =========================================
/// We got some new data in our buffer
/// @returns Should return number of bytes that have been processed.
virtual void OnReceive(const char* pInBuffer, size_t nBufferSize) = 0;
/// We've been disconnected for some reason.
virtual void OnDisconnect() {};
/// raised when something goes wrong. Typically you would Disconnect() and Init()
/// @param dwErrorCode A systemerrorcode, or one of the ones defined in ChatErrors.h
virtual void OnError(DWORD dwErrorCode);
/// Raised when a client connect, you can use it to display a welcome message.
virtual void OnConnect() {};
// Properties
// ==============================
/// @returns the client id.
int GetClientId() const { return m_nClientId; };
/// @returns State of the server.
SERVER_STATE_FLAGS GetState() const { return m_nState; };
bool IsConnected() const { return m_nState == SSF_CONNECTED; };
/// @returns number of seconds that the client have been connected
int GetConnectTime() const;
}; //class
}; //datatal