前言

我是一个 linux c++ 开发者,但是一直对 Makefile 的语法很是头痛,每次都记不住,所以每次写 Makefile 都很痛苦,Makefile 里需要你自己编写依赖和推导规则,这个过程能不能简单点呢?

对于编译一个 C++ 工程来说,也许需要的就是头文件路径、库路径、编译参数,剩下的东西基本也不重要,这三样足够去编译一个工程了。所以有没有一个工具能简单点的去实现 C++ 项目的构建呢?

答案是有的,Scons 就是答案。

Scons

什么是 scons

这里直接引用官网的解释:

What is SCons?

SCons is an Open Source software construction tool—that is, a next-generation build tool. Think of SCons as an improved, cross-platform substitute for the classic Make utility with integrated functionality similar to autoconf/automake and compiler caches such as ccache. In short, SCons is an easier, more reliable and faster way to build software.

What makes SCons better?

  • Configuration files are Python scripts–use the power of a real programming language to solve build problems.
  • Reliable, automatic dependency analysis built-in for C, C++ and Fortran–no more “make depend” or “make clean” to get all of the dependencies. Dependency analysis is easily extensible through user-defined dependency Scanners for other languages or file types.
  • Built-in support for C, C++, D, Java, Fortran, Yacc, Lex, Qt and SWIG, and building TeX and LaTeX documents. Easily extensible through user-defined Builders for other languages or file types.
  • Building from central repositories of source code and/or pre-built targets.
  • Built-in support for fetching source files from SCCS, RCS, CVS, BitKeeper and Perforce.
  • Built-in support for Microsoft Visual Studio .NET and past Visual Studio versions, including generation of .dsp, .dsw, .sln and .vcproj files.
  • Reliable detection of build changes using MD5 signatures; optional, configurable support for traditional timestamps.
  • Improved support for parallel builds–like make -j but keeps N jobs running simultaneously regardless of directory hierarchy.
  • Integrated Autoconf-like support for finding #include files, libraries, functions and typedefs.
  • Global view of all dependencies–no more multiple build passes or reordering targets to build everything.
  • Ability to share built files in a cache to speed up multiple builds–like ccache but for any type of target file, not just C/C++ compilation.
  • Designed from the ground up for cross-platform builds, and known to work on Linux, other POSIX systems (including AIX, BSD systems, HP/UX, IRIX and Solaris), Windows NT, Mac OS X, and OS/2.

最大特点就是使用 Python 语法来编写编译构建脚本,并且支持依赖自动推导,支持编译 C/C++/D/Java/Fortran等项目,并且是跨平台的(因为 python 是跨平台的)。

阅读全文 »

aliyun_spot

自动创建阿里云抢占式实例。

支持一下作者,购买阿里云

背景

阿里云抢占式实例应该属于阿里云的一种闲置资源利用,性价比非常高,每小时的价格在 0.01 ~ 0.05 每小时,具体根据不同的配置和地域有差别,流量价格小于 1元/G.

抢占式实例最高可以以一折的价格购买 ECS 实例,并能稳定持有该实例至少一个小时。一个小时后,当市场价格高于您的出价或资源供需关系变化时,抢占式实例会被自动释放,请做好数据备份工作。

非常适合爬虫

非常适合爬虫

非常适合爬虫

也适合程序员个人日常开发使用,上班来创建,下班释放,开销基本可以控制在在 1毛 ~ 2 毛。

对于我来说,最近在写一个爬虫,看了很多代理都很贵,免费的又不稳定,正好了解到阿里云的抢占式实例,所以非常满足我的需求。

但是要注意,这个实例是有可能被释放的,但是不用担心,比如香港地区的释放率最近(2020-08-19)小于 3%. 另外,每个人可以最大创建 100 个实例,所以还是不用太担心。

阅读全文 »

Valgrind Massif

valgrind 是什么,这里直接引用其他人的博客:

Valgrind是一套Linux下,开放源代码(GPL
V2)的仿真调试工具的集合。Valgrind由内核(core)以及基于内核的其他调试工具组成。

内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。

Valgrind的体系结构如下图所示:

Massif 命令行选项

关于 massif 命令行选项,可以直接查看 valgrind 的 help 信息:

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

MASSIF OPTIONS
--heap=<yes|no> [default: yes]
Specifies whether heap profiling should be done.

--heap-admin=<size> [default: 8]
If heap profiling is enabled, gives the number of administrative bytes per block to use. This should be an estimate of the average, since it may vary. For example, the
allocator used by glibc on Linux requires somewhere between 4 to 15 bytes per block, depending on various factors. That allocator also requires admin space for freed blocks,
but Massif cannot account for this.

--stacks=<yes|no> [default: no]
Specifies whether stack profiling should be done. This option slows Massif down greatly, and so is off by default. Note that Massif assumes that the main stack has size zero
at start-up. This is not true, but doing otherwise accurately is difficult. Furthermore, starting at zero better indicates the size of the part of the main stack that a user
program actually has control over.

--pages-as-heap=<yes|no> [default: no]
Tells Massif to profile memory at the page level rather than at the malloc'd block level. See above for details.

--depth=<number> [default: 30]
Maximum depth of the allocation trees recorded for detailed snapshots. Increasing it will make Massif run somewhat more slowly, use more memory, and produce bigger output
files.

--alloc-fn=<name>
Functions specified with this option will be treated as though they were a heap allocation function such as malloc. This is useful for functions that are wrappers to malloc or
new, which can fill up the allocation trees with uninteresting information. This option can be specified multiple times on the command line, to name multiple functions.

Note that the named function will only be treated this way if it is the top entry in a stack trace, or just below another function treated this way. For example, if you have a
function malloc1 that wraps malloc, and malloc2 that wraps malloc1, just specifying --alloc-fn=malloc2 will have no effect. You need to specify --alloc-fn=malloc1 as well.
This is a little inconvenient, but the reason is that checking for allocation functions is slow, and it saves a lot of time if Massif can stop looking through the stack trace
entries as soon as it finds one that doesn't match rather than having to continue through all the entries.

Note that C++ names are demangled. Note also that overloaded C++ names must be written in full. Single quotes may be necessary to prevent the shell from breaking them up. For
example:

--alloc-fn='operator new(unsigned, std::nothrow_t const&)'

--ignore-fn=<name>
Any direct heap allocation (i.e. a call to malloc, new, etc, or a call to a function named by an --alloc-fn option) that occurs in a function specified by this option will be
ignored. This is mostly useful for testing purposes. This option can be specified multiple times on the command line, to name multiple functions.

Any realloc of an ignored block will also be ignored, even if the realloc call does not occur in an ignored function. This avoids the possibility of negative heap sizes if
ignored blocks are shrunk with realloc.

The rules for writing C++ function names are the same as for --alloc-fn above.

--threshold=<m.n> [default: 1.0]
The significance threshold for heap allocations, as a percentage of total memory size. Allocation tree entries that account for less than this will be aggregated. Note that
this should be specified in tandem with ms_print's option of the same name.

--peak-inaccuracy=<m.n> [default: 1.0]
Massif does not necessarily record the actual global memory allocation peak; by default it records a peak only when the global memory allocation size exceeds the previous peak
by at least 1.0%. This is because there can be many local allocation peaks along the way, and doing a detailed snapshot for every one would be expensive and wasteful, as all
but one of them will be later discarded. This inaccuracy can be changed (even to 0.0%) via this option, but Massif will run drastically slower as the number approaches zero.

--time-unit=<i|ms|B> [default: i]
The time unit used for the profiling. There are three possibilities: instructions executed (i), which is good for most cases; real (wallclock) time (ms, i.e. milliseconds),
which is sometimes useful; and bytes allocated/deallocated on the heap and/or stack (B), which is useful for very short-run programs, and for testing purposes, because it is
the most reproducible across different machines.

--detailed-freq=<n> [default: 10]
Frequency of detailed snapshots. With --detailed-freq=1, every snapshot is detailed.

--max-snapshots=<n> [default: 100]
The maximum number of snapshots recorded. If set to N, for all programs except very short-running ones, the final number of snapshots will be between N/2 and N.

--massif-out-file=<file> [default: massif.out.%p]
Write the profile data to file rather than to the default output file, massif.out.<pid>. The %p and %q format specifiers can be used to embed the process ID and/or the
contents of an environment variable in the name, as is the case for the core option --log-file.

对其中几个常用的选项做一个说明:

阅读全文 »

写在前面的话

自比特币诞生到现在,比特币(网络)经历过大大小小非常多次的攻击,尤其在比特币诞生之初的几年,并且随着比特币价格的一路飙涨,黑客针对比特币网络的攻击就一直没有停止过。据估算,目前大约有 350 ~ 400 万比特币永久丢失,价值大约 240 ~ 280 亿美元。当然其中不只有由于黑客的攻击导致的丢失,毕竟比特币最初的几年很多人都没有意识到比特币的价值,很多的私钥都遗失了。

本文就谈一下目前几种区块链网络攻击,以及其防御方案。

本文尽量用简单易懂的白话来描述,也仅代表我个人的看法,欢迎探讨

同系列:

异形攻击

异形攻击又称地址污染攻击,是指诱使同类链的节点之间互相发现、互联、侵入的一种攻击手法。同类链的意思是底层 P2P 网络使用了相同或者相似的 P2P 通信协议。这尤其针对比特币和以太坊系列的公链。

众所周知,最近几年区块链行业蓬勃发展,又过于浮躁。其中很多劣质公链大量 COPY 以太坊、比特币的源码,甚至不做修改,仅仅修改下名字成为一条新的公链,这就导致大量的公链的底层是相同的或者兼容的。

那么如果攻击者执行了异形攻击,就有可能导致同类链的节点之间互相缠绕在一起,影响公链节点内部的通信和路由,进而影响到交易、共识和安全。从而让攻击者有机会施行其他的攻击,比如 DDoS 攻击,网络分裂攻击。

本质上还是由于伸手党的存在,并且不加以修饰和对节点的检测造成了异形攻击。应对办法也很简单,首先是拒绝做伸手党,即便伸手党,起码也要研究下别人的代码,做点创新和原创的东西;其次加强对本公链的节点类型的检测,比如节点地址不符合的一切拒绝,通信协议不一致的一切拒绝,通信报文头特殊字段不一致的一切拒绝等等。

配图与本文无关
阅读全文 »

写在前面的话

自比特币诞生到现在,比特币(网络)经历过大大小小非常多次的攻击,尤其在比特币诞生之初的几年,并且随着比特币价格的一路飙涨,黑客针对比特币网络的攻击就一直没有停止过。据估算,目前大约有 350 ~ 400 万比特币永久丢失,价值大约 240 ~ 280 亿美元。当然其中不只有由于黑客的攻击导致的丢失,毕竟比特币最初的几年很多人都没有意识到比特币的价值,很多的私钥都遗失了。

本文就谈一下目前几种区块链网络攻击,以及其防御方案。

本文尽量用简单易懂的白话来描述,也仅代表我个人的看法,欢迎探讨

同系列:

拒绝服务攻击(Denial of Service Attack)

分布式拒绝服务攻击(Distributed Denial of Service Attack)

概念

信息安全的三要素——“保密性”、“完整性”和“可用性”中,拒绝服务攻击,针对的目标正是“可用性”。该攻击方式利用目标系统网络服务功能缺陷或者直接消耗其系统资源,使得该目标系统无法提供正常的服务。

拒绝服务攻击(DoS) 问题一直得不到合理的解决,目前还是世界性难题,究其原因是因为这是由于网络协议本身的安全缺陷造成的,从而拒绝服务攻击也成为了攻击者的终极手法。攻击者进行拒绝服务攻击,实际上让服务器实现两种效果:一是迫使服务器的缓冲区满,不接收新的请求;二是使用IP欺骗,迫使服务器把合法用户的连接复位,影响合法用户的连接。

而分布式拒绝服务攻击 (DDoS) 是指攻击者采用分布式攻击手法施行 DoS 攻击,通常是控制了多台机器向目标主机或者路由器发起 DoS 攻击。

针对区块链来说,攻击者通过 DDoS 攻击试图减慢网络速度,或者迫使网络停止运作。也可用于针对矿池,使矿池脱机,或者针对特定的目标主机,使其从网络离线。

阅读全文 »

写在前面的话

自比特币诞生到现在,比特币(网络)经历过大大小小非常多次的攻击,尤其在比特币诞生之初的几年,并且随着比特币价格的一路飙涨,黑客针对比特币网络的攻击就一直没有停止过。据估算,目前大约有 350 ~ 400 万比特币永久丢失,价值大约 240 ~ 280 亿美元。当然其中不只有由于黑客的攻击导致的丢失,毕竟比特币最初的几年很多人都没有意识到比特币的价值,很多的私钥都遗失了。

本文就谈一下目前几种区块链网络攻击,以及其防御方案。

本文尽量用简单易懂的白话来描述,也仅代表我个人的看法,欢迎探讨

同系列:

女巫攻击(Sybil Attack)

什么是女巫攻击

“女巫”这个词我们应该不陌生,通常指邪恶的化身,并且拥有可怕的魔法。

阅读全文 »

写在前面的话

自比特币诞生到现在,比特币(网络)经历过大大小小非常多次的攻击,尤其在比特币诞生之初的几年,并且随着比特币价格的一路飙涨,黑客针对比特币网络的攻击就一直没有停止过。据估算,目前大约有 350 ~ 400 万比特币永久丢失,价值大约 240 ~ 280 亿美元。当然其中不只有由于黑客的攻击导致的丢失,毕竟比特币最初的几年很多人都没有意识到比特币的价值,很多的私钥都遗失了。

本文就谈一下目前几种区块链网络攻击,以及其防御方案。

本文尽量用简单易懂的白话来描述,也仅代表我个人的看法,欢迎探讨

同系列:

日蚀攻击(Eclipse Attack)

P2P 网络

概念

在介绍什么是日蚀攻击之前,有必要先对区块链系统的底层 P2P 网络做一个简单的介绍,因为日蚀攻击就是利用了 P2P 网络的特性来进行的攻击。

P2P 即 Peer to Peer,中文意思是对等网络,它是分布式系统和计算机网络相结合的产物。对等的意思就是网络中的节点角色、地位是平等的,任何节点具有极强的自由,可以任意加入、离开网络。这跟传统的 C/S 模型的结构有很大区别,任何节点既是 client ,也是 server,或者说网络中没有 server 节点,任何节点 down 掉不会对整个网络产生致命的影响,具有极强的伸缩性。

P2P 网络从诞生到现在经过了几个阶段,分别是混合式 P2P,无结构化 P2P以及结构化 P2P。

  • 混合式:顾名思义,P2P 网络混合了传统的 C/S 模型,网络中有角色充当 server 角色
  • 无结构化:也就是网状结构模型,纯分布式网络,典型代表就是比特币网络,节点之间以一种随机的,松散的方式组织在一起
  • 结构化:节点按照一定规则组织在一起,路由算法比较精准,比如 DHT 算法

混合式
阅读全文 »

写在前面的话

自比特币诞生到现在,比特币(网络)经历过大大小小非常多次的攻击,尤其在比特币诞生之初的几年,并且随着比特币价格的一路飙涨,黑客针对比特币网络的攻击就一直没有停止过。据估算,目前大约有 350 ~ 400 万比特币永久丢失,价值大约 240 ~ 280 亿美元。当然其中不只有由于黑客的攻击导致的丢失,毕竟比特币最初的几年很多人都没有意识到比特币的价值,很多的私钥都遗失了。

本文就谈一下目前几种区块链网络攻击,以及其防御方案。

本文尽量用简单易懂的白话来描述,也仅代表我个人的看法,欢迎探讨

同系列:

51%攻击

在了解什么是 51%攻击前,先简单科普下区块链的几个概念,这里主要以比特币为例作说明。

什么是挖矿?

其实挖矿这个词描述得有点太过于形象了,以至于弄得反而很生涩。当然区块链世界里还有很多玩概念的东西,背后道理其实反而没那么复杂。

在比特币网络里,大家共同在维护一张账目表,参与记账的节点可以称之为矿工,其中矿工需要做的事情就是拼命竞争记账的权利,这个竞争记账权的过程可以称之为挖矿,当一个节点得到这个记账权之后,可以描述为这个节点挖到矿了。那么节点为什么会拼命的竞争这个记账权呢?因为比特币会对挖到矿的节点有奖励。这个奖励是基于区块高度的,最开始是每个区块奖励 50btc,每产生 210000 个区块为一个减半间隔,减半间隔之后奖励会减半。比如目前(2020.04)区块奖励是 12.5btc。

上面这段话里面有两个点需要解释:

  1. 为什么节点要竞争这个记账权
  2. 区块高度又是什么

针对第一个问题,如果用比较白话的方式讲的话就是,在分布式去信任的系统中,由于有激励的存在,大家都想拿到这个记账权,但是这个记账权在同一时刻(这里用词不一定表示某一刻,更多的形容相对的同一时刻)只允许其中一个节点拿到,并且由这个节点对交易进行记录。这样才能保证这张账本是唯一的,大家看到的是一样的账本。不然大家都来记账的话,这张账本就乱了,这就是称之为 ”共识“ 的由来。

针对第二个问题,很好理解,区块高度或者说时钟高度,其实是用来描述一个区块的序号的,从创世区块 0 开始依次递增。不用过分纠结,本身是一个很简单的东西,或者叫区块序号更容易理解【手动滑稽】,可以看一下下图:

阅读全文 »

python脚本采集bandwidth

经常要做一些 linux 系统上的性能分析或者采集 cpu/mem/bandwidth 上报到监控系统。

分享一个我平常常用到的 bandwidth 采集脚本,原理是分析 /proc/net/dev 文件, 脚本如下:

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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#脚本探测网卡流入带宽,循环输出

import os
import time
import pdb

filename = './bandwidth.log'

'''
[root@~]$ cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 1144779885672 14057281982 0 0 0 0 0 0 1144779885672 14057281982 0 0 0 0 0 0
eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth2: 26686495240 203608963 0 0 0 0 0 1 78529414436 193724479 0 0 0 0 0 0
eth3: 10038847365 82467612 0 0 0 0 0 0 26209215795 64571217 0 0 0 0 0 0
bond0: 36725342605 286076575 0 0 0 0 0 1 104738630231 258295696 0 0 0 0 0 0
'''

def get_rx(interface = 'eth0'):
rsbytes = []
cmd = 'cat /proc/net/dev'
r = os.popen(cmd).readlines()
if len(r) < 4:
print "error: can't find eth interface"
return rsbytes
interface_dict = {}
for i in xrange(2,len(r),1): #从 lo 开始
interface_name = r[i].split()[0].split(':')[0]
interface_dict[interface_name] = i

if interface in interface_dict:
position = interface_dict.get(interface)
recvbytes = r[position].split()[1]
sendbytes = r[position].split()[9]
rsbytes.append(int(recvbytes))
rsbytes.append(int(sendbytes))

return rsbytes


def iftop_interface(interface = 'eth0'):
begin = int(time.time())
beginrs = get_rx(interface)
if not beginrs:
print 'error: can not find interface %s' % interface
return
while True:
time.sleep(2)
endrs = get_rx(interface)
end = int(time.time())
rxrate = float((endrs[0] - beginrs[0])) / (end - begin) * 8
sxrate = float((endrs[1] - beginrs[1])) / (end - begin) * 8
tl = time.localtime(end)
date = time.strftime('%m-%d %H:%M:%S', tl)
cout = "%s [recv(rate) = %s Mbps] [send(rate) = %s Mbps] \n" % (date,rxrate / 1000000,sxrate / 1000000)

fout = open(filename,'a')
fout.write(cout)
fout.close()

print cout

#重新赋值,进入再次循环
begin,beginrs = end,endrs


if __name__ == "__main__":
iftop_interface('ens33')

默认的网卡名字是 eth0,有些机器可能会不一样,只需要修改成你自己机器的网卡名称就行。

脚本可以直接在 我的github 进行下载。

其他

欢迎关注下我的其他脚本,平常可能会用到的一些脚本,整理了一下。

https://github.com/smaugx/dailytools

Blog:

2018-05-21 于杭州
By 史矛革

python脚本采集cpu

经常要做一些 linux 系统上的性能分析或者采集 cpu/mem/bandwidth 上报到监控系统。

分享一个我平常常用到的 cpu 采集脚本,原理是分析 /proc/stat 文件, 脚本如下:

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
#!/usr/bin/env python
# -*- coding:utf8 -*-

import time
import copy

class CpuWatch(object):
def __init__(self, time_step):
self.cpufile_ = '/proc/stat'
self.watch_time_step_ = time_step # 60 s
return

# 采集cpu信息
def read_cpu(self):
cpu_info = {}
cpufile = self.cpufile_
with open(cpufile, 'r') as fin:
for line in fin:
line_fields = line.split()
if line_fields[0] != "cpu":
continue
total = 0
for field in line_fields:
if field == "cpu":
continue
total += int(field)

cpu_info = {
"User": int(line_fields[1]),
"Sys": int(line_fields[3]),
"Idle": int(line_fields[4]),
"Steal": int(line_fields[8]),
"Wait": int(line_fields[5]),
"Total": total
}
fin.close()
return cpu_info

def get_avg_cpu(self, cpu_info_old, cpu_info):
if not cpu_info_old or not cpu_info:
return None

result = {}
if set(cpu_info.keys()) != set(cpu_info_old.keys()):
return None

delta_total = cpu_info["Total"] - cpu_info_old["Total"]
delta_user = cpu_info["User"] - cpu_info_old["User"]
delta_sys = cpu_info["Sys"] - cpu_info_old["Sys"]
delta_idle = cpu_info["Idle"] - cpu_info_old["Idle"]
delta_wait = cpu_info["Wait"] - cpu_info_old["Wait"]
delta_steal = cpu_info["Steal"] - cpu_info_old["Steal"]

last_cpu_info = cpu_info
result = {
"cpu_user": int(float(delta_user)/float(delta_total) * 100),
"cpu_sys": int(float(delta_sys)/float(delta_total) * 100),
"cpu_wait": int(float(delta_wait)/float(delta_total) * 100),
"cpu_steal": int(float(delta_steal)/float(delta_total) * 100),
"cpu_idle": int(float(delta_idle)/float(delta_total) * 100),
"cpu_util": int(float(delta_total - delta_idle - delta_wait - delta_steal)/float(delta_total) * 100)
}
print(result)
return result

def run(self):
cpu_info_old = {}
while True:
if not cpu_info_old:
cpu_info_old = self.read_cpu()
time.sleep(self.watch_time_step_)
cpu_info = self.read_cpu()

result = self.get_avg_cpu(cpu_info_old, cpu_info)
cpu_info_old = copy.deepcopy(cpu_info)

if __name__ == '__main__':
cpu_watcher = CpuWatch(time_step = 5)
cpu_watcher.run()

脚本可以直接在 我的github 进行下载。

其他

欢迎关注下我的其他脚本,平常可能会用到的一些脚本,整理了一下。

https://github.com/smaugx/dailytools

Blog:

2018-05-20 于杭州
By 史矛革