C擴展 從共享內存shm到memcache外部內存 Linux共享內存(一) Memcache 協議 (譯) Memcached通訊協議(中文版)

引言 - ipc - shm 共享內存html

  本文會經過案例瞭解ipc 的共享內存機制使用, 後面會講解C 如何使用外部內存服務memcached. 好先開始瞭解 linux 共享內存機制.linux

推薦先參看下面內容回顧一下 共享內存 linux api.git

  linux進程間的通訊(C): 共享內存    http://blog.chinaunix.net/uid-26000296-id-3421346.htmlgithub

上面文章能夠簡單看一下概念.  下面這篇文章好些, 能夠細看加深共享內存api使用熟練度.ubuntu

  Linux共享內存(一)  http://www.cnblogs.com/hicjiajia/archive/2012/05/17/2506632.htmlapi

那咱們開始吧. 先看 初步編譯文件 Makefile緩存

CC = gcc 
DEBUG = -ggdb3 -Wall
RUN = $(CC) $(DEBUG) -o $@ $^

all:shmsrv.out shmclt.out

shmsrv.out:shmsrv.c
    $(RUN)
shmclt.out:shmclt.c
    $(RUN)

# 刪除 make clean 操做
.PHONY:clean
clean:
    rm -rf *.i *.s *.o *.out *~ core_*; ls -al

 先看 共享內存 服務器端, 主要是寫內容到共享內存中. shmsrv.cbash

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

// 控制檯打印錯誤信息, fmt必須是雙引號括起來的宏
#define CERR(fmt, ...) \
    fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\
             __FILE__, __func__, __LINE__, errno, strerror(errno),##__VA_ARGS__)

// 控制檯打印錯誤信息並退出, t一樣fmt必須是 ""括起來的字符串常量
#define CERR_EXIT(fmt,...) \
        CERR(fmt,##__VA_ARGS__),exit(EXIT_FAILURE)

// 簡單檢測,意外就退出
#define IF_CHECK(code) \
      if((code) < 0) \
        CERR_EXIT(#code)

// 共享內存key
#define _INT_SHMKEY (0x12321)

/*
 * 這裏設置一個共享內存, 寫入數據, 讓別人來讀.
 * 寫入的數據內容來自用戶輸入.
 * 須要先啓動
 */
int main(int argc, char* argv[]) {
    int shmid, i, j;
    char* shm;

    // 檢測參數輸入
    if(argc < 2)
        CERR_EXIT("uage: %s argv[1] [argv[.]].", argv[0]);

    /*
     *  0764 是0開頭表示八進制數,
     *  7表示 當前進程具備讀寫執行權限, 
     *     6表示 同會話組具備讀寫權限, 同組表示groupid 相同 
     *     4表示 其它表示具備讀權限
     */
    IF_CHECK(shmid = shmget(_INT_SHMKEY, BUFSIZ+1, 0764|IPC_CREAT));
    
    // 添加簡單測試 
    printf("test stdio.h BUFSIZ = %d\n", BUFSIZ);

    // 開始共享內存關聯
    shm = shmat(shmid, NULL, 0);
    // 這裏寫入數據
    for(i=j=0; i<argc; ++i) {
        const char* ts = argv[i];
        while(*ts) {
            shm[j++] = *ts++;
            if(j>=BUFSIZ)
                break;
        }
        if(j>=BUFSIZ)
            break;
        shm[j++] = ' ';
    }
    shm[j] = '\0';

    // 這裏查看一下共享內存信息
    system("ipcs -m");

    // 取消關聯
    IF_CHECK(shmdt(shm));

    // 刪除共享內存
    //IF_CHECK(shmctl(shmid, IPC_RMID, NULL));
    
    return 0;    
}

推薦看 上面代碼 瞭解共享內存api使用方式, 先建立或打開, 後面綁定, 再到取消綁定等價於內核引用計數減一.服務器

可能須要注意的是 對於 0764 詳細解釋, 這個是約定, 採用八進制數, 第一個數 7 = 4 + 2 + 1 .網絡

4表示讀權限, 2表示寫權限, 1表示 可執行權限. 文件權限能夠 搜一下了解.

例如 文件權限   http://blog.chinaunix.net/uid-20864319-id-448817.html

後面

ipcs -m 

表示查看 全部共享內存狀態. 具體的操做命令能夠繼續搜一搜.

例如  ipc 命令 http://www.cnblogs.com/cocowool/archive/2012/05/22/2513027.html

運行結果以下

 

表示當前鏈接數爲1. 大小爲8193 權限是 0764, 名稱爲 0x00012321.

再來看 客戶端只讀取 shmclt.c 

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

// 控制檯打印錯誤信息, fmt必須是雙引號括起來的宏
#define CERR(fmt, ...) \
    fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\
             __FILE__, __func__, __LINE__, errno, strerror(errno),##__VA_ARGS__)

// 控制檯打印錯誤信息並退出, t一樣fmt必須是 ""括起來的字符串常量
#define CERR_EXIT(fmt,...) \
        CERR(fmt,##__VA_ARGS__),exit(EXIT_FAILURE)

// 簡單檢測,意外就退出
#define IF_CHECK(code) \
      if((code) < 0) \
        CERR_EXIT(#code)

// 共享內存key
#define _INT_SHMKEY (0x12321)

/*
 * 這裏設置一個共享內存, 寫入數據, 讓別人來讀.
 * 寫入的數據內容來自用戶輸入.
 * 須要先啓動
 */
int main(int argc, char* argv[]) {
    int shmid;
    char* shm;

    IF_CHECK(shmid = shmget(_INT_SHMKEY, BUFSIZ+1, IPC_CREAT));

    // 開始共享內存關聯
    shm = shmat(shmid, NULL, 0);

    // 輸出內容
    puts(shm);
    // 這裏查看一下共享內存信息
    system("ipcs -m");

    // 取消關聯
    IF_CHECK(shmdt(shm));
    // 刪除共享內存
    IF_CHECK(shmctl(shmid, IPC_RMID, NULL));
    
    return 0;    
}

運行結果是

 打印出結果了, 後面 ipcs -m 就查不出結果了.

刪特定共享內存 命令是 ipcrm -m shmid

其它就多嘗試. 共享內存本質多個進程將虛擬內存地址映射到相同的物理內存地址.

 

前言 - memcache 服務安裝使用

  到這裏咱們瞭解了共享內存基礎使用, 後面擴展一點了解memcache 緩存機制(外部內存). 有機會再研究分析它的源碼,

再來分享. 扯一點,memcache 是這個高速緩存項目的名稱, 就是這個項目, memcached表示最後啓動的服務名稱.

前言部分主要是 瞭解 memcache的安裝 和 基本協議命令. 採用 環境是 ubuntu 15. 10版本.

安裝 命令

sudo apt-get install memcached

安裝好了 採用

ps -ef | grep memcached

測試 安裝成功結果, 是啓動了 memcached 服務

後面能夠看看 memcache 命令中文手冊 , 也能夠經過 memcached -h 查看, 翻譯的中文能夠簡單參照下面.

memcached 中文手冊 http://www.jinbuguo.com/man/memcached.html

後面 咱們開始使用 memcache . 主要圍繞, 設置數據, 更新數據, 刪除數據.

一種操做方式 以下

 進入後 add set get 操做以下 示例以下

第一個 set id 0 0 5 表示 設置 key 爲 id , 第一個0表示標識爲 unsigned short . 第二個0表示沒有過時時間, 5表示 後面插入字符長度爲5.

後面 輸入 nihao 就是 set 進去的數據.

成功返回 STORED, 失敗返回 NOT_STORED.

add 和 set 類似只能在沒有待插入key 時候纔會成功, 不然都失敗.

詳細的能夠看

memcache telnet 維護  http://blog.csdn.net/love__coder/article/details/7828253

更加詳細的參看 下面

 Memcache 協議 (譯)  http://www.cnblogs.com/warriorlee/archive/2011/09/18/2180661.html

 memcache 簡易介紹筆記 http://blog.sina.com.cn/s/blog_53f716d40100hls0.html  

 Memcached通訊協議(中文版) http://www.cnblogs.com/kevintian/articles/1197681.html

具體設置命令仍是比較多, 這裏只列舉了最經常使用的用法. 更多的經驗還得本身試錯.

memcache 仍是很好用的. 到這裏memcache 基礎協議部分能夠過了. 下面會經過 其驅動正式開發.

 

正文 - C調用使用memcached服務

  memcahce 確實比較不錯, 挺好用的.  首先直接看下面例子, 到這裏仍是比較重要的. 請必定要注意仔細了, 能完整跑起來的不容易.

那開始跟着我作吧. 咱們memcached 服務器已經安裝好了, 可是少個客戶端驅動, 不然沒法調用它服務進行處理.

在Linux 上咱們採用 libmemcachde 庫.

Introducing the C Client Library for memcached  http://docs.libmemcached.org/libmemcached.html

源碼安裝下載地址  https://github.com/memcached/memcached/wiki/ReleaseNotes1425

下載下來後執行

tar –xvf libmemcached-1.0.18.tar
cd libmemcached-1.0.18

執行過程結果

進去以後結果以下

到這裏 執行下面步驟

./configure
make
sudo make install

執行上面以後 保證成功了. 可能在以前 你須要安裝 libevent-dev, sudo apt-get install libevent-dev. 安裝網絡庫.

安裝完畢以後 須要爲 其配置 lib 環境變量 (很重要, 理解爲 window上 path) 看下圖

具體命令以下

cd
vi .bashrc
Shift + G
i
# 爲 memcached 客戶端libmemcahced添加 的庫目錄
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
wq!

source .bashrc

中間命令是爲了 進去 .bashrc 文件在最後一行添加 新的 環境變量, 其中 /usr/local/lib 是本用戶安裝的庫目錄.

好了到這裏一切穩當了.  先寫個簡單的demo memheoo.c 測試一下

#include <stdio.h>
#include <stdlib.h>
#include <libmemcached/memcached.h>

/*
 * 測試 memcached 的使用
 */
int main(int argc, char* argv[]) {
    // connect server
    memcached_st* memc;
    memcached_return rc;
    memcached_server_st* mems;
    time_t expir = 0;
    uint32_t flag = 0;
    const char* res;
    const char* key = "hello";
    size_t klen = strlen(key), vlen;

    // 開始測試, 能夠不用添加檢測代碼, 這裏只爲了知道有這個api
    memc = memcached_create(NULL);
    mems = memcached_server_list_append(NULL, "127.0.0.1", 11211, &rc);
    if(!memcached_success(rc)){
        fprintf(stderr, "添加服務器列表失敗!\n");
        exit(EXIT_FAILURE);
    }
    // 這東西目前惟一資料就是libmemcached源碼
    rc = memcached_server_push(memc, mems);
    if(!memcached_success(rc)) {
        fprintf(stderr, "添加服務器列表向客戶端失敗!");
        exit(EXIT_FAILURE);
    }
    memcached_server_list_free(mems);

    // 開始設置數據
    rc = memcached_set(memc, key, klen, "world", 5 , expir, flag);
    if(rc == MEMCACHED_SUCCESS)
        printf("Set data<hello, world> => %d\n", rc);

    // 這裏獲得數據
    res = memcached_get(memc, key, klen, &vlen, &flag, &rc);
    if(rc == MEMCACHED_SUCCESS) 
        printf("get value:%s, len:%ld, flag:%d\n", res, vlen, flag);
    
    // 刪除數據
    rc = memcached_delete(memc, key, klen, expir);
    if(rc == MEMCACHED_SUCCESS)
        printf("%s 刪除成功!\n", key);
    else
        puts("刪除失敗!");
    
    // free
    memcached_free(memc);

    return 0;    
}

編譯命令 執行命令以下

gcc -g -Wall -o memheoo.out memheoo.c -lmemcachedls

./memheoo.out

最後執行結果以下

好這裏咱們基本的demo都執行完畢了. 所有都跑起來. 瞬間感受順暢了一點.

最後咱們經過 libmemcached 構建一件有意思的時間鎖.  具體以下 memlock.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libmemcached/memcached.h>

/*
 * 測試 memcached 的使用
 */
int main(int argc, char* argv[]) {
    // connect server
    memcached_st* memc;
    memcached_return rc;
    memcached_server_st* mems;
    time_t expir = 10; // 過時時間爲10s
    const char* key = "__mem_key_lock";
    size_t klen = strlen(key);

    // 建立服務器地址添加到客戶端中
    memc = memcached_create(NULL);
    mems = memcached_server_list_append(NULL, "127.0.0.1", 11211, &rc);
    rc = memcached_server_push(memc, mems);
    if(rc != MEMCACHED_SUCCESS) {
        fprintf(stderr, "添加服務器地址失敗!=>%s\n", memcached_error(memc));    
        exit(EXIT_FAILURE);
    }
    memcached_server_list_free(mems);

    // 開始經過數據加鎖
    rc = memcached_add(memc, key, klen, "0", 1, expir, 0);
    if(rc != MEMCACHED_SUCCESS) {
        printf("這裏競爭鎖失敗! MEMCACHED_NOTSTORED = %d \n", rc == MEMCACHED_NOTSTORED);
        memcached_free(memc);
        exit(EXIT_FAILURE);
    }
    
    printf("獲得鎖資源 這裏等待 : %ld s後結束\n", expir);
    // 等待 10s ,能夠用另外一個 進程測試
    sleep(expir);

    // free
    memcached_free(memc);

    return 0;    
}

看第一個會話進程開啓測試

第二會話在這期間測試

這裏經過 memcached 服務構建一個帶時效性的 lock, 是否是頗有意思.  到這裏基本上關於memcahed 或內存使用是能夠了解了.

對於高級部分擴展, 那就隨着業務的需求進行優化和擴展了. 每一項技術都是無底洞, 因業務需求而定最好.

 

後記

  到這裏基本完畢, 有問題能夠交流, 會快速改正. 拜~~

相關文章
相關標籤/搜索