/*自定义标准头文件*/ #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*/ 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(_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("创建对象失败,内存不足!")); } 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的值。