从零开始写一个简单好用的游戏服务器引擎[2] - 跨平台相关
来源:互联网 发布:java代码实现充值功能 编辑:程序博客网 时间:2024/06/15 10:20
因为项目需要,所以必须做成跨平台的.一方面是历史原因,一方面是有时确实会碰上只有Windows Server或者只有Linux服务器的情况.不过对于服务端来讲,跨平台还是不算太复杂,主要就是以下几个方面:
1.宏定义和类型别名
尽量都向Windows的命名靠拢了.
所以用的时候也以Windows的为标准.
#if defined(_WIN32) || defined(_WIN64)#define LIB_WINDOWS#else#define LIB_LINUX#endif#ifdef LIB_LINUXtypedef unsigned int UINT;typedef unsigned long long ULONGLONG;typedef long long LONGLONG;typedef long long __int64;typedef int BOOL;#define TRUE 1#define FALSE 0typedef 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); // 这样创建的原因是因为Windwos的CRITICAL_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
常用的就这些了.
0 0
- 从零开始写一个简单好用的游戏服务器引擎[2] - 跨平台相关
- 从零开始写一个简单好用的游戏服务器引擎[0] - 前言
- 从零开始写一个简单好用的游戏服务器引擎[1] - 概要
- 从零开始写一个简单好用的游戏服务器引擎[3] - 网络
- 从零开始写一个简单好用的游戏服务器引擎[4] - 公开啦
- 一个简单的2d游戏引擎
- 用node从零开始去写一个简单的爬虫
- 写一个自己的游戏引擎
- 写一个好的游戏主循环
- 一个简单MIDI音乐游戏 用的是HGE引擎
- 从零开始写一个发送h264的rtsp服务器(上)
- 从零开始写一个发送h264的rtsp服务器(下)
- Cocos2d-Java跨平台游戏引擎和相关开发工具的安装配置
- 一个用wiEngine写的非常简单的游戏
- 【从零开始写一个简单的ImageLoader框架】项目介绍
- 【从零开始写一个简单的ImageLoader框架】ImageLoader分析
- 【从零开始写一个简单的ImageLoader框架】MyImageLoader代码简介
- 用c++写一个简单的打字游戏
- 数据库三范式
- java通过jdbc驱动连接hive操作实例
- 使用QSBR进行安全的内存回收
- Codeforces 724B Batch Sort(暴力枚举)
- 从ActionBar切换到toolBar
- 从零开始写一个简单好用的游戏服务器引擎[2] - 跨平台相关
- mybatis+postgresql insert, update or delete returning *问题
- 电脑的启动过程
- MII、RMII、GMII接口的详细介绍
- Ubuntu14.04 安装CUDA7.5 + Caffe + cuDNN
- static_cast vs dynamic_cast
- Android平台png转jpg的实现
- 图像滤镜处理算法:灰度、黑白、底片、浮雕 (转)
- S2SH开发环境搭建