/*自定义标准头文件*/

#ifndef _BE43_6E9002874EFE_SESTD_H
#define	_BE43_6E9002874EFE_SESTD_H

#ifdef SEAPI_EXPORTS
#       define SEAPI_API __declspec(dllexport)
#else
#       define SEAPI_API
#endif

#include <string.h>
#include <string>
#include <boost/exception/all.hpp>

typedef std::string STRING;
typedef std::wstring WSTRING;
typedef std::stringstream STRSTREAM;
typedef std::wstringstream WSTRSTREAM;

#if defined(SE_UNICODE)
typedef WSTRING TSTRING;
typedef WSTRSTREAM TSTRSTREAM;
#else
typedef STRING TSTRING;
typedef STRSTREAM TSTRSTREAM;
#endif

#if defined(_MSC_VER )
#	include <tchar.h>
#else
#	if defined(SE_UNICODE)
typedef wchar_t TCHAR;
#		define _T(x)	L ## x
#		define _tcslen       wcslen
#		define _tcsncpy	wcsncpy
#	else
typedef char TCHAR;
#		define _T(x)	x
#		define _tcslen      strlen
#		define _tcsncpy	strncpy
#	endif
#endif

//自定义异常类
struct se_exception
	:virtual std::exception
	,virtual boost::exception  
{};
//自定义异常消息
typedef boost::error_info<struct _tag_error_messsage_,TSTRING> se_error_message;
//抛出异常(异常消息、文件名、行号、抛出异常的函数)
#define SE_THROW(msg) throw se_exception()<<se_error_message(msg)\
	<<boost::throw_file(__FILE__)\
	<<boost::throw_line(__LINE__)\
	<<boost::throw_function(BOOST_CURRENT_FUNCTION)
//函数说明(该函数可能会抛出的异常)
#ifdef SE_STD_DECL_THROW
#	define SE_THROW_DESC(x) throw(x)
#else
#	define SE_THROW_DESC(x)
#endif

#endif	/*_BE43_6E9002874EFE_SESTD_H */

#ifndef _BE43_6E9002874EFE_SESSION_H
#define	_BE43_6E9002874EFE_SESSION_H

#include <map>
#include  <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include  <boost/thread.hpp>
#include  <boost/bind.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include "sestd.h"

/*状态*/
typedef enum {
	sesession_idle, /*空闲*/
	sesession_use /*使用中*/
} sesession_status;

template <typename T>
class sesessions;

/*模板T必须支持拷贝(拷贝构造函数)*/
template <typename T>
class SEAPI_API sesession_item {
	friend class sesessions<T>;
private:
	/*当前session的活动状态*/
	sesession_status _status;
	/*session最后一次活动时间*/
	time_t _active;
	/*session存储的数据*/
	T _data;
public:
	sesession_item(const T &data)
		: _status(sesession_idle)
		, _active(time(NULL))
		, _data(data) {
	};

	sesession_item(const sesession_item &obj)
		: _status(obj._status)
		, _active(obj._active)
		, _data(obj._data) {
	};

	~sesession_item(void) {
	};
public:
	/*获取会话数据*/
	const T &getdata() const {
		return _data;
	};

	/*获取会话数据*/
	T *getdataex() const{
		return &_data;
	};
};

template <typename T>
class SEAPI_API sesessions : boost::noncopyable {
public:
	typedef sesession_item<T> session_item;
private:
	const time_t WAIT_TIME_SECONDS;
	time_t _timeout; /*会话超时时间,单位毫秒*/
	map<STRING, session_item> _sessions;
private:
	boost::mutex _io_mutex;
	STRSTREAM _stream;
private:
	boost::scoped_ptr<boost::thread> _spthread;
	boost::mutex _mutex;
	boost::condition_variable_any _cond;
	bool _isrun, _isstop;
public:
	sesessions(void)
		: WAIT_TIME_SECONDS(60 * 1000)
		, _timeout(20 * 60)   /*修正time_t单位为秒,原来WAIT_TIME_SECONDS * 20=120000秒=2000分钟=33小时,33小时会话才会过期*/
		, _isrun(false)
		, _isstop(false) {
	};

	~sesessions(void) {
		stop();
	};
private:
	/*检查会话是否失效*/
	void session_check() {
		boost::mutex::scoped_lock lock(_mutex);
		_isrun = true;
		_cond.notify_one();
		while (!_isstop) {
			boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(WAIT_TIME_SECONDS);
			_cond.timed_wait(_mutex, timeout); /*unlock-wait-lock*/
			if (_isstop)
				break;
			time_t curTime = time(NULL);
			for (typename map< STRING, session_item >::iterator it = _sessions.begin(); it != _sessions.end();) {
				time_t interval = curTime - it->second._active; /*会话超时并且空闲时才删除*/
				if (interval >= _timeout && sesession_idle == it->second._status) {
					_sessions.erase(it++); /* Really smart! */
				} else {
					++it;
				}
			}
		}
		_isrun = false;
		_isstop = false;
	};

	/*重置session状态和活动时间*/
	void reset_session_status(session_item *pitem) {
		mutex::scoped_lock lock(_mutex);
		pitem->_status = sesession_idle;
		pitem->_active = time(NULL);
	};
public:
	/*生成32位uuid字符串*/
	void make_identifier(STRING &identifier) {
		boost::mutex::scoped_lock lock(_io_mutex);
		boost::uuids::uuid uid = boost::uuids::random_generator()();
		for (boost::uuids::uuid::const_iterator it = uid.begin(); it != uid.end(); ++it)
			_stream << setfill('0') << setw(2) << hex << (short) (*it);
		identifier = _stream.str();
		_stream.clear();
		_stream.str("");
	};

	/*获取是否运行*/
	inline bool get_isrun() {
		boost::mutex::scoped_lock lock(_mutex);
		return _isrun;
	};

	void set_session_timeout(const time_t &timeout) {
		boost::mutex::scoped_lock lock(_mutex);
		_timeout = timeout;
	};

	void get_session_timeout() {
		boost::mutex::scoped_lock lock(_mutex);
		return _timeout;
	};

	void start() SE_THROW_DESC(se_exception) {
		try {
			stop();
			_spthread.reset(new boost::thread(boost::bind(&sesessions::session_check, this)));
			if (!_spthread)
				SE_THROW(_T("启动会话检查线程失败!"));
			/*等待线程运行*/
			boost::mutex::scoped_lock lock(_mutex);
			_cond.wait(_mutex);
		} catch (se_exception &exp) {
			stop();
			throw exp;
		}
	};

	void stop() {
		if (!_spthread) return;
		/*通知线程停止*/
		{
			boost::mutex::scoped_lock lock(_mutex);
			_isstop = true;
			_sessions.clear();
			_cond.notify_one();
		}
		/*等待线程运行完成*/
		_spthread->join();
		_spthread.reset();
	};

	/*
	创建一个新的会话
	如果返回对象 false 时,表示当前identifier已经存在
	*/
	bool create_session(const STRING &identifier, const session_item &item) {
		boost::mutex::scoped_lock lock(_mutex);
		pair<typename map<STRING, session_item>::iterator, bool> ret = _sessions.insert(pair<STRING, session_item > (identifier, item));
		return ret.second;
	};

	/*更新Session最新活动时间(如果有)*/
	void reset_session_active(const STRING &identifier) {
		mutex::scoped_lock lock(_mutex);
		typename map<STRING, session_item>::iterator it = _sessions.find(identifier);
		if (it == _sessions.end())
			return;

		session_item &session = it->second;
		if (sesession_use == session._status) {
			/*会话正在使用,每过100毫秒检查一次是否正在使用,共检查三次*/
			for (int i = 0; i < 3; ++i) {
				boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(100);
				_cond.timed_wait(_mutex, timeout);
				if (sesession_idle == session._status)
					break;
			}
			if (sesession_idle != session._status)
				return;
		}
		session._active = time(NULL);
	};

	/*获取指定的session*/
	/*获取指定的session*/
	boost::shared_ptr< session_item > get_specify_session(const STRING &identifier) SE_THROW_DESC(se_exception) {
		boost::shared_ptr< session_item > spsession;
		/*范围锁,避免shared_ptr释放时死锁boost::mutex::scoped_lock lock和boost::shared_ptr注意使用方法,否则死锁*/
		do {
			boost::mutex::scoped_lock lock(_mutex);
			typename map<STRING, session_item>::iterator it = _sessions.find(identifier);
			if (it == _sessions.end())
				SE_THROW(_T("指定的会话超时或还未创建!"));
			session_item &session = it->second;
			if (sesession_use == session._status) {
				/*会话正在使用,每过100毫秒检查一次是否正在使用,共检查三次*/
				for (int i = 0; i < 3; ++i) {
					boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(100);
					_cond.timed_wait(_mutex, timeout);
					if (sesession_idle == session._status)
						break;
				}
				if (sesession_idle != session._status)
					SE_THROW(_T("指定的会话正在使用中,请稍候再试!"));
			}
			spsession.reset(&session, boost::bind(&sesessions<T>::reset_session_status, this, _1));
			if (spsession)
				spsession->_status = sesession_use;
			else
				SE_THROW(_T("创建对象失败,内存不足!"));
		} while (0);
		return spsession;
	}
#endif /*_BE43_6E9002874EFE_SESSION_H*/


使用说明:

1.start启动会话检查线程

2.create_session创建一个新的会话

3.get_specify_session获取会话

4.注意模板T必须有拷贝构造函数

5.为保证跨平台,使用boost,相关内容主参考boost

6.建议采用URL重写的方式来传递SessionID的值,不依赖Cookie。如果客户端Cookie禁用,则服务器可以自动通过重写URL的方式来保存Session的值。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐