从零开始写一个简单好用的游戏服务器引擎[2] - 跨平台相关

因为项目需要,所以必须做成跨平台的.一方面是历史原因,一方面是有时确实会碰上只有Windows Server或者只有Linux服务器的情况.不过对于服务端来讲,跨平台还是不算太复杂,主要就是以下几个方面:

1.宏定义和类型别名
尽量都向Windows的命名靠拢了.
所以用的时候也以Windows的为标准.

#if defined(_WIN32) || defined(_WIN64)
#define LIB_WINDOWS
#else
#define LIB_LINUX
#endif

#ifdef LIB_LINUX

typedef unsigned int UINT;

typedef unsigned long long ULONGLONG;

typedef long long LONGLONG;

typedef long long __int64;

typedef int BOOL;

#define TRUE        1
#define FALSE       0

typedef int HANDLE;
#define INVALID_HANDLE_VALUE ((HANDLE)-1)

typedef int INT,*PINT;

typedef int SOCKET;

typedef unsigned int *PUINT;

typedef long LONG_PTR, *PLONG_PTR;

typedef int INT_PTR, *PINT_PTR;

typedef LONG_PTR SSIZE_T, *PSSIZE_T;

typedef unsigned char BYTE;

typedef BYTE *LPBYTE;

typedef char CHAR;

typedef long LONG;

typedef wchar_t WCHAR;

typedef const char* LPCSTR;

typedef char* LPSTR;

typedef const wchar_t* LPCWSTR;

typedef wchar_t* LPWSTR;

typedef unsigned short WORD;

typedef unsigned long DWORD;

typedef DWORD ULONG;

typedef short SHORT;

typedef unsigned short USHORT;

typedef unsigned long long UINT_PTR, *PUINT_PTR;

typedef unsigned long long UINT64;

typedef long long INT64;

typedef double DOUBLE;

typedef void* LPVOID;

typedef time_t __time32_t;
typedef LONGLONG __time64_t;

#ifndef interface
#define interface struct
#endif

另外就是一些常见的常量宏

#define MAX_PATH 260
#define _TRUNCATE ((size_t)-1)
#define MAXCHAR         (0x7f)
#define MAXSHORT        (0x7fff)
#define MAXLONG         (0x7fffffff)
#define MAXLONGLONG     (0x7fffffffffffffff)

#define MAXINT ((INT)(MAXUINT >> 1))
#define MAXUINT ((UINT)~((UINT)0))
#define MAXULONG32 ((ULONG32)~((ULONG32)0))

#define INFINITE        MAXLONG

#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))

#define gmtime_s(_tm,_ts)       gmtime_r(_ts,_tm)

#define _mktime32       mktime

#define ExitProcess     exit

#define ZeroMemory(_Dst,_Size) memset((_Dst),0,(_Size))

#define GetLastError() errno
#define WSAGetLastError() errno

#define strcat_s(_Dst,_DstMax,_Src) strncat(_Dst,_Src,_DstMax)

#define Sleep(t) usleep((t*1000))

#define _ASSERT(_expr) assert(_expr)
#define _ASSERTE(_expr) assert(_expr)

#define SOCKET_ERROR (-1)

#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1

#define closesocket close

恶心的strcpy&printf大家族

#define strcpy_s        strcpy
#define strncpy_s       strncpy

#define wcscpy_s        wcscpy
#define wcsncpy_s       wcsncpy

#define _snprintf_s     snprintf
#define sprintf_s       snprintf
#define _vsnprintf_s    vsnprintf
#define vsnprintf_s     vsnprintf
#define vsprintf_s      vsnprintf

#define _snwprintf_s    swprintf
#define swprintf_s      swprintf
#define _vsnwprintf_s   vswprintf

#define StrCmpIW        wcscasecmp
#define StrCmpIA        strcasecmp

#define StrStrIA        strcasestr

#define printf_s        printf

#endif // LIB_LINUX

基本常用的就这些了.

2.网络库

直接用libevent.本身就跨平台,性能也很好,用起来也很方便.
http://libevent.org/

3.线程&同步锁
线程没什么好说的.

// 线程入口函数
#ifdef LIB_WINDOWS
    static unsigned WINAPI ThreadProc(LPVOID pParam);
#else
    static void* ThreadProc(LPVOID pParam);
#endif // LIB_WINDOWS
// 线程开启
#ifdef LIB_WINDOWS
    UINT nThreadID = 0;
    HANDLE hThread = (HANDLE)_beginthreadex(NULL,
        0,
        ThreadProc,
        (void*)this,
        0,
        &nThreadID);
    if (hThread == INVALID_HANDLE_VALUE)
        return FALSE;
#else
    UINT nThreadID = 0;
    int ret = pthread_create(&nThreadID, NULL, ThreadProc, (void*)this);
    if (ret != 0)
    {
        return FALSE;
    }
#endif // LIB_WINDOWS

关键是同步锁还是有比较多不同.
直接用宏区分出来封装一下写两份好了.

#ifdef LIB_WINDOWS
    class CCriticalSection
    {
    public:
        explicit CCriticalSection(void)
        {
            InitializeCriticalSectionAndSpinCount(&m_cs, 4000);
        }
        ~CCriticalSection(void)
        {
            DeleteCriticalSection(&m_cs);
        }

        void Lock(void)
        {
            EnterCriticalSection(&m_cs);
        }

        void UnLock(void)
        {
            LeaveCriticalSection(&m_cs);
        }

    private:
        CRITICAL_SECTION m_cs;
    };

    class CSemaphore
    {
    public:
        CSemaphore(void) :m_hSemaphore(NULL){}
        virtual ~CSemaphore(void)
        {
            if (m_hSemaphore != NULL)
            {
                CloseHandle(m_hSemaphore);
            }
        }

        BOOL Create(WCHAR *pName, LONG lInitCount, LONG lMaxCount)
        {
            m_hSemaphore = CreateSemaphore(NULL, lInitCount, lMaxCount, pName);
            if (m_hSemaphore == NULL)
            {
                return FALSE;
            }
            return  TRUE;
        }

        BOOL Lock(DWORD  dwTimeOut = INFINITE)
        {
            DWORD dwReturn = WaitForSingleObject(m_hSemaphore, dwTimeOut);
            if (dwReturn == WAIT_OBJECT_0)
            {
                return TRUE;
            }
            return  FALSE;
        }

        BOOL UnLock(LONG lCount)
        {
            return ReleaseSemaphore(m_hSemaphore, lCount, NULL);
        }
    private:
        HANDLE m_hSemaphore;
    };
#else
    class CCriticalSection
    {
    public:
        explicit CCriticalSection(void)
        {
            pthread_mutexattr_init(&m_csAttr);

            pthread_mutexattr_settype(&m_csAttr, PTHREAD_MUTEX_RECURSIVE_NP);
            // 这样创建的原因是因为WindwosCRITICAL_SECTION默认情况下是带有线程递归的.也就是说在同一个线程中允许递归锁.但也要递归解锁到0才能允许其它线程使用.如果不加递归锁属性的话就会在递归加锁时造成死锁!

            pthread_mutex_init(&m_cs, &m_csAttr);
        }
        ~CCriticalSection(void)
        {
            pthread_mutex_destroy(&m_cs);
        }

        void Lock(void)
        {
            pthread_mutex_lock(&m_cs);
        }

        void UnLock(void)
        {
            pthread_mutex_unlock(&m_cs);
        }

    private:
        pthread_mutex_t m_cs;
        pthread_mutexattr_t m_csAttr;
    };

    class CSemaphore
    {
    public:

        CSemaphore(void){}
        virtual ~CSemaphore(void);

        BOOL Lock(DWORD  dwTimeOut = INFINITE)
        {// Linux信号量超时锁和非超时锁使用方法有区别
            if (dwTimeOut == INFINITE)
            {
                if (sem_wait(&m_Sem))
                {
                    return FALSE;
                }
            }
            else
            {
    #define TIME_USEC   (1000000)
                timeval tv;
                timespec ts;

                gettimeofday(&tv,NULL);

                int nSec = (int) (dwTimeOut / 1000);
                int nMilSec = dwTimeOut - (nSec * 1000);

                tv.tv_sec += nSec;
                tv.tv_usec += (nMilSec * 1000);

                if (tv.tv_usec > TIME_USEC)
                {
                    tv.tv_sec += (long)(tv.tv_usec / TIME_USEC);
                    tv.tv_usec %= TIME_USEC;
                }

                ts.tv_sec = tv.tv_sec;
                ts.tv_nsec = (tv.tv_usec * 1000);

                if (sem_timedwait(&m_Sem, &ts))
                {
                    return FALSE;
                }
            }

            return TRUE;
        }

        BOOL UnLock(LONG lCount)
        {
            if (sem_post(&m_Sem))
            {
                // Unlock Sem Failed
                return FALSE;
            }
            return TRUE;
        }

        BOOL Create(WCHAR *pName, LONG lInitCount, LONG lMaxCount)
        {
            int nRet = sem_init(&m_Sem, 0, 0);
            if (nRet)
            {
                // Create Sem Failed
                return FALSE;
            }

            UnLock(lInitCount);

            return TRUE;
        }
    private:
        sem_t m_Sem;
    };
#endif // LIB_WINDOWS

常用的就这些了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值