需求
C++中使用hiredis客戶端接口訪問redis;
需要使用mset一次設置多個二進制數據
以下給出三種封裝實現方案;
簡單拼接方案
在redis-cli中,mset的語法是這樣的:
OK
按照這樣的語法拼接后,直接使用hiredis字符串接口redisCommand傳遞:
- void msetNotBinary(redisContext *c, const vector<string> &vtKey, const vector<string> & vtVal )
- {
- if(vtKey.size() != vtVal.size())
- {
- throw runtime_error( "Redis error" );
- }
- string strCmd = "MSET";
- for(int i = 0; i < vtKey.size(); i++)
- {
- strCmd += " "+vtKey[i]+" "+vtVal[i];
- }
- cout << "strCmd:" << strCmd << endl;
- void * r = redisCommand(c, strCmd.c_str() );
- if ( !r )
- throw runtime_error( "Redis error" );
- freeReplyObject( r );
- }
- void do_test( redisContext *c )
- {
- vector<string> vtKey;
- vector<string> vtVal;
- vtKey.push_back("A");
- vtVal.push_back("AAAA");
- vtKey.push_back("B");
- vtVal.push_back("BBBB");
- vtKey.push_back("C");
- vtVal.push_back("CCCC");
- //add a binary data
- vtKey.push_back("D");
- vtVal.push_back("");
- char a[] = "ABCDE";
- a[2] = 0;
- vtVal[3].assign(a,5);
- try
- {
- msetNotBinary(c, vtKey, vtVal );
- //mset1( c, vtKey, vtVal );
- //mset2( c, vtKey, vtVal );
- }
- catch ( runtime_error & )
- {
- cout << "Error" << endl;
- }
- }
- int main(int argc, char *argv[])
- {
- redisContext *c;
- c = redisConnect("127.0.0.1",6379);
- if (c->err)
- {
- cout << "Connection error: " << c->errstr << endl;
- return -1;
- }
- do_test(c);
- redisFree(c);
- return 0;
- }
這種方式可以處理mset多個字符串數據,但對于數據內容為二進制數據的無能為力;
redisCommandArgv接口傳遞 方案
對于多個參數傳遞,hiredis提供了以下接口,這個接口中最后一個參數是所有的傳入數據的內容長度,
就是說這個接口是二進制安全的:
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
主要工作就是構造一個動態的二維數組char ** argv,其中涉及到char **到const char **的轉換,有一定的風險,
關于這一點前一篇文章已經談到;
- void mset1( redisContext *c, const vector<string> &vtKey, const vector<string> & vtVal )
- {
- if(vtKey.size() != vtVal.size())
- {
- throw runtime_error( "Redis error" );
- }
- char ** argv = new char*[vtKey.size() + vtVal.size() + 1 ];
- size_t * argvlen = new size_t[vtKey.size() + vtVal.size() + 1 ];
- int j = 0;
- argv[j] = new char[5];
- memcpy(argv[j],"MSET",4);
- argvlen[j] = 4;
- ++j;
- for(int i = 0 ; i < vtKey.size();i++)
- {
- argvlen[j] = vtKey[i].length();
- argv[j] = new char[argvlen[j]];
- memset((void*)argv[j],0,argvlen[j] );
- memcpy((void*)argv[j],vtKey[i].data(),vtKey[i].length());
- j++;
- argvlen[j] = vtVal[i].length();
- argv[j] = new char[argvlen[j]];
- memset((void*)argv[j],0,argvlen[j]);
- memcpy((void*)argv[j],vtVal[i].data(),vtVal[i].length());
- j++;
- }
- //if not use const_cast<const char**> ,compile error
- //for why assign from char** to const char** error, see my blog ...
- void *r = redisCommandArgv(c, vtKey.size() + vtVal.size() + 1, const_cast<const char**>(argv), argvlen );
- if ( !r )
- throw runtime_error( "Redis error" );
- freeReplyObject( r );
- for(int i = 0;i < vtKey.size();i++)
- {
- delete [] argv[i];
- argv[i] = NULL;
- }
- delete []argv;
- delete []argvlen;
- argv = NULL;
- }
redisCommandArgv接口傳遞的Vector方案
還是使用redisCommandArgv接口,使用vector來構造這個const char **,這個方法是從參考資料1中學到的:
- void mset2( redisContext *c, const vector<string> &vtKey, const vector<string> & vtVal)
- {
- if(vtKey.size() != vtVal.size())
- {
- throw runtime_error( "Redis error" );
- }
- vector<const char *> argv( vtKey.size() + vtVal.size() + 1 );
- vector<size_t> argvlen( vtKey.size() + vtVal.size() + 1 );
- int j = 0;
- static char msetcmd[] = "MSET";
- argv[j] = msetcmd;
- argvlen[j] = sizeof(msetcmd)-1;
- ++j;
- for(int i = 0;i< vtKey.size();++i)
- {
- argvlen[j] = vtKey[i].length();
- argv[j] = new char[argvlen[j]];
- memset((void*)argv[j],0,argvlen[j] );
- memcpy((void*)argv[j],vtKey[i].data(),vtKey[i].length());
- j++;
- argvlen[j] = vtVal[i].length();
- argv[j] = new char[argvlen[j]];
- memset((void*)argv[j],0,argvlen[j]);
- memcpy((void*)argv[j],vtVal[i].data(),vtVal[i].length());
- j++;
- }
- void *r = redisCommandArgv(c, argv.size(), &(argv[0]), &(argvlen[0]) );
- if ( !r )
- throw runtime_error( "Redis error" );
- freeReplyObject( r );
- }
這樣,就實現二進制數據的傳遞;
二進制校驗
程序執行后,可以用redis-cli來驗證:
對于非二進制安全的實現,二進制內容是截斷的:
而二進制安全的實現接口,二進制數據的0通過轉義方式顯示:
完整可執行的代碼詳見github:https://github.com/me115/cppset/tree/master/2DimArray
以上所述就是本文的全部內容了,希望大家能夠喜歡。
新聞熱點
疑難解答