因为项目需要,所以必须做成跨平台的.一方面是历史原因,一方面是有时确实会碰上只有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);
// 这样创建的原因是因为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
常用的就这些了.