(3)存储一个角色的基础信息(使用命令set)
存储结构:
key:BASE角色id ,value 角色基础信息
int playerId = player->get_player_base()->m_player_id;
char tmpBuf[64];
memset(tmpBuf,0,64);
sprintf(tmpBuf,"BASE%d",playerId);
string key(tmpBuf);
CRWRedisClient redisClient;
redis::client* tmpRedisClient = redisClient.get_redis_client();
if(NULL == tmpRedisClient)
{
return ;
}
try
{
tmpRedisClient->set(key, value);
}
catch (redis::redis_error & e)
{
cerr << "got exception: " << e.what() << endl << "FAIL" << endl;
return ;
}
4、读取redis的客户端应用
(1)一次获取一个玩家的装备包裹的所有道具(使用命令hgetall)
存储结构:
key : EQUIPMENTBAGplayerId frield: pos value:CBagItem
bool CRWRedisClientOperator::load_player_equipbag_from_redis(CGamePlayer* player)
{
if(NULL == player)
{
return false;
}
//通过playerId得到key值
int playerId = player->get_player_base()->m_player_id;
if(0 == playerId)
{
return false;
}
char tmpBuf[64];
memset(tmpBuf,0,64);
//根据键(EQUIPMENTBAG%d",playerId),获取该玩家 所有装备道具的数据到vector<pair<string,string> > strPairVec
//使用到接口void hgetall( const string_type & key, string_pair_vector & out )
sprintf(tmpBuf,"EQUIPMENTBAG%d",playerId);
string key(tmpBuf);
if(false == CRWRedisClientOperator::instance()->is_key_exist_in_redis(key))
{
return false;
}
vector<pair<string,string> > strPairVec;
//通过key值从redis取数据
CRWRedisClient redisClient;
redis::client* tmpRedisClient = redisClient.get_redis_client();
if(NULL == tmpRedisClient)
{
return false;
}
try
{
tmpRedisClient->hgetall(key,strPairVec);//获取一个玩家的所有装备背包道具
}
catch (redis::redis_error & e)
{
cerr << "got exception: " << e.what() << endl << "FAIL" << endl;
return false;
}
//得到背包
CPlayerBag* tmpBag = player->get_player_bag();
if(NULL == tmpBag)
{
return false;
}
vector<pair<string,string> >::iterator iter = strPairVec.begin();
for(;iter != strPairVec.end();iter++)
{
string frield = iter->first;
int pos = ACE_OS::atoi(frield.c_str());
string value = iter->second;
if(value.length() != sizeof(CBagItem))
{
return false;
}
CBagItem* equipItem = new CBagItem();
if(NULL == equipItem)
{
return false;
}
memcpy(equipItem,value.c_str(),value.length());
if(!tmpBag->insert_bagitem_equip(pos,equipItem))
{
return false;
}
}
return true;
}
(2)读取角色的基础信息(使用命令get)
存储结构:
key BASE角色id,value 角色基础信息
char tmpBuf[64];
memset(tmpBuf,0,64);
sprintf(tmpBuf,"BASE%d",player->get_player_base()->m_player_id);
string key(tmpBuf);
struct CPlayerBase playerMsg;
memset(&playerMsg, 0, sizeof(CPlayerBase));
string getValue;
CRWRedisClient redisClient;
redis::client* tmpRedisClient = redisClient.get_redis_client();
if(NULL == tmpRedisClient)
{
return false;
}
try
{
if (false == tmpRedisClient->exists(key))
{
cout <<key <<" not exists !!!" << endl;
return false;
}
getValue = tmpRedisClient->get(key);
}
catch (redis::redis_error & e)//对于会抛出异常的接口,需要捕捉异常
{
cerr << "got exception: " << e.what() << endl << "FAIL" << endl;
return false;
}
if(getValue.length() > sizeof(CPlayerBase))//如果比需要的长度要大,则是不合法的
{
return false;
}
memcpy(&playerMsg, getValue.c_str(), getValue.length());//直接在redis,copy到player中
//开始拷贝数据到角色指针的数据里
player->get_player_base()->m_player_id = playerMsg.m_player_id;
......
5、redis客户端池
客户端池的初始化
bool CRedisClientPool::init_redis_client_pool()
{
CRedisServer tmpRedisServer = CConfigManager::instance()->get_srv_config().get_redis_server_conf();
string redisIp = tmpRedisServer.get_ip();
int port = tmpRedisServer.get_port();
for(int i = 0; i < 5; i++)
{
if(false == init_redis_client(redisIp,port))
{
return false;
}
}
return true;
}
客户端连接初始化
bool CRedisClientPool::init_redis_client(string redisIp, int port)
{
try
{
redis::client* m_redis_client = new redis::client(redisIp,port,"");
if(NULL != m_redis_client)
{
push_redis_client(m_redis_client);//压到redis客户端池列表
}
}
catch (redis::redis_error & e)
{
cerr << "got exception: " << e.what() << endl << "FAIL" << endl;
return false;
}
return true;
}
添加客户端连接到客户端池
void CRedisClientPool::push_redis_client(redis::client* redisClient)
{
if(NULL == redisClient)
{
return ;
}
m_q_mutex.acquire();
m_redis_client_list.push_back(redisClient);
m_q_mutex.release();
}
6、第三方的库接口
(1)redis客户端对象
typedef base_client<default_hasher> client;
struct default_hasher
{
inline size_t operator()(const std::string & key, const std::vector<connection_data> & connections)
{
return boost::hash<std::string>()(key) % connections.size();//每次操作是根据键哈希获取连接列表里的一个,这样每个键可以尽量使用不同的连接(可能是为了某些多线程场景的减少锁竞争)
}
};
template<typename CONSISTENT_HASHER>
class base_client
{
private:
void init(connection_data & con)
{
char err[ANET_ERR_LEN];
con.socket = anetTcpConnect(err, const_cast<char*>(con.host.c_str()), con.port);//使用anet库做网络通信客户端接口
if (con.socket == ANET_ERR)
{
std::ostringstream os;
os << err << " (redis://" << con.host << ':' << con.port << ")";
throw connection_error( os.str() );
}
anetTcpNoDelay(NULL, con.socket);
select(con.dbindex, con);
}
public:
...
explicit base_client(const string_type & host = "localhost",
uint16_t port = 6379,const string_type &pwd ="",int_type dbindex = 0)
{
connection_data con;
con.host = host;
con.port = port;
con.dbindex = dbindex;
con.pwd = pwd;
init(con);
connections_.push_back(con);//初始化连接后放到连接列表里
}
(2)接口函数
获取redis的哈希表的值
void hgetall( const string_type & key, string_pair_vector & out )
{
int socket = get_socket(key);
send_(socket, makecmd("HGETALL") << key);//命令
string_vector s;
recv_multi_bulk_reply_(socket, s);//获取多个返回的回应消息作为HGETALL 的结果
for(size_t i = 0; i < s.size(); i+=2)
out.push_back( make_pair(s[i], s[i+1]) );
}
插入到redis的哈希表用到的
void hmset( const string_type & key, const string_pair_vector & field_value_pairs )
{
int socket = get_socket(key);
makecmd m("HMSET");//命令
m << key;
for(size_t i=0; i < field_value_pairs.size(); i++)
m << field_value_pairs[i].first << field_value_pairs[i].second;//把一个vector的键值发送过去设置
send_(socket, m);
recv_ok_reply_(socket);//接收应答结果
}
get命令
string_type get(const string_type & key)
{
int socket = get_socket(key);
send_(socket, makecmd("GET") << key);
return recv_bulk_reply_(socket);
}
读取网络数据
std::string recv_bulk_reply_(int socket)
{
int_type length = recv_bulk_reply_(socket, REDIS_PREFIX_SINGLE_BULK_REPLY );
if (length == -1)
return missing_value();
int_type real_length = length + 2; // CRLF
std::string data = read_n(socket, real_length);
#ifndef NDEBUG
//output_proto_debug(data.substr(0, data.length()-2));
#endif
if (data.empty())
throw protocol_error("invalid bulk reply data; empty");
if (data.length() != static_cast<std::string::size_type>(real_length))
throw protocol_error("invalid bulk reply data; data of unexpected length");
data.erase(data.size() - 2);
return data;
}
(3)定义的异常
定义的redis异常的基础类
class redis_error : public std::exception
{
public:
redis_error(const std::string & err) : err_(err) {}
virtual ~redis_error() throw () {}
operator const std::string () const { return err_; }
virtual const char* what() const throw ()
{
return err_.c_str();
}
private:
std::string err_;
};