[实践OK]libmemcached使用(c 客户端连接 memcached),封装 libmemcached 构建 memcached 客户端。

jackxiang 2015-2-15 17:05 | |
背景:如果要用c写成一个服务部署4台机器,均得和memcached交互,还得用这个库,如PHP的扩展啥的没怎么和c的lib打交到,这下实践一下挺好的,过程比较曲折但是也发现了这memcached用新的gcc还是对配置上有一些影响的,就单说配置这块的门槛就变高了,更别说c下的调试啥的,实践起来仅仅通过网上的一篇文章未必能搞定。
libmemcached是C客户端到memcached服 务器的接口库。具有低内存占用率、线程安全、并提供对memcached功能的全面支持。它还采用多种命令行工具,包括: memcat、memflush、memrm、memstat、memslap。
在Ubuntu上安装memcached和libmemcached  http://www.linuxidc.com/Linux/2010-04/25543.htm
libmemcached C/C++ API使用实例 http://www.linuxidc.com/Linux/2012-01/52516.htm
memcached简单的使用教程(转载):          http://blog.csdn.net/huangqiwa/article/details/21174425
使用连接池访问memcached(libmemcached)的完整例子:http://blog.csdn.net/hzhxxx/article/details/41961355

(1)封装 libmemcached 构建 memcached 客户端:http://blog.csdn.net/yanghw0510/article/details/7292236
(2)libmemcached使用(c 客户端连接 memcached) :
(3)libmemcached 下载地址。https://launchpad.net/libmemcached/

1、下载安装libmemcached
$ wget http://launchpad.net/libmemcached/1.0/0.44/+download/libmemcached-0.44.tar.gz
$ tar xvzf libmemcached-0.44tar.gz
$ cd libmemcached-0.44
$ ./configure
$ make
$ sudo make install
libmemcached 默认安装在/usr/local/,头文件安装在/usr/local/include/libmemcachde/,动态库默认安装在/usr/local/lib/下。
我在这儿下的:https://launchpadlibrarian.net/165454254/libmemcached-1.0.18.tar.gz
注:
如果报”./libmemcached-1.0/memcached.h:46:27: error: tr1/cinttypes: No such file or directory”错误,则需要升级gcc版本.
处理如下:
yum install gcc44 gcc44-c++ libstdc++44-devel
export CC=/usr/bin/gcc44
export CXX=/usr/bin/g++44
重新编译安装libmemcached-1.0.9
关键信息:error: tr1/cinttypes: No such file or directory
报错原因:libmemcached需要 gcc 4.2 以上版本才可编译,而centos 5.4 的gcc版本只有4.1 ,详见:https://bugs.launchpad.net/libmemcached/+bug/1076181
解决方法:安装gcc44的扩展包,详见:http://gearman.info/build/centos5-8.html
export就是在于此,把这个gcc和g++的版本号给提上去,以方便这个memcached的编译:
/usr/bin/gcc44 -v
gcc version 4.4.7 20120313 (Red Hat 4.4.7-1) (GCC)

gcc -v
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

/usr/bin/g++44 -v
gcc version 4.4.7 20120313 (Red Hat 4.4.7-1) (GCC)
g++ -v
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)
——————————————————————————————————————————————————————————
这个问题在安gearman时也遇到过,升级gcc,参考连接: http://jackxiang.com/post/7693/ ,软链接如下所示:
export CC=/usr/bin/gcc44 or export CC=/usr/bin/gcc
export CXX=/usr/bin/g++44
./configure && make && make install      

./configure && make && make install
/usr/bin/install -c -m 644 support/libmemcached.pc '/usr/local/lib/pkgconfig'
make[2]: Leaving directory `/tmp/testmemcachedcpp/libmemcached-1.0.18'
make[1]: Leaving directory `/tmp/testmemcachedcpp/libmemcached-1.0.18'

g++ -o testmemcached testmemcached.cpp -lmemcached  
In file included from /usr/local/include/libmemcached/memcached.h:39,
                 from testmemcached.cpp:6:
/usr/local/include/libmemcached-1.0/memcached.h:46:23: error: cinttypes: No such file or directory
明天再整下,估计是so没有给ldd进来...
2、libmemcached简单测试使用


编译:g++ -o testmemcached testmemcached.cpp -lmemcached
运行:./testmemcached
结果:Save data:value sucessful!
      Get value:value sucessful!
      Delete key:key sucessful!

实践编译一下:
g++ -o testmemcached testmemcached.cpp -lmemcached
In file included from /usr/local/include/libmemcached/memcached.h:39,
                 from testmemcached.cpp:6:
/usr/local/include/libmemcached-1.0/memcached.h:46:23: error: cinttypes: No such file or directory
看来还得重新export一次新的编译器,因为昨天的关了终端,今天的又没了:
export CC=/usr/bin/gcc44 or export CC=/usr/bin/gcc  //这行有问题~
export CXX=/usr/bin/g++44
g++ -o testmemcached testmemcached.cpp -lmemcached
为何还是不行?
echo $CC
/usr/bin/gcc  //没变,这儿有问题,再重新设置一次,查到上面这个or有问题:export CC=/usr/bin/gcc44。
# echo $CXX
/usr/bin/g++44 //变了

重新设置,好了:
export CC=/usr/bin/gcc44
/usr/bin/gcc44

继续折腾,/usr/bin/gcc44 -o testmemcached testmemcached.cpp -lmemcached
In file included from /usr/lib/gcc/x86_64-redhat-linux6E/4.4.7/../../../../include/c++/4.4.7/cinttypes:35,
                 from /usr/local/include/libmemcached-1.0/memcached.h:46,
                 from /usr/local/include/libmemcached/memcached.h:39,
                 from testmemcached.cpp:6:
/usr/lib/gcc/x86_64-redhat-linux6E/4.4.7/../../../../include/c++/4.4.7/c++0x_warning.h:31:2: error: #error This file requires compiler and library support for the upcoming ISO C++ standard, C++0x. This support is currently experimental, and must be enabled with the -std=c++0x or -std=gnu++0x compiler options.


#error This file requires compiler and library support for the upcoming ISO C++ standard, C++0x.
加上:-lpthread -std=c++0x ,解决如下:
g++ -o testmemcached testmemcached.cpp -lmemcached -lpthread -std=c++0x
/usr/bin/ld: cannot find -lmemcached
collect2: ld returned 1 exit status  
也就是说编译器并不能从ldconfig 里得知,其lib在哪儿(及时把Lib路径加入到/etc/ld.so.conf.d/libmemcache.conf),得指定:


在网上找了一下,发现是这样的:http://blog.163.com/guixl_001/blog/static/4176410420121021111117987/ 里说得加一个新的参数,是和宏相关,那就加了,
指定一个新的参数:-std=c++0x :
/usr/bin/gcc44  -o testmemcached testmemcached.cpp -lmemcached   -std=c++0x            
/usr/local/lib/libmemcached.so: undefined reference to `pthread_once'
collect2: ld returned 1 exit status


/usr/bin/g++44  -o testmemcached testmemcached.cpp -lmemcached   -std=c++0x              
/usr/local/lib/libmemcached.so: undefined reference to `pthread_once'
怎样彻底解决"undefined reference to `pthread_create'"问题 ,说是加个: -lrt ,这一看就是那个memcached的库包含了这个文件:#include<pthread.h>
来源参考:
http://bbs.chinaunix.net/thread-1586752-1-1.html

于是Ok啦,最终O了,如下:
[root@test testmemcachedcpp]# /usr/bin/g++44  -o testmemcached testmemcached.cpp -lmemcached -lrt  -std=c++0x
[root@test testmemcachedcpp]#  
运行一下试试:
[root@test testmemcachedcpp]#  ./testmemcached
./testmemcached: error while loading shared libraries: libmemcached.so.11: cannot open shared object file: No such file or directory
[root@test /]# find . -name "libmemcached.so.11"
./usr/local/lib/libmemcached.so.11
打开配置文件 vi /etc/ld.so.conf
加上一行:/usr/local/lib
执行/sbin/ldconfig /etc/ld.so.conf
[root@test testmemcachedcpp]# /sbin/ldconfig /etc/ld.so.conf
[root@test testmemcachedcpp]# ./testmemcached              
[root@test testmemcachedcpp]#
没报错了~,用gdb看一下 加个-g参数:
/usr/bin/g++44 -g  -o testmemcached testmemcached.cpp -lmemcached -lrt  -std=c++0x

发现localhost没有开11211,于是找了一台机器把ip和端口写上,重新编译一次后运行Ok,如下:
[root@test testmemcachedcpp]# ./testmemcached
Save data:value sucessful!
Get value:value sucessful!

少了一个删除成功的,简单调试一下:
(gdb) n
Get value:value sucessful!
50         rc=memcached_delete(memc,key.c_str(),key_length,expiration);
(gdb) p key.c_str()
$5 = 0x184372e8 "key"
(gdb) p key_length
$6 = 3
(gdb) n
51         if(rc==MEMCACHED_SUCCESS)
(gdb) p rc
$3 = MEMCACHED_INVALID_ARGUMENTS

也就是调这个函数的参数不对,返回不是MEMCACHED_SUCCESS,所以没有打印出:cout<<"Delete key:"<<key<<" sucessful!"<<endl;

####################新的代码里grep了一下该方法###########################
./tests/mem_udp.cc:                 memcached_delete(memc, test_literal_param("foo"), 0));
./libmemcached-1.0/memcached.hpp:    return memcached_success(memcached_delete(memc_, key.c_str(), key.length(), 0));
./libmemcached-1.0/memcached.hpp:    return memcached_success(memcached_delete(memc_,
./tests/libmemcached-1.0/replication.cc:    memcached_return_t del_rc= memcached_delete(memc_replicated,
./tests/libmemcached-1.0/mem_functions.cc:    rc= memcached_delete(memc, "foo", 3, 1);

./tests/libmemcached-1.0/mem_functions.cc:    test_compare(MEMCACHED_BUFFERED, (rc= memcached_delete(memc, "foo", 3, 0)));
./tests/libmemcached-1.0/mem_functions.cc:    test_compare(MEMCACHED_SUCCESS, memcached_delete(memc, "foo", 3, 0));
./tests/libmemcached-1.0/mem_functions.cc:    test_compare(MEMCACHED_NOTFOUND, memcached_delete(memc, "foo", 3, 0));

####################################################################
于是修改为下面这样:
//rc=memcached_delete(memc,key.c_str(),key_length,expiration);
rc=memcached_delete(memc,key.c_str(),key_length,0);

./testmemcached
Save data:value2 sucessful!
Get value:value2 sucessful!
Delete key:key sucessful!

刚才失败时有值,现在运行后没值了,给成功删除了:
[root@localhost ~]# telnet 192.168.108.7 11211
Escape character is '^]'.
get key
VALUE key 0 5
value
END
get key
END



后面怎么结合c的socket 及epoll进行进程/线程调试就不再细说了,我也在摸索中,应该也有相关的调试办法,但这儿说明这个memcached搞个新的gcc版本库才能编译确实带了相当多编译及配置上的的麻烦~

最后,用C函数里的add函数实现类php的memcache的扩展的原子操作函数,如下:
原子操作方法,假如有add后就不能再add,必须删除后才能add,这个可以用作锁:
./libmemcached-1.0.18/libmemcached-1.0/memcached.hpp:    


和php的add函数一样第一次运行时没有问题此时值设置成功,再运行add时一次就add不进去,add设置进去后,用set是能重新设置进去的,只是用add原子操作是不行的,用它来做锁很好使:
1)代码片段:

2)运行情况:
[root@test testmemcachedcpp]# gdb testmemcached
b 41
r
Add data:value unsucessful,Perhaps add key before set !
(gdb) p rc
$2 = MEMCACHED_NOTSTORED
但是能够set进去:
42         rc=memcached_set(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);
(gdb) n
43         if(rc==MEMCACHED_SUCCESS)
(gdb) p rc
$3 = MEMCACHED_SUCCESS
EOF


对add后的键对应的值,再用set方法是可以设置的,如下:
string key = "key2";
string value = "jackxiang";
rc=memcached_add(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);
后再修改这个值:
value = "xiangdong";
rc=memcached_set(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);

用gdb的断点跟踪一下并用telnet在设置后查看,如下:
[root@localhost ~]# telnet 192.168.108.7 11211
Escape character is '^]'.
get key2
END
get key2
VALUE key2 0 9
jackxiang
END
get key2
VALUE key2 0 9
xiangdong
END

听说,在下载客户端libmemcached-1.0.18/tests 下有测试列子,也可参考。比如cpp_example.cc
ls ~+/cpp_example.cc
/tmp/testmemcachedcpp/libmemcached-1.0.18/tests/cpp_example.cc

摘自:http://www.cppblog.com/kefeng/archive/2010/10/11/129422.html
         http://blog.chinaunix.net/uid-52437-id-2108905.html
后发现这个哥们写的文章很详细,http://blog.chinaunix.net/uid-20548989-id-1667248.html

加入add后,rc=MEMCACHED_NOTSTORED情况,代码贴下面:

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:http://jackxiang.com/post/7814/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2017-8-1 17:11
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]