redis c、java编程api

目录
  1. redis c 编程api
  2. redis java编程api

redis c 编程api

官方推荐使用的API接口:

  • hiredis
    This is the official C client. Support for the whole command set, pipelining, event driven programming.See redis/hiredis

  • hiredis-vip
    This is the C client for redis cluster. Support for synchronous api, MSET/MGET/DEL, pipelining, asynchronous api. See vipshop/hiredis-vip

其中,hiredis-vip是基于hiredis衍生出来的,其支持hiredis的所有操作,并支持redis集群操作

api使用方法,可见github上的test.c:
hiredis/test.c
hiredis-vip/test.c

redis java编程api

官方推荐使用的API接口:

  • Jedis
  • lettuce
    Advanced Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
  • Redisson
    distributed and scalable Java data structures on top of Redis server

tips:
可以在redis官网上查看各种编程语言支持的redis API接口Clients,其中,带星号的是redis官方推荐使用的

redis实战书籍笔记

目录

性能工具:
redis-benchmark
redis-benchmark -c 1 -q

redis事务
同数据库事务的概念一样,具有ACID性质。
为了支持事务,数据库使用锁机制,redis中通过使用watch/unwatch语法来达到互斥访问的目的。
使用watch命令支持redis事务

redis非事务流水线
可以提高redis命令执行的效率,特别是在通信的双方tcp链路传输耗时的情况下尤为明显。
pipeline=conn.pipeline()
pipeline.execute()

redis锁
细粒度锁

redis信号量
当需要限制资源的使用个数时,锁机制就不适用了,这时候需要信号量。

yU#705501

使用python抓取网页

  1. 面向过程编程方式
1
2
3
4
5
6
7
8
#get_page.py
import json
from urllib import urlopen
url="https://chhy2009.github.io"
response=urlopen(url)
contents=response.read()
text=contents.decode('utf8')
print(text)
  1. 面向对象方式
1
2
3
4
5
6
7
import requests
url="https://chhy2009.github.io"
response=requests.get(url)
print(response.status_code)
print(response.apparent_encoding)
response.encoding='utf-8' #可以使用这种方式改变编码
print(response.text)

上述为get方式,另外,requests也post方式。支持get, posts, put, delete, head, options等请求类型。

  • 传递url参数
    参数如果需要传递参数的话需要使用post方式,相对安全点,使用方式如下(get方式也一样):
1
2
payload = {'key1': 'value1', 'key2': 'value2'}
response=requests.post(url, payload)
  • 超时
    get 和 post方法都是阻塞式方法,为了防止服务器不能及时响应,可以在请求中携带timeout参数,
    request库链接:Requests: 让 HTTP 服务人类

netlink详解

目录
  1. netlink机制
  2. 自定义的netlink例子
  3. 使用NETLINK_GENERIC

netlink机制

参考链接:
Communicating between the kernel and user-space in Linux using Netlink Sockets: Source code reference

内核通信之Netlink源码分析-用户内核通信原理

自定义的netlink例子

代码参考:
How to use netlink socket to communicate with a kernel module?

参考链接:
Generic Netlink详解

更多学习资料参考百度文库: Netlink详解

内核编程知识点

目录
  1. 内核编程知识点
  2. 系统调用

内核编程知识点

分享几篇内核知识点相关的文章:
Linux内核编程笔记

内核剖析,涉及的方面包括:

  • 系统调用SCI(linux/kernel)
  • 进程管理(linux/kernel)
  • 内存管理(linux/mm)
  • 虚拟文件系统VFS(linux/fs)
  • 网路堆栈(linux/net)
  • 设备驱动(linux/driver)
  • 依赖体系结构的代码(linux/arch目录)

系统调用

使用 Linux 系统调用的内核命令

各个版本的快速排序源码

目录

废话不多说,直接附上源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;
//头尾元素比较的快排一趟排序算法
template <class T>
int partition(T *array, int begin, int end )
{
T index_value = array[begin];
int i = begin;
int j = end + 1;
while(1)
{
for(++i;i < j; ++i)
{
if(array[i] > index_value)
break;
}
for(--j;j > i; --j)
{
if(array[j] < index_value)
break;
}
if(j > i)
swap(array[i], array[j]);
else
break;
}
swap(array[begin], array[j]);
return j;
}
//头尾元素比较的快排一趟排序算法,partition的另一种写法
template <class T>
int partition2(T *array, int begin, int end )
{
T index_value = array[begin];
int i = begin;
int j = end;
while(i < j)
{
while(i < j && array[j] >= index_value) //从右边找到比比较值小的
--j;
if(i < j)
array[i++] = array[j]; //将j 位的值换到前面的位置
while(i < j && array[i] < index_value) //从左边找到比比较值大的
++i;
if(i < j)
array[j--] = array[i];
}
array[i] = index_value;
return i;
}
//从前往后元素比较的快排一趟排序算法
template <class T>
int partition1(T * array, int begin, int end)
{
T index_value = array[end];
int i = begin - 1;
int j = begin;
for(;j < end; ++j)
{
if(array[j] < index_value)
{
++i;
if(i != j)
{
swap(array[j], array[i]);
}
}
}
swap(array[end], array[i + 1]);
return i + 1;
}
//递归的快排版本
template <class T>
void quick_sort(T *array, int begin, int end)
{
int pos = 0;
if(begin < end)
{
//pos = partition1<int>(array, begin, end);
pos = partition2<int>(array, begin, end);
}
else
return ;
quick_sort<T>(array, begin, pos - 1);
quick_sort<T>(array, pos + 1, end);
}
//非递归的快排版本
template<class T>
void quick_sort_non_recursion(T *array, int begin, int end)
{
stack<int> _stack;
_stack.push(begin);
_stack.push(end);
for(;!_stack.empty();)
{
int _end = _stack.top();
_stack.pop();
int _begin = _stack.top();
_stack.pop();
int pos = 0;
if(_begin < _end)
pos = partition1<int>(array, _begin, _end);
//pos = partition<int>(array, begin, end);
else
continue ;
_stack.push(pos + 1);
_stack.push(_end);
_stack.push(_begin);
_stack.push(pos - 1);
}
}
int main()
{
int array[10] = { 2 , 4, 1, 18, 5, 3, 23, 11, 5, 9};
quick_sort<int>(array, 0, 9);
//quick_sort_non_recursion<int>(array, 0, 9);
int i = 0;
for (;i < 10; ++i)
cout << array[i] << "\t";
cout << endl;
return 0;
}

比较:
按效率上来讲,头尾比较的方法比从前往后比较的算法减少了元素交换的次数,效率稍微高些;但是头尾比较的算法是不稳定的排序算法,而从前往后的算法是稳定的排序算法,且从前往后遍历的方法也适合链表一类的数据结构,适用面更广泛。

迭代版本通过栈存放快排的区间,将递归方式转换成迭代。

内核驱动模块入门

目录
  1. 驱动程序的hello world
  2. 程序及makefile
    1. 加载和卸载驱动

驱动程序的hello world

程序及makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
// 下面的是主要的内容
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static int year=2017;
int hello_init()
{
printk(KERN_WARNING "Hello kernel, it's %d!\n",year);
return 0;
}
void hello_exit()
{
printk("Bye, kernel!\n");
}
// 下面两个为关键的模块函数
module_init(hello_init);
module_exit(hello_exit);

Makefile

obj-m := hello.o

all :
    $(MAKE) -C /usr/src/kernels/2.6.32-642.13.1.el6.x86_64 M=$(PWD) modules

clean:
    $(MAKE) -C /usr/src/kernels/2.6.32-642.13.1.el6.x86_64 M=$(PWD) clean

以上为Centos 64位系统环境;正常情况下也可设置为/lib/modules/$(shell uname -r)/build或/usr/src/kernels/$(shell uname -r)。

执行make编译,可以得到驱动hello.ko

加载和卸载驱动

  • 加载模块: insmod hello.ko

  • 查看模块: lsmod |grep hello

  • 卸载模块: rmmod hello

使用dmesg可以看到内核输出了相应的打印:

Hello kernel, it’s 2017!
Bye, kernel!

说明:
代码说明:
Ubuntu12.10 内核源码外编译 linux模块–编译驱动模块的基本方法
驱动文件的makefile说明可参考:
linux驱动模块Makefile解

awk简介

目录
  1. awk程序结构
    1. awk编程
  2. awk中使用shell命令

于sed工具类似,awk是一种优秀的行文本处理工具。其具有内置的变量和函数,可以进行正则表达式的匹配,流程控制,数学运算。事实上,可以说awk是一种编程语言。

awk程序结构

任何awk语句都由模式(pattern)及动作(action)组成。其中模式是一组用于测试输入行是否需要执行动作的规则,动作则是找到匹配内容后的执行动作(包含语句、函数和表达式的执行过程)。调用方式
awk [-F field-separator] ‘pattern{action}’ filename
其中,pattern和action都可以省略不写。无pattern默认匹配全部的记录;而无action则是打印原始记录。简单的AWK表达式之外,pattern可以是BEGIN或END;这两种条件对应的action分别是读取所有的记录之前和之后。 filename可以用|输入替代。

几个概念

  1. BEGIN 及 END 语句
    awk定义了两个特殊字段BEGIN和END,分别在程序开始前和结束前执行,相当于类的构造及析构函数。
    awk的执行过程: 执行BEGIN语句,然后按行处理输入文本,最后执行END语句。
  2. 记录和域
    awk 认为纪录是结构化的,awk将输入文件按行处理,行中每个字符串定义为域,域中用分隔符分隔(通常以空格或, :等分隔),如:
1
2
lrwxr-xr-x 1 root wheel 8 Jun 26 2016 bin
lrwxr-xr-x 1 root wheel 8 Jun 26 2016 include

上面的输入有2行,每行有9个域
域在awk中用$N表示,其中N=1、2…, $0表示整条纪录

awk编程

  • awk 内置变量
    AWK的内建变量包括域变量,例如$1, $2, $3,以及$0。这些变量给出了记录中域的内容。 内建变量也包括一些其他变量:
1
2
3
4
5
6
7
8
- NR:已输入记录的条数。
- NF:当前记录中域的个数。记录中最后一个域可以以$NF的方式引用。
- FILENAME:当前输入文件的文件名。
- FS:“域分隔符”,用于将输入记录分割成域。其默认值为“空白字符”,即空格和制表符。FS可以替换为其它字符,从而改变域分隔符。
- RS:当前的“记录分隔符”。默认状态下,输入的每行都被作为一个记录,因此默认记录分隔符是换行符。
- OFS:“输出域分隔符”,即分隔print命令的参数的符号。其默认值为空格。
- ORS:“输出记录分隔符”,即每个print命令之间的符号。其默认值为换行符。
- OFMT:“输出数字格式”(Format for numeric output),其默认值为"%.6g"
  • 函数
    awk内置和很多函数,当然也可以自定义函数,示例如下:
1
2
3
4
5
6
awk '
function add_three (number) {
return number + 3
}
BEGIN {result=add_three(1); print result}
'

上面的例子输出4.

  • awk脚本
    可以使用awk脚本的方式来执行awk命令,awk脚本模版如下,与命令行方式类似:
1
2
3
4
#! /bin/awk -f
BEGIN{}
{}
END{}
  • 匹配
    可以使用
1
awk 'BEGIN {FS=","} {if($1~/xxx/) print $2 >>data.txt}' filename

来提取匹配的域,其中xxx为匹配的正则表达式

  • 格式化
    可以使用printf来代替print,输出格式化的文本。格式符和c语言类似,常用的为%d,%s,

  • 循环及条件语句
    awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。

条件语句为if/else,与C语言也相同

awk中使用shell命令

  1. 通过getline函数,获取命令执行结果

通过在awk内使用管道,可以把shell命令的输出传送给awk

1
2
$ awk 'BEGIN{ "date" | getline date; print date; }'
Sat Jul 8 22:04:20 HKT 2017

如果不使用管道,则getline默认从标准输入读取输入字符,这时不能当命令执行;
可以使用<,让getline从文件中读取内容

  1. 使用awk内置system函数
1
awk 'BEGIN{system("ls -l")}'

执行结果如下:

1
2
3
4
5
6
total 16
lrwxr-xr-x 1 root wheel 8 Jun 26 2016 X11 -> /opt/X11
lrwxr-xr-x 1 root wheel 8 Jun 26 2016 X11R6 -> /opt/X11
drwxr-xr-x 3 root wheel 102 Feb 27 2016 adic
drwxr-xr-x 1055 root wheel 35870 Jun 19 2016 bin
...

搭配getline使用,则为:

1
awk 'BEGIN{while(system("ls -l") | getline line) {print line}}'

  1. 使用awk print出要执行的命令,然后交给/bin/bash处理
1
awk 'BEGIN{print "ls -l"|"bash"}'

以下是一篇比较好的文章,可供参考:
linux awk命令详解
awk官方文档

注意:
可以将awk命令写在文件中,然后用awk -f awk-script-file filename 方式执行,其中脚本中的#!/bin/sh改为#!/bin/awk
当变量不从管道输入awk时,awk无法引用已经定义的变量

虚函数表

目录

说到c++的运行时多态机制,就不能不提继承和virtual关键字,继承和virtual关键字使子类能够重载父类的方法,实现运行时多态。
运行时多态的背后机制就是虚函数表,下面进行简单的介绍:

  1. 当一个类中的方法使用了virtual时,该类的对象就会额外多出一个虚函数表地址指针(该指针指向虚函数表,因此含有虚函数的对象会额外多出一个sizeof(指针)的空间)。
  2. 虚函数表入口地址位于对象的起始地址处。
  3. 虚函数表中存放了类的各个虚函数,虽然类一样,但是每个对象都保存了指向虚函数表地址的指针。

下面看下代码 test.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <thread>
using namespace std;
class Empty{
};
class Base{
public:
virtual void func1() { cout << "Base func1" << endl;}
virtual void func2() { cout << "Base func2" << endl;}
};
int main()
{
cout << "sizeof(Empty) = " << sizeof(Empty) << endl;
cout << "sizeof(Base) = " << sizeof(Base) << endl;
typedef void(*Func)();
Base object;
cout << "address of vtable = " << (long *)*(long*)(&object) << endl; //虚函数表位于对象起始地址处
Func func1 = (Func)*(long *)*(long*)(&object); //虚函数表地址的第一个地址
cout << "address of first virtual function = " << &func1 << endl; //虚函数表位于对象起始地址处
func1();
Func func2 = (Func)*((long *)*(long*)(&object) + 1); //虚函数地址偏移一位——long *指针的大小,32位系统为4字节,64位系统为8字节
cout << "address of second virtual function = " << &func2 << endl; //虚函数表位于对象起始地址处
func2();
return 0;
}

编译:g++ test.cpp 然后./a.out运行之,结果如下:

1
2
3
4
5
6
7
sizeof(Empty) = 1
sizeof(Base) = 8
address of vtable = 0x1068f70d8
address of first virtual function = 0x7fff5930aa58
Base func1
address of second virtual function = 0x7fff5930aa50
Base func2

引申:
c++中的重载分为静态重载,即在编译期决定了使用的函数原型,这种重载一般通过函数参数的差异(可以是参数的个数或者参数类型)来实现,如:

1
2
int add(int a, int b);
double add(double a, double b);
本站总访问量