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