www.pudn.com > ChatUseIOCP.rar > DtSocketBase.h


#pragma once 
 
/// Include our thread sync library if it's not already included. 
#ifndef EXAMPLE 
#include  
#include  
#include  
#include  
#else 
#include "../DtLibrary/DtLocker.h" 
#include "../DtLibrary/DtException.h" 
#include "../DtLibrary/dtthread.h" 
#include "../DtLibrary/dtincludes.h" 
#endif 
#include  
 
#ifndef DTSOCKETBASE 
#define DTSOCKETBASE 
 
namespace Datatal 
{ 
 
 
/// you may define this buffer yourself. 
#ifndef _SOCKETLIB_WORK_SIZE_ 
#define _SOCKETLIB_WORK_SIZE_		1024	// Number of bytes we can read in each operation 
#endif 
 
////////////////////////////////////////////////////////////////////////// 
/// 
///		 
///  @class			DtSocketBase - base class for client communication 
///  @version		1.0 
///	 @author		Jonas Gauffin 
///  @homepage		http://www.gauffin.org/cpp 
///	 
///  @brief			Baseclass for client communcication, only intended to  
///					be used as a base class for communication. 
///  
///  @since 2003-02-28	jg	File created 
///  @since 2003-06-10	jg	Users may define the buffer size. 
///  @since 2003-06-10	jg	Both classes use the same buffers. 
///	 @since 2003-08-07	jg	Now derived from DtThread 
///  @since 2003-08-18	jg	Outbuffers are now queued instead of being copied to a large buffer. 
///  @since 2003-08-18	jg	Incomming data must be handled by derived class. 
///	 @since 2003-08-18	jg	HandleRecieve/Send uses size_t for the buffersize. 
///  @since 2003-08-18	jg	Send functions is in the baseclass. 
///  @since 2003-08-18	jg	General variables(critical sections, newdata event, outbuffers) is moved to the baseclass 
/// 
////////////////////////////////////////////////////////////////////////// 
class DtSocketBase : protected DtThread 
{ 
public: 
 
	enum DT_SOCKET_STATE 
	{ 
		DTSS_DISCONNECTED, 
		DTSS_CONNECTING, 
		DTSS_CONNECTED, 
		DTSS_ERROR 
	}; 
 
	DT_SOCKET_STATE GetState() const { return m_dtssState; }; 
 
	/// If nothing else is said, trigger the events. Else just call the functions. 
	DtSocketBase(void); 
	~DtSocketBase(void); 
 
	/// Toggle reconnect, well connect automaticly if disconnected. 
	/// @param bReconnect True if we should reconnect 
	void SetReconnect(bool bReconnect) { m_bReconnect = bReconnect; }; 
	bool GetReconnect() { return m_bReconnect; }; 
 
	/// Function to connect. 
	virtual void Connect() = 0; 
 
	/// Disconnectes the current device. 
	virtual bool Disconnect(bool bStopThread = false); 
 
	/// Function to connect. 
	/// @param data The data to send, buffer will be handled by this class. 
	/// @param nBufSize the buffer size. 
	/// @returns true if the send succeed 
	bool Send(char* data, size_t nBufSize); 
 
	/// Returns the type of communicationclass that currently are used. 
	/// @returns The type of the current communictation. TCPIP or SERIAL 
	virtual const char* GetTypeName() = 0; 
 
	/// Are we connected or not? 
	bool IsConnected() const { return m_dtssState == DTSS_CONNECTED; }; 
 
	/// Request to write to a logfile. Triggers the OnLogWrite event. 
	/// Importance flag can be used to filter the messages. 
	/// @param nImportance 0 = lowlevel, 1 = good debugging entries, 2 = ALL entrys. 
	/// @param pszGroup Groups.. in/out/misc 
	/// @param nBufferSize Size of the buffer that will be allocated by WriteLog, default 1024 
	virtual void WriteLog(int nImportance, const char* pszGroup, LPCTSTR lpszFormat, ...); 
 
	/// Handle incomming data. 
	/// If you dont want to use events, just override this function. 
	/// @param InBuffer Number of bytes Received. 
	/// @param nBufSize Number of bytes in the buffer. 
	virtual void HandleReceive(const char* pInBuffer, size_t nBufSize)  
	{ return __raise OnReceive(pInBuffer, nBufSize);	}; 
 
	/// A send have been completed. 
	/// If you dont want to use events, just override this function. 
	virtual void HandleSendComplete() { __raise OnSendComplete(); }; 
 
	/// The "other" side have disconnected. 
	/// If you dont want to use events, just override this function. 
	virtual void HandleDisconnect() { __raise OnDisconnect(); }; 
 
 
	/// Yes! We have been connected. 
	/// If you dont want to use events, just override this function. 
	virtual void HandleConnect()  
	{ __raise OnConnect(); }; 
	 
	/// Event triggered when one of the classes want to write a logentry. 
	/// Importance flag can be used to filter the messages. 
	/// If you dont want to use events, just override this function. 
	/// @param LogEntry the entry that we want to write 
	/// @param nImportance 0 = lowlevel, 1 = good debugging entries, 2 = ALL entrys. 
	virtual void HandleWriteLog(int nImportance, const char* pszGroup, const char* pszLogEntry)  
	{ __raise OnWriteLog(nImportance, pszGroup, pszLogEntry); }; 
 
	/// WSA Errors for tcp/ip. 
	virtual void HandleError(int nErrorCode, const char* pszDescription)  
	{ __raise OnError(nErrorCode, pszDescription); }; 
 
	/// OnReceive Event, triggered when new data arrives, data must be handled! 
	/// @param InBuffer Number of bytes Received. 
	/// @param nBufSize Number of bytes in the buffer. 
	///	@returns Number of bytes proccessed. IMPORTANT! 
	__event void OnReceive(const char* pInBuffer, size_t nBufSize); 
 
	/// Event triggered when a send have been completed. 
	__event void OnSendComplete(); 
 
	/// Event triggered when something, except us, closes the connection (error etc.) 
	__event void OnDisconnect(); 
 
	/// Event triggered when we got a connect. 
	__event void OnConnect(); 
 
	__event void OnError(int nErrorCode, const char* szErrorDescription); 
 
	/// Event triggered when one of the classes want to write a logentry. 
	/// Importance flag can be used to filter the messages. 
	/// @param LogEntry the entry that we want to write 
	/// @param nImportance 0 = lowlevel, 1 = good debugging entries, 2 = ALL entrys. 
	__event void OnWriteLog(int nImportance, const char* pszGroup, const char* LogEntry); 
 
protected: 
 
	/// Set the communication state. 
	void SetState(DT_SOCKET_STATE dtssState) { m_dtssState = dtssState;  }; 
 
 
	/// Container for our outbuffers. 
	struct Outbuffer 
	{ 
		char* pBuffer; 
		size_t nSize; 
		Outbuffer* pNext; 
	}; 
	/// Linked list (first in, first out) with all our outbuffers. 
	struct OutbufferList 
	{ 
		Outbuffer* pFirst; 
		Outbuffer* pLast; 
		OutbufferList() 
		{ 
			pFirst = NULL; 
			pLast = NULL; 
		} 
		/// Append a buffer at the end. 
		void Append(char* pBuffer, size_t nSize) 
		{ 
			if (!pBuffer || !nSize) throw std::invalid_argument("pBuffer and nSize cannot be NULL"); 
 
			Outbuffer* pNewNode = new Outbuffer; 
			pNewNode->pBuffer = pBuffer; 
			pNewNode->pNext = NULL; 
			pNewNode->nSize = nSize; 
 
			if (pLast) 
				pLast->pNext = pNewNode; 
			else 
				pFirst = pNewNode; 
 
			pLast = pNewNode; 
		} 
		/// Remove the first buffer and set that the second one is the first. 
		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; 
		} 
	}; 
 
 
	bool				m_bReconnect; 
	DT_SOCKET_STATE		m_dtssState; 
	OutbufferList		m_lOutBuffers;			/// Linked list with all outbuffers. 
	int					m_nBufferPos;			/// Where in the buffer we are. 
 
	DtCriticalSection	m_CritRead;				/// ThreadSync for inbuffer 
	DtCriticalSection	m_CritWrite;			/// ThreadSync for outbuffer 
 
	HANDLE				m_hNewDataEvent;	/// Signal that new data have been added  
 
 
 
}; 
 
class DtSocketException : public DtException 
{ 
public: 
	/// A constructor for our exceptionclass 
	/// @param nErrorNumber The error that were raised. Should be GetLastError or -1 for custom error. 
	/// @param Name Name of the current error 
	/// @param Description A more detailed information about the raised error. 
	DtSocketException(int nErrorNumber, const char* pszName, const char* pszFormattedString) 
	{ 
		m_nLine = 0; 
		m_szFileName[0] = NULL; 
 
		SetErrorNumber(nErrorNumber); 
		SetName(pszName); 
		SetDescription(pszFormattedString); 
	}; 
}; //DtSocketException 
 
}; //Namespace 
 
#endif