C++ 技术知识点 (1)

内存对齐

#pragma pack(push,1)

VC中提供了#pragma pack(n)来设定变量以n字节对齐方式。如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。


字符数组清0

char name[12] = {0}; 
或 
memset(name, 0, 12);

若不清零,字符数组内为随机值,可能导致字符串编码问题,一定要先清零


标准字符数组使用方法

#define CHAR_LEN 12
char name[CHAR_LEN + 1];
memset(name, 0x00, sizeof(name));
strncmp(name, "xxxx", CHAR_LEN) == 0

strncpy(name, "xxxx", CHAR_LEN);
name[CHAR_LEN] = 0;

字符串比较(不区分大小写)

stricmp


屏蔽编译警告

#   pragma warning(disable:4267)
// 'var' : conversion from 'size_t' to 'type', possible loss of data

时间枚举

enum TimeConstants
{
    MINUTE = 60,
    HOUR   = MINUTE*60,
    DAY    = HOUR*24,
    MONTH  = DAY*30,
    YEAR   = MONTH*12,
    IN_MILISECONDS = 1000
};

OS定义

#define PLATFORM_WINDOWS 0
#define PLATFORM_UNIX    1
#define PLATFORM_APPLE   2
#define PLATFORM_INTEL   3

编译器定义

#define COMPILER_MICROSOFT 0
#define COMPILER_GNU       1
#define COMPILER_BORLAND   2
#define COMPILER_INTEL     3

LockedQueue 加锁队列

template <class T, class LockType, typename StorageType=std::deque<T> >
class LockedQueue
{
LockType _lock;
StorageType _queue;
volatile bool _canceled;

LockedQueue(): _canceled(false){ }
virtual ~LockedQueue(){ }
void add(const T& item)
bool next(T& result)
T& peek()
void cancel()
bool cancelled()
void lock()
void unlock()
};

通过在函数起始和结尾处添加lock();unlock(); 实现加锁和解锁,或者使用自动锁定模版 ACE_Guard<LockType> g(this->_lock);


创建对象模版类

template <class T>
    class TRINITY_DLL_DECL OperatorNew
{
    public:
        static T* Create(void) { return (new T); }
        static void Destroy(T *obj) { delete obj; }
};


单例模式Singleton

template
    <
    typename T,
    class ThreadingModel = Trinity::SingleThreaded<T>,
    class CreatePolicy = Trinity::OperatorNew<T>,
    class LifeTimePolicy = Trinity::ObjectLifeTime<T>
    >
    class TRINITY_DLL_DECL Singleton
{
    public:
        static T& Instance();

    protected:
        Singleton() {};

    private:

        // Prohibited actions...this does not prevent hijacking.
        Singleton(const Singleton &);
        Singleton& operator=(const Singleton &);

        // Singleton Helpers
        static void DestroySingleton();

        // data structure
        typedef typename ThreadingModel::Lock Guard;
        static T *si_instance;
        static bool si_destroyed;
};

ThreadingModel负责加锁,CreatePolicy负责创建和释放对象,LifeTimePolicy负责生命周期。隐藏复制构造和拷贝构造函数


socket预定义

#ifdef _MSC_VER
#pragma comment(lib, "wsock32.lib")
#endif

typedef unsigned long ipaddr_t;
typedef unsigned short port_t;
typedef int socklen_t;

// 1.8.6: define FD_SETSIZE to something bigger than 64 if there are a lot of
// simultaneous connections (must be done before including winsock.h)
#define FD_SETSIZE 1024

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>

class WSAInitializer // Winsock Initializer
{
public:
    WSAInitializer() {
        if (WSAStartup(0x101,&m_wsadata))
        {
            exit(-1);
        }
    }
    ~WSAInitializer() {
        WSACleanup();
    }
private:
    WSADATA m_wsadata;
};

typedef std::list<SOCKET> socket_v;

字符串分割

Tokens StrSplit(const std::string &src, const std::string &sep)
{
    Tokens r;
    std::string s;
    for (std::string::const_iterator i = src.begin(); i != src.end(); i++)
    {
        if (sep.find(*i) != std::string::npos)
        {
            if (s.length()) r.push_back(s);
            s = "";
        }
        else
        {
            s += *i;
        }
    }
    if (s.length()) r.push_back(s);
    return r;
}

typedef std::vector<std::string> Tokens;

src为拼接字符串,sep为分割标识符,可以有多个分割标志,结果存入Tokens


字符串是否ip地址

bool IsIPAddress(char const* ipaddress)
{
    if(!ipaddress)
        return false;

    // all valid ip address formats are recognized e.g.: 12.23,121234,0xABCD)
    return inet_addr(ipaddress) != INADDR_NONE;
}

字符串对称交换

template<size_t T>
    inline void convert(char *val)
{
    std::swap(*val, *(val + T - 1));
    convert<T - 2>(val + 1);
}

传入如”abcde”,处理后得到”edcba”Tchar*的长度,swap交换两个参数的值,convert递归调用


vector的reserve和resize

reserve增加了vector的capacity,但没有改变size;resize改变了vector的capacity和size。 reserve是容器预留空间,不真正创建元素,在添加对象之前,不能引用容器内元素(相当于一块未开发的土地),加入元素时要调用push_bak或insert函数。


clock 进程运行时间

clock_t __cdecl clock(void);
//返回进程已运行的cpu计时单元数,转换为秒数:
#define CLOCKS_PER_SEC  1000
clock()/CLOCKS_PER_SEC

signal 设置信号动作

void (* signal(int _SigNum, void (* _Func)(int)))(int);
void OnSignal(int s)

void HookSignals()
{
    signal(SIGINT, OnSignal);
    signal(SIGTERM, OnSignal);
}

void UnhookSignals()
{
    signal(SIGINT, 0);
    signal(SIGTERM, 0);
}

HookSignals绑定信号,UnhookSignals取消绑定


设置处理器数目

uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
if (Aff > 0)
{
	ULONG_PTR appAff;
	ULONG_PTR sysAff;

	if (GetProcessAffinityMask(hProcess,&appAff,&sysAff))
	{
		ULONG_PTR curAff = Aff & appAff; 
// remove non accessible processors
		if (curAff)
			SetProcessAffinityMask(hProcess,curAff);
	}
}

select函数

select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读。

select(int nfds, fd_set * readfds,fd_set * writefds,fd_set *exceptfds,const struct timeval* timeout);

ndfs:监视的文件句柄数,一般设为监视的最大文件号加一。

readfds:监视的可读文件句柄集合。

writefds:select监视的可写文件句柄集合。

exceptfdsselect监视的异常文件句柄集合。

timeout:本次select()的超时结束时间。

 

readfdswritefds中映象的文件可读或可写或超时,本次select()就结束返回。程序员利用一组系统提供的宏在select()结束时便可判断哪一文件可读或可写。

struct timeval* timeoutselect的超时时间,有两个成员,一个是秒数,另一个是毫秒数。它可以使select处于三种状态:

1)若将NULL以形参传入,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;

2)若将时间值设为00毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;

3timeout的值大于0,这就是等待的超时时间,即selecttimeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。

 

FD_ZERO(fd_setfdset) 清空fdset与所有文件句柄的联系。

FD_SET(int fd,fd_set *fdset)建立文件句柄fdfdset的联系。

FD_CLR(int fd,fd_set *fdset)清除文件句柄fdfdset的联系。

FD_ISSET(int fd, fdset *fdset)检查fdset联系的文件句柄fd是否可读写,当>0表示可读写


socket消息处理

SocketHandler h;
ListenSocket<AuthSocket> authListenSocket(h);
authListenSocket.Bind(bind_ip.c_str(),rmport);

h.Add(&authListenSocket);

while (!stopEvent)
{
	h.Select(0, 100000);
}


SocketHandler类

class SocketHandler : public ISocketHandler

(1)记录日志
SocketHandler(StdLog *log = NULL);		// log对象指针SocketHandler::SocketHandler(StdLog *p):m_stdlog(p)

void SocketHandler::LogError(Socket *p,const std::string& user_text,int err,const std::string& sys_err,loglevel_t t)
{
    if (m_stdlog)
        m_stdlog -> error(this, p, user_text, err, sys_err, t);
}

(2)socket map,存放socket句柄和对象指针
typedef std::map<SOCKET,Socket *> socket_m;

(3)线程加锁
SocketHandler(Mutex& mutex,StdLog *log = NULL);
SocketHandler::SocketHandler(Mutex& mutex,StdLog *p)
:m_stdlog(p)
,m_mutex(mutex)
{
    m_mutex.Lock();
    FD_ZERO(&m_rfds);
    FD_ZERO(&m_wfds);
    FD_ZERO(&m_efds);
}

SocketHandler::~SocketHandler()
{
    if (m_b_use_mutex)
    	m_mutex.Unlock();
}

if (m_b_use_mutex)
{
	m_mutex.Unlock();
	n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,tsel);
	m_mutex.Lock();
}

构造函数里加锁,析构里解锁,每次执行函数时先解锁再加锁

(4)设置socket读写状态
void SocketHandler::Get(SOCKET s,bool& r,bool& w,bool& e)
{
    if (s >= 0)
    {
        r = FD_ISSET(s, &m_rfds) ? true : false;
        w = FD_ISSET(s, &m_wfds) ? true : false;
        e = FD_ISSET(s, &m_efds) ? true : false;
    }
}

void SocketHandler::Set(SOCKET s,bool bRead,bool bWrite,bool bException)
{
	if (bRead)
	{
		if (!FD_ISSET(s, &m_rfds))	FD_SET(s, &m_rfds);
	}
	else
		FD_CLR(s, &m_rfds);

	if (bWrite)
	{
		if (!FD_ISSET(s, &m_wfds))	FD_SET(s, &m_wfds);
	}
	else
		FD_CLR(s, &m_wfds);

	if (bException)
	{
		if (!FD_ISSET(s, &m_efds))	FD_SET(s, &m_efds);
	}
	else
		FD_CLR(s, &m_efds);
}

(5)select函数
/** Wait for events, generate callbacks. */
int Select(long sec,long usec);
/** This method will not return until an event has been detected. */
int Select();
int Select(struct timeval *tsel);

int SocketHandler::Select(long sec,long usec)
{
    struct timeval tv;
    tv.tv_sec = sec;
    tv.tv_usec = usec;
    return Select(&tv);
}

int SocketHandler::Select(struct timeval *tsel)
{
fd_set rfds = m_rfds;
fd_set wfds = m_wfds;
fd_set efds = m_efds;

int n;
n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,tsel);

for (socket_v::iterator it2 = m_fds.begin(); it2 != m_fds.end() && n; it2++)
{
	SOCKET i = *it2;
	if (FD_ISSET(i, &rfds))
	{
		socket_m::iterator itmp = m_sockets.find(i);
		if (itmp != m_sockets.end())
		{
			Socket *p = itmp -> second;
			p -> OnRead();
		}
		n--;
	}
	if (FD_ISSET(i, &wfds))
	{
		socket_m::iterator itmp = m_sockets.find(i);
		if (itmp != m_sockets.end())
		{
			Socket *p = itmp -> second;
			p -> OnWrite();
		}
		n--;
	}
	if (FD_ISSET(i, &efds))
	{
		socket_m::iterator itmp = m_sockets.find(i);
		if (itmp != m_sockets.end())
		{
			Socket *p = itmp -> second;
			p -> OnException();
		}
		n--;
	}
}
}

AuthSocket类

class AuthSocket: public TcpSocket
继承顺序为
AuthSocket – TcpSocket – StreamSocket – Socket

(1)构造
AuthSocket::AuthSocket(ISocketHandler &h) : TcpSocket(h)

(2)读取
CircularBuffer ibuf;

void AuthSocket::OnRead()
{
TcpSocket::OnRead();
while (1)
{
	if (!ibuf.GetLength())
		return;

	uint8 _cmd;
	ibuf.SoftRead((char *)&_cmd, 1);

	size_t i;
	for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i)
	{
		if ((uint8)table[i].cmd == _cmd &&
			(table[i].status == STATUS_CONNECTED ||
			(_authed && table[i].status == STATUS_AUTHED)))
		{
			(*this.*table[i].handler)();
			break;
		}
	}
}
}

(3)消息绑定函数
typedef struct AuthHandler
{
    eAuthCmd cmd;
    uint32 status;
    bool (AuthSocket::*handler)(void);
}AuthHandler;

const AuthHandler table[] =
{
	{ 
		AUTH_LOGON_CHALLENGE,     
		STATUS_CONNECTED, 
		&AuthSocket::_HandleLogonChallenge    
	},

	{ 
		AUTH_LOGON_PROOF,         
		STATUS_CONNECTED, 
		&AuthSocket::_HandleLogonProof
	}
	// ...
};

(4)消息包
#pragma pack(push,1)

typedef struct AUTH_LOGON_PROOF_S
{
    uint8   cmd;
    uint8   error;
    uint8   M2[20];
    uint32  unk1;
    uint32  unk2;
    uint16  unk3;
} sAuthLogonProof_S;

#pragma pack(pop)


环形缓冲区CircularBuffer

char *buf;				// 缓冲区数组
size_t m_max;			// 最大长度
size_t m_q;				// 读写起始位置间长度
size_t m_b;				// 读取起始位置
size_t m_t;				// 写入起始位置
unsigned long m_count;	// 实际存储大小

m_b = 3

读位置

m_q = 3 读写间长度

写位置

 

 

 

 

 

->

 

 

 

->

 

 

m_count = 7

m_t

 

 

m_max = 10

(1)构造析构
CircularBuffer::CircularBuffer(size_t size)
: buf(new char[2 * size]), m_max(size), m_q(0)
, m_b(0), m_t(0), m_count(0)
{}

CircularBuffer::~CircularBuffer()
{
	delete[] buf;
}

此处设置buf大小为2 * size,不理解,估计只使用size个大小,另一半闲置

(2)写数据
bool CircularBuffer::Write(const char *s,size_t wLen)
{
	// 已存长度+ 新增长度> 最大长度,溢出
	if (m_RWLen + wLen > m_max)
		return false;

	m_count += (unsigned long)wLen;	// 实际长度增加

	// 写位置+ 新增> 最大,跳回头部
	if (m_W + wLen > m_max)
	{
		// 写位置到尾部的可写长度,先拷贝一部分
		size_t w_End = m_max - m_W;
		memcpy(buf + m_W, s, wLen);

		// 头部开始,再拷贝剩余长度
		memcpy(buf, s + w_End, wLen - w_End);

		m_W = wLen - w_End;		// 写位置
		m_RWLen += wLen;		// 读写间长度
	}
	else	// 到尾部足够
	{
		memcpy(buf + m_W, s, wLen);	// 直接拷贝
		memcpy(buf + m_max + m_W, s, wLen); // 不理解??
		m_W += wLen;			// 写位置
		if (m_W >= m_max)
			m_W -= m_max;
		m_RWLen += wLen;
	}
	return true;
}

写数据后,读取间长度增加,写位置改变,实际长度改变。 其中 m_q 对应 m_RWLen,m_t 对应m_W, m_b 对应 m_R

(3)读数据
bool CircularBuffer::Read(char *s,size_t rLen)
{
	if (rLen > m_RWLen)	// 没有足够的数据可读
		return false;

	// 读位置+ 读长度> 最大长度
	if (m_R + rLen > m_max)
	{
		// 到尾部可读长度
		size_t r_End = m_max - m_R;
		if (s)
		{
			// 先读到尾部的一部分,再读首部的一部分
			memcpy(s, buf + m_R, r_End);
			memcpy(s + r_End, buf, rLen - r_End);
		}
		m_R = rLen - r_End;	// 读位置
		m_RWLen -= rLen;	// 读写间隔
	}
	else	// 不超出尾部,直接读
	{
		if (s)
			memcpy(s, buf + m_R, rLen);

		m_R += rLen;		// 读位置后移
		if (m_R >= m_max)
			m_R -= m_max;
		m_RWLen -= rLen;
	}

	if (!m_RWLen)	// 读写间长度为
		m_R = m_W = 0;

	return true;
}

读数据后,读位置改变,读写间长度改变

bool CircularBuffer::SoftRead(char *s, size_t l)
该函数类似Read,但不改变读位置

(4)删除
bool CircularBuffer::Remove(size_t l)
{
	return Read(NULL, l);
}

相当于只改变读位置和长度,没有数据拷贝

(5)获取各种长度
获取读写间长度
size_t TcpSocket::CircularBuffer::GetLength()
{
    return m_q;
}

获取读指针
const char *TcpSocket::CircularBuffer::GetStart()
{
    return buf + m_b;
}

获取读位置到尾部的长度
size_t TcpSocket::CircularBuffer::GetL()
{
    return (m_b + m_q > m_max) ? m_max - m_b : m_q;
}

获取空闲长度
size_t TcpSocket::CircularBuffer::Space()
{
    return m_max - m_q;
}

获取实际存储长度
unsigned long TcpSocket::CircularBuffer::ByteCounter(bool clear)
{
    if (clear)
    {
        unsigned long x = m_count;
        m_count = 0;
        return x;
    }
    return m_count;
}















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值