豌豆

没有荚

1 install

1
yum install openvpn

2 config

在 /etc/openvpn 下建立目录,如 config/,用于存放配置文件,将服务器生成的证书、配置文件等放入其中。

3 run

1
openvpn --cd /etc/openvpn/config --config  client_a.open
  • –cd 配置文件所在的目录,openvpn命令会先进入到此目录

  • –config 配置文件名称

1 可调用对象

在 C++ 中,可调用对象一般是指:

  • 一个函数指针

  • 一个重载 () 操作符的类对句(仿函数)

  • 一个可被转换为函数指针的类对象

  • 一个类成员函数指针

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
#include <iostream>

void func(void)
{
std::cout<<"func(void) called"<<std::endl;
}

struct Foo
{
void operator()(void)
{
std::cout<<"Foo::()(void) called"<<std::endl;
}
};

struct Bar
{
using ft_t = void(*)(void);
static void func(void)
{
std::cout<<"Bar::func(void) called"<<std::endl;
}

operator ft_t(void)
{
return func;
}
};

struct A
{
int m_a;
void mem_func(void)
{
std::cout<<"A:memfunc(void) called and m_a="<<m_a<<std::endl;
}
};

int main() {
//1.函数指针
void(* func_ptr)(void) = &func;
func_ptr();

//2.仿函数
Foo foo;
foo();

//3.可被转换为函数指针的类对象
Bar bar;
bar();

//4.类成员函数指针或类成员指针
void (A::*mem_func_ptr)(void) = &A::mem_func;
int A::*mem_obj_ptr = &A::m_a;
A aa;
(aa.*mem_obj_ptr) = 123;
(aa.*mem_func_ptr)();

return 0;
}

上例中的这些对象(func_ptr,foo,bar,mem_func_ptr,mem_obj_ptr) 均可称之为 “可调用对象”。相应的,其类型可被称作“可调用类型”。注意这里只有成员函数有成员函数指针而没有函数类型或函数引用类型,这是因为函数类型并不能直接用于定义对象,而函数引用或以看做一个 const 的函数指针。 可调用对象具有比较统一的调用形式,即使用括号操作(除成员函数指针),而定义的方法各不一样。这样我们在试图使用统一的方式保存,或传递一个可调用对象时,会十分烦琐。

2 std::function 可调用对象包装器

std::function 是一个类模板,它可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟调用它们。

Read more »

1 概述

python-docx-example-docx-01

python 为脚本自动化操作 Word 提供了可能。最为常用是 python-docx .使用它可以方便地创建或更新 Microfoft Word(.docx) files.

下图是其官网给出的一个使用 python-docx 创建的 word 文档的 Demo:

文档地址:http://python-docx.readthedocs.io/en/latest/index.html

github: https://github.com/python-openxml/python-docx
这是官网给出的代码:

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
from docx import Document
from docx.shared import Inches

document = Document()

document.add_heading('Document Title', 0)

p = document.add_paragraph('A plain paragraph having some ')
p.add_run('bold').bold = True
p.add_run(' and some ')
p.add_run('italic.').italic = True

document.add_heading('Heading, level 1', level=1)
document.add_paragraph('Intense quote', style='IntenseQuote')

document.add_paragraph(
'first item in unordered list', style='ListBullet'
)
document.add_paragraph(
'first item in ordered list', style='ListNumber'
)

document.add_picture('monty-truth.png', width=Inches(1.25))

table = document.add_table(rows=1, cols=3)
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Qty'
hdr_cells[1].text = 'Id'
hdr_cells[2].text = 'Desc'
for item in recordset:
row_cells = table.add_row().cells
row_cells[0].text = str(item.qty)
row_cells[1].text = str(item.id)
row_cells[2].text = item.desc

document.add_page_break()

document.save('demo.docx')

2 安装 python-docx

可以使用 pip 或 easy_install 来进行安装

1
2
3
4
5
pip install python-docx



easy_install python-docx

也可以直接下载安装文件来进行安装:

1
2
3
tar xvzf python-docx-{version}.tar.gz
cd python-docx-{version}
python setup.py install

要求Python 版本在2.6 以上或 3.3 以上,lxml 版本在 2.3.2及以上。 在 Windows 10 / Python 2.7 环境下安装时出现 lxml3.7.2 安装失败的问题,可降低版本进行尝试:

1
pip install lxml==3.4.2

3 快速上手

3.1 打开文档

1
2
from docx import Document
document = Document()

新建一个空的 word 文档。当然,也可以打开一个已存在的 word 文档,只要传入相应的路径就好。

3.2 添加段落

Read more »

1 应该提供 API 版本号信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//version.h
#include <string>
#define API_MAJOR 1
#define API_MINOR 2
#define API_PATCH 0

class version
{
public:
static int GetMajor();
static int GetMinor();
static int GetPatch();
static std::string GetVersion();
static bool IsAtLeast(int major,int minor,int patch);
static bool HasFeature(const std::string& name);
}

这个类提供了单独返回当前版本号的主、次、补丁版本号的的访问函数。它们返回各 define 定义的值。GetVersion 方法向用户返回友好的字符串版本号信息。 当用户相比较版本号时,他们通常不关心版本号本身,而是想知道某些特性在该版本的API中是否存在。HasFeature() 方法 不是告诉用户哪个版本的 API 引入了哪些特性,而是让亿们直接测试某个特性是否可用。

2 软件分支策略

一般的大型项目通常会涉及到某种形式的分支策略,这需要同步开发、维护不同的软件版本发布。我们将讨论为项目选择分支策略和方针时需要考虑的一些事项。

2.1 分支策略

每个软件都需要一条 trunk (主干)代码路线,它是

cppAPIversion

软件项目源码
的持久库。对于对于每次版本的发布
,可以从主干进行。每次新版本的开发,可以从主干的代码添加分支,而使主干的代码不受开发的影响而保持稳定。右图是一种常见的分支策略。

2.2 API与并行分支

在API发布以后,对其所有的更改都应该表现为一个连续的过程,即不发布不兼容的非线性版本的API,一个版本的API应该是前一个版本功能的严格超集。在大型项目中,通常会有几条并行的代码分支在进行同时开发,这就会产生若干个并行维护的API版本。因此,工作在不同并行分支上的团队互不引入不兼容的特性是非常重要的。下列方法可以帮忙处理这种潜在的问题:

Read more »

在c++11以前,我们获取当前时间的时间戳,需要借助于第三方库,如 boost ,或者针对不同的操作做不同的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef _MSC_VER
#include <sys/time.h>
#endif

long long GetTimeSpan()
{
long long llTimeMs = 0L;
#ifdef _MSC_VER
timeb tb;
ftime(&tb);

lTimeMs = tb.time * 1000 + tb.millitm;

#else
timeval tmv;
gettimeofday(&tmv,NULL);

llTimeMs = (long long)(tmv.tv_sec) * 1000L + tmv.tv_usec / 1000;

#endif
return llTimeMs;
}

而在c++11中,这个问题得到解决。 c++11 标准库中提供 chrono库,用来处理时间相关的数据。

1 duration 记录时长

duration 表示一段时间间隔。其原型:

1
2
template <class _Rep, class _Period>
class duration;

_Rep 为一个数值类型,如 int, long, 用来表示时钟数的类型。 _Period 为一个默认的模板参数 std::ratio,表示时钟周期。 ratio的原型:

1
2
template <intmax_t _Num, intmax_t _Den = 1>
class ratio

它表示一个时钟周期的秒数。_Num 代表分子,_Den代表分母,它们的比值就是一个时钟周期,可以通过调整分子与分母来表示任意一个时钟周期。如 ratio<1> 表示一个时钟周期为1秒,ratio<3600>表示一个时钟周期为1小时,ratio<1,1000>表示一个时钟周期为1毫秒,ratio<1,2>表示一个时钟周期为0.2秒,ratio<9/7>表示一个时钟周期为9/7秒。 标准库将一些常用的时钟周期做了定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef ratio<1LL, 1000000000000000000LL> atto;
typedef ratio<1LL, 1000000000000000LL> femto;
typedef ratio<1LL, 1000000000000LL> pico;
typedef ratio<1LL, 1000000000LL> nano;
typedef ratio<1LL, 1000000LL> micro;
typedef ratio<1LL, 1000LL> milli;
typedef ratio<1LL, 100LL> centi;
typedef ratio<1LL, 10LL> deci;
typedef ratio< 10LL, 1LL> deca;
typedef ratio< 100LL, 1LL> hecto;
typedef ratio< 1000LL, 1LL> kilo;
typedef ratio< 1000000LL, 1LL> mega;
typedef ratio< 1000000000LL, 1LL> giga;
typedef ratio< 1000000000000LL, 1LL> tera;
typedef ratio< 1000000000000000LL, 1LL> peta;
typedef ratio<1000000000000000000LL, 1LL> exa;

typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long > seconds;
typedef duration< long, ratio< 60> > minutes;
typedef duration< long, ratio<3600> > hours;

在不同的时钟周期中,我们可以使用 chrono_cast 来进行转换。两个 duration还可以进行加减运算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <chrono>
#include <iostream>
using namespace std;

int main(int argc, const char * argv[]) {

chrono::hours hrs(2); //两小时
cout<<hrs.count()<<" hours = "; //count() 函数获取时钟周期下的时钟数
chrono::minutes mns = chrono::duration_cast<chrono::minutes>(hrs); //120分钟
cout<<mns.count()<<" minutes"<<endl;

chrono::minutes tm = hrs - chrono::minutes(30); //时长的加减运算
cout<<hrs.count()<<" hours - 30 minutes = " <<tm.count()<<" minutes = ";

typedef chrono::duration<double,ratio<3600,1>> hs; //时长的类型转换。注意 duration 的 _Rep 参数类型。
hs c = chrono::duration_cast<hs>(tm);
cout<<c.count()<<" hours"<<endl;

return 0;
}

//# 输出 #:
// 2 hours = 120 minutes
// 2 hours - 30 minutes = 90 minutes = 1.5 hours
Read more »

在C++ 中,遍历一个容器的方法一般是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <vector>
int main(void)
{
std::vector<int> vec;
//do sth
std::vector<int>::iterator it = vec.begin();
for(; it != vec.end(); ++it)
{
std::cout<< *it <<std::endl;
}
return 0;
}

对STL比较熟悉的程序员肯定还知道在 中有一个 for_each 算法,可以用来完成上述功能:

1
2
3
4
5
6
7
int main(void)
{
std::vector<int> vec;
//do sth
std::for_each(vec.begin(), vec.end(), [](auto val){std::cout<<val<<std::endl;});
return 0;
}

这里借助了 auto 关键字和 lambda 表达式简化了操作。 std::for_each 比起前面 for 循环,最大的好处是不再需要关注迭代器的概念,而只需要关心容器中的元素类型即可。 但这两种方法,都必须显式的给出容器有开头和结尾(begin,end).这是因为上面的两种方法都不是基于范围(range)来设计的. 范围的概念在很多高级语言中都有涉及。例如下面这段 python 代码:

1
2
3
arr = [1,2,3,4,5]
for n in arr:
print n

在这种循环中,不再需要关心容器的两端,循环会自动以容器的范围进行展开。而且这种语法可以清楚地表明它的意义。使用这种方式进行循环无疑会使编码和维护更加简便。 现在,c++11 可有了基于范围的 for 循环

Read more »

1 创建类

使用 class 关键字来创建一个类。

1
2
3
class ClassName:
'类的注释'
class_suite #类体

类的注释可由 ClassName.doc 来查看。class_suite 由类的成员、方法、属性组成

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#-*- coding:utf-8 -*-
class Student:
'学生'
def __init__(self, name,sex,num):
self.name = name
self.sex = sex
self.num = num

def displayInfo(self):
print "Name:",self.name,",Sex:",self.sex,",Num:",self.num

def __del__(sefl):
class_name = self.__class__.__name__
print class_name,'Deleted'
  • init() 可以看作是类的构造函数。(其实类的构造函数是 new ,它是一个类方法 ,在类的实例初始化之前调用。init 实际是类的初始化函数)

  • self 代表类的实例,类的方法必须有一个额外的形参,按惯例它的名称为self,但在调用时不必传入该参数。

  • del() 是类的析构函数,在对象被销毁的时候调用。

2 类的实例

要创建一个类的实例,可以调用该一特殊的函数来完成。该函数的名称为类的名称,参数为该类的 init()的参数。

1
2
3
4
5
6
7
8
9
10
>>> from Student import Student
>>> s = Student('A',1,1)
>>> s.displayInfo()
Name: A ,Sex: 1 ,Num: 1
>>> print s.name #属性
A
>>> print s.__doc__
学生
>>> print Student.__doc__
学生

还可以使用下列函数来访问属性:

  • getattr(obj,name[,default]) 访问对象的属性

  • hasattr(obj,name) 检查是否存在一个属性

  • setattr(obj,name,value) 设置一个改改。如果不存在,则创建之

  • delattr(obj,name) 删除一个属性

Read more »

数据类型

cpplogo

1.long long

long long 数据类型,提供至少 64 位的整型数据。

2.nullptr

C++11 推荐使用 nullptr 表示空指针,不再推荐使用 NULL 或 0 表示空指针。 NULL为从 C 语言中引进的,在 C 语言中一般被定义为宏:

1
2
3
4
5
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif

在 C 语言中,可以将 void* 隐式转换为任意指针类型,而在 C++ 中,可以为任意类型的指针赋 0 值。所以 c++ 将 NULL 定义为 0. nullptr 是指针类型(nullptr_t),该类型的对象不允许转换到非指针类型。

3.contexpr

1).const expression 常量表达式

是指值不会改变且在编译过程中就能得到计算结果的表达式。字面量属于常量表达式,使用常量表达式初始化的 const 对象也是常量表达式。一个对象或表达式是不是常量表达式要由它的数据类型和初始值共同决定:

1
2
3
4
const int max = 1024;    // max 是常量表达式
const int min = max - 1000; // min 是常量表达式
int nsize = 64; // nsize 不是常量表达式
const int sz = nsize + 1; // nsize 不是常量表达式

尽管 size 变量的初始化值是字面常量 ,但是它的定义数据类型是 int 而不是 const int 。 尽管 sz 定义为 const int ,但其值需要运行时才能得到,所以它也不是常量表达式。

2).constexpr 变量

C++11 中,允许将变量声明为 constexpr 类型,以便由编译器检查变量是否为一个常量表达式:声明为 constexpr 的变量一定是一个常量 ,且必须使用常量表达式初始化:

1
2
3
constexpr int max = 1024;    //是常量表达式
constexpr int min = max - 1000; //是常量表达式
constexpr int sz = get_size(); //只有当 get_size() 是常量表达式时,定义才是常量表达式

3).constexpr 函数

constexpr 可用于指示函数是一个常量表达式。这需要满足:

  • 返回值类型是字面值类型

  • 形参类型是字面值类型

  • 函数体中必须有且仅有一条 return 语句

4).constexpr 与 const

1
2
const int* p = nullptr;    //p 是一个指向整型常量的指针
constexpr int* q = nullptr; //q 是一个指向整型的常量指针

这里的 p 和 q 本质是不一样的。指针 p 指向的整数是常量,而指针 q 本身是常量,其指向的整数则可以不是常量:

1
2
3
4
*p = 5;         //错误 ,p 指向的整数是一个常量,即 *p 是不可修改的
p = new int(0); //正确 , p 是可以修改的
*q = 5; //正确 , q 指向的整数的值是可以修改的
q = new int(0); //错误 , q 是一个常量表达式,不可修改

其中的关键在于constexpr把它所定义的对象置为了顶层const.

4.noexcept

noexcept 指示一个函数不会抛出异常。如果一个使用 noexcept 修饰的函数内部抛出了异常,编译器并不会报错,但

Read more »

[

](https://code.wandoer.com/wp-content/uploads/2016/11/http.jpg)概述

HTTP(HyperText Transfer Protocal)超文本传输协议, 是一个基于请求与响应模式的、无状态的应用层协议。它是 WEB 上应用最广泛的协议。它一般基于 TCP 的连接方式。其主要特点有:

  • 支持 C/S 通信模式

  • 简单快速。HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信快。

  • 灵活。HTTP 协议允许客户端和服务端传输任意类型任意格式的数据。不同的类型由 Content-Tyoe 标记

  • 面向无连接。无连接是指每次建立的连接只处理一个文请求。

  • 无状态。无状态是指协议对于事务处理没有记忆能力。如果后续处理需要前面的信息,则它必须重传。这样可有导致每次连接传送的数据量增大。

HTTP URL

URL(Uniform Resource Locator) 统一资源定位符,它包含了查找某个资源的信息。其格式如下:

1
http://host[:port][abs_path]

http 指定协议的名称,表示要通过 HTTP 协议来定位网络资源。 host 是一个合法的网络域名 或 IP 地址。 port 指定使用的网络端口,缺省值为 80 。 abs_path 指定请求的资源的 URI .如果 URL 中没有给出 URI, 则必须以 “/” 符号结束(这个工作通常由浏览器完成)。

连接

浏览器与服务器联系的最常用方法是与服务器的 80 端口建立 TCP 连接。使用 TCP 的意义在于,浏览器和服务器都不需要担心如何处理长消息、可靠性与拥塞控制,这些事将由 TCP 来处理。 在早期的 HTTP1.0 中,连接建立起来后会在一个请求和一个响应后立即释放。因为那时的 HTML 很简单,基本只有文本,使用这种模式就够了。但是随着时代的发展,HTML里包含了太多的东西,使用单独的 TCP 来传递每个资源代价太大。于是 HTTP1.1诞生了,它支持持续连接(persistent connection),它可以在一个 TCP 连接上进行多次请求响应,还可以发送流水线请求。这种做法减少建立多个 TCP 连接所用的时间,减少服务器的空闲时间,提高了性能。

HTTP 协议的请求

每个 HTTP Request (请求) 由一行或多行 ASCII 文本组成。其中第一行的第一个词为请求方法的名称,然后是请求资源的 URI,再后是协议的版本。这几个部分使用空格分开:

1
Method Request-URI  HTTP-Version CRLF

Method 为请求方法,必须为大写。 Request-URI 是一个统一资源标识符。 HTTP-Version 表示请求的 HTTP 协议版本。 CRLF 表示换行符。 例如:

1
GET about.html  HTTP/1.1

常用的请求方法如下:

Read more »
0%