C++ http Session
/*自定义标准头文件*/#ifndef _BE43_6E9002874EFE_SESTD_H#define_BE43_6E9002874EFE_SESTD_H#ifdef SEAPI_EXPORTS#define SEAPI_API __declspec(dllexport)#else#define SEAPI_API#endif#include...
·
/*自定义标准头文件*/
#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的值。
更多推荐
已为社区贡献1条内容
所有评论(0)