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