loop_in_codes

低调做技术__欢迎移步我的独立博客 codemaro.com 微博 kevinlynx

自己实现memcached客户端库

Kevin Lynx

7.21.2008

What's memcached ?

memcached是一个以key-value的形式缓存数据的缓存系统。通过将数据缓存到内存中,从而提高数据的获取速度。
memcached以key-value的形式来保存数据,你可以为你每一段数据关联一个key,然后以后可以通过这个key获取
这段数据。

memcached是一个库还是什么?memcached其实是一个单独的网络服务器程序。它的网络底层基于libevent,你可以
将其运行在网络中的一台服务器上,通过网络,在遵循memcached的协议的基础上与memcached服务器进行通信。

What do we want to wrap ?

我们需要做什么?我们只需要遵循memcached的协议(参见该文档),封装网络层的通信,让上层可以通过调用诸如
add/get之类的接口即可实现往memcached服务器缓存数据,以及取数据。上层程序员根本不知道这些数据在网络
上存在过。

这个东西,也就是memcached官方所谓的client apis。你可以使用现成的客户端库,但是你也可以将这种重造轮子
的工作当作一次网络编程的练习。it's up to you.:D

Where to start ?

很遗憾,对于windows用户而言,memcached官方没有给出一个可以执行或者可以直接F7即可得到可执行文件的下载
(如果你是vc用户)。幸运的是,已经有人做了这个转换工作。

你可以从http://jehiah.cz/projects/memcached-win32/这里下载到memcached的windows版本,包括可执行程序和
源代码。

我们直接可以运行memcached.exe来安装/开启memcached服务器,具体步骤在以上页面有所提及:

安装:memcached.exe -d install,这会在windows服务里添加一个memcached服务
运行:memcached.exe 
-d start,你也可以通过windows的服务管理运行。

   
然后,你可以在任务管理器里看到一个'memcached'的进程,很占内存,因为这是memcached。

So, here we go ...

通过以上步骤运行的memcached,默认在11211端口监听(是个TCP连接,可以通过netstat查看)。接下来,我们就可
以connect到该端口上,然后send/recv数据了。发送/接收数据只要遵循memcached的协议格式,一切都很简单。

使用最简单的阻塞socket连接memcached服务器:

       SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );
        
struct sockaddr_in addr;
        memset( 
&addr, 0sizeof( addr ) );
        addr.sin_family 
= AF_INET;
        addr.sin_port 
= htons( 11211 );
        addr.sin_addr.s_addr 
= inet_addr( "127.0.0.1" ); 

        ret 
= connect( s, (struct sockaddr*&addr, sizeof( addr ) );
        
if( ret == 0 )
        
{
            printf( 
"connect ok\n" );
        }
 

       
About the protocol

简单地提一下memcached的协议。

可以说,memcached的协议是基于行的协议,因为无论是客户端请求还是服务器端应答,都是以"\r\n"作为结束符。
memcached的协议将数据(send/recv操作的数据)分为两种类型:命令和用户数据。

命令用于服务器和客户端进行交互;而用户数据,很显然,就是用户想要缓存的数据。

关于用户数据,你只需要将其编码成字节流(说白了,只要send函数允许即可),并附带数据结束标志"\r\n"发送即可。

关于命令,memcached分为如下几种命令:存储数据、删除数据、取出数据、其他一些获取信息的命令。其实你换个角度
想想,memcached主要就是将数据存储到内存里,所以命令也多不了哪去,基本就停留在add/get/del上。

关于key,memcached用key来标识数据,每一个key都是一个不超过255个字符的字符串。

到这里,你可以发现memcached对于数据的存储方式(暴露给上层)多少有点像std::map,如果你愿意,你可以将客户端
API封装成map形式。= =#

具体实现

接下来可以看看具体的实现了。

首先看看存储数据命令,存储数据命令有:add/set/replace/append/prepend/cas。存储命令的格式为:
<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
具体字段的含义参看protocol.txt文件,这里我对set举例,如下代码,阻塞发送即可:

        char cmd[256] ;
        
char data[] = "test data";
        sprintf( cmd, 
"set TestKey 0 0 %d\r\n", strlen( data ) );
        ret 
= send( s, cmd, strlen( cmd ), 0 ); 


注意:noreply选项对于有些memcached版本并不被支持,例如我们使用的1.2.2版本。注意官方的changelog即可。

当你发送了存储命令后,memcached会等待客户端发送数据块。所以我们继续发送数据块:

 

        ret = send( s, data, strlen( data ), 0 );
        ret 
= send( s, "\r\n"20 ); // 数据结束符

 

然后,正常的话,memcached服务器会返回应答信息给客户端。

 

        char reply[256];
        ret 
= recv( s, reply, sizeof( reply ) - 10 );
        reply[ret] 
= 0;
        printf( 
"server reply : %s\n", reply ); 

 

如果存储成功,服务器会返回STORED字符串。memcached所有应答信息都是以字符串的形式给出的。所以可以直接printf出来。

关于其他的操作,我就不在这里列举例子了。我提供了我封装的memcached客户端库的完整代码下载,使用的是阻塞socket,
对应着memcached的协议看,很容易看懂的。

It's a story about a programmer...

最近发觉自己有点极端,要么写纯C的代码,要么写满是template的泛型代码。

 

相关代码下载

posted on 2008-07-21 15:54 Kevin Lynx 阅读(6321) 评论(5)  编辑 收藏 引用 所属分类: network

评论

# re: 自己实现memcached客户端库 2008-10-23 16:56 浪迹天涯

学习了!
不知博主是否真实测试过采用memcached的服务器性能有多少提升?  回复  更多评论   

# re: 自己实现memcached客户端库[未登录] 2008-10-23 20:44 Kevin Lynx

@浪迹天涯
老实说,实际项目里还没用过memcached。  回复  更多评论   

# re: 自己实现memcached客户端库 2009-03-26 17:35 阿斯蒂芬

你的代码在linux上编译报出这个错误error: storage size of 'addr' isn't known
行号在sizeof( addr ).也就是获取结构大小的时候.  回复  更多评论   

# re: 自己实现memcached客户端库[未登录] 2009-03-26 18:05 Kevin Lynx

@阿斯蒂芬
能不能具体点?哪个文件,哪一行?
我稍微搜索了下代码,发现只有在fun_test.txt里才有sizeof( addr ),这个文件是用于功能测试的,只要kl_memcached下的源文件编译得过你就可以使用。:)  回复  更多评论   

# re: 自己实现memcached客户端库 2011-06-21 11:23 110

@阿斯蒂芬
这是windows下的代码,姐  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理