引言 - 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 或内存使用是能够了解了.
对于高级部分扩展, 那就随着业务的需求进行优化和扩展了. 每一项技术都是无底洞, 因业务需求而定最好.
后记
到这里基本完毕, 有问题能够交流, 会快速改正. 拜~~