天天看點

艾偉:自己實作memcached用戶端庫

What's memcached ?

memcached以key-value的形式來儲存資料,你可以為你每一段資料關聯一個key,然後以後可以通過這個key擷取

這段資料。

将其運作在網絡中的一台伺服器上,通過網絡,在遵循memcached的協定的基礎上與memcached伺服器進行通信。

What do we want to wrap ?

add/get之類的接口即可實作往memcached伺服器緩存資料,以及取資料。上層程式員根本不知道這些資料在網絡

上存在過。

的工作當作一次網絡程式設計的練習。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用戶端庫

安裝:memcached.exe -d install,這會在windows服務裡添加一個memcached服務

艾偉:自己實作memcached用戶端庫

運作:memcached.exe -d start,你也可以通過windows的服務管理運作。

艾偉:自己實作memcached用戶端庫

然後,你可以在任務管理器裡看到一個'memcached'的程序,很占記憶體,因為這是memcached。

So, here we go ...

通過以上步驟運作的memcached,預設在11211端口監聽(是個TCP連接配接,可以通過netstat檢視)。接下來,我們就可

以connect到該端口上,然後send/recv資料了。發送/接收資料隻要遵循memcached的協定格式,一切都很簡單。

使用最簡單的阻塞socket連接配接memcached伺服器:

艾偉:自己實作memcached用戶端庫

       SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );

艾偉:自己實作memcached用戶端庫

        struct sockaddr_in addr;

艾偉:自己實作memcached用戶端庫

        memset( &addr, 0, sizeof( addr ) );

艾偉:自己實作memcached用戶端庫

        addr.sin_family = AF_INET;

艾偉:自己實作memcached用戶端庫

        addr.sin_port = htons( 11211 );

艾偉:自己實作memcached用戶端庫

        addr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); 

艾偉:自己實作memcached用戶端庫
艾偉:自己實作memcached用戶端庫

        ret = connect( s, (struct sockaddr*) &addr, sizeof( addr ) );

艾偉:自己實作memcached用戶端庫

        if( ret == 0 )

艾偉:自己實作memcached用戶端庫
艾偉:自己實作memcached用戶端庫
艾偉:自己實作memcached用戶端庫

{

艾偉:自己實作memcached用戶端庫

            printf( "connect ok\n" );

艾偉:自己實作memcached用戶端庫

        } 

艾偉:自己實作memcached用戶端庫
艾偉:自己實作memcached用戶端庫

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

艾偉:自己實作memcached用戶端庫

        char cmd[256] ;

艾偉:自己實作memcached用戶端庫

        char data[] = "test data";

艾偉:自己實作memcached用戶端庫

        sprintf( cmd, "set TestKey 0 0 %d\r\n", strlen( data ) );

艾偉:自己實作memcached用戶端庫

        ret = send( s, cmd, strlen( cmd ), 0 ); 

艾偉:自己實作memcached用戶端庫
艾偉:自己實作memcached用戶端庫

注意:noreply選項對于有些memcached版本并不被支援,例如我們使用的1.2.2版本。注意官方的changelog即可。

當你發送了存儲指令後,memcached會等待用戶端發送資料塊。是以我們繼續發送資料塊:

艾偉:自己實作memcached用戶端庫

        ret = send( s, data, strlen( data ), 0 );

艾偉:自己實作memcached用戶端庫

        ret = send( s, "\r\n", 2, 0 ); // 資料結束符

然後,正常的話,memcached伺服器會傳回應答資訊給用戶端。

艾偉:自己實作memcached用戶端庫

        char reply[256];

艾偉:自己實作memcached用戶端庫

        ret = recv( s, reply, sizeof( reply ) - 1, 0 );

艾偉:自己實作memcached用戶端庫

        reply[ret] = 0;

艾偉:自己實作memcached用戶端庫

        printf( "server reply : %s\n", reply ); 

如果存儲成功,伺服器會傳回STORED字元串。memcached所有應答資訊都是以字元串的形式給出的。是以可以直接printf出來。

對應着memcached的協定看,很容易看懂的。

It's a story about a programmer...

最近發覺自己有點極端,要麼寫純C的代碼,要麼寫滿是template的泛型代碼。

<a href="http://www.cppblog.com/Files/kevinlynx/kl_memcached.rar" target="_blank">相關代碼下載下傳</a>

繼續閱讀