最近配置路由器 pdnsd,经常需要调试 DNS 信息,就离不开调试工具了。 nslookup 用来查询 DNS 记录,查看域名解析是否正常,经常被用来在网络故障时诊断网络问题。
在 Ubuntu 下可以使用如下命令安装:
sudo apt install dnsutils
格式:
nslookup [-option] [name | -] [server]
nslookup
是一个查询 Internet domain name server 的工具,nslookup 有两种模式:
进入交互模式,总共有两种方法。
第一种方法,直接输入 nslookup
命令,不加任何参数,则直接进入交互模式,此时 nslookup 会连接到默认的域名服务器(即 /etc/resolv.conf
的第一个 dns 地址)。
第二种方法,是支持选定不同域名服务器的。需要设置第一个参数为“-”,然后第二个参数是设置要连接的域名服务器主机名或 IP 地址。
如果你直接在 nslookup 命令后加上所要查询的 IP 或主机名,那么就进入了非交互模式。当然,这个时候你也可以在第二个参数位置设置所要连接的域名服务器。
nslookup
> www.douban.com
Server: 127.0.1.1 // 连接的 DNS 服务器
Address: 127.0.1.1#53 // DNS 服务器 IP 地址与端口
Non-authoritative answer: // 非权威答案,从连接的 DNS 服务器本地缓存中读取,非实际查询得到
Name: www.douban.com
Address: 115.182.201.6 // IP 地址
Name: www.douban.com
Address: 115.182.201.7
Name: www.douban.com
Address: 115.182.201.8
进入交互模式之后,使用 server dns-server
来改变上连 DNS 服务器地址
nslookup www.douban.com [dns-server]
如果没有指定 dns-server
,使用系统默认的 DNS 服务器。
本来打算去的自然博物馆,可无奈去官网看的时候已经没有预订票,于是就去了中国美术馆。北京来了快6年而似乎该去的博物馆都尚未能去,想接下来的时间里能不能用自己的脚都走遍,用自己的眼睛都看遍。借用网友的一句话,“不能也不敢说自己懂艺术,只是单纯的喜欢,喜欢美,喜欢不同的表达,喜欢安静的可以欣赏思想与灵感的地方”。上一次画画还要追溯到初中,近十年时间没有接触任何艺术,也没有接受任何艺术形式的熏陶。在最初进入的时候确实是一头雾水,幸而我们这一次去的时候正好是中华民族大团结全国美术作品展,至少还有一个主题让我们可以想象。虽然进门看到如此主旋律的主题有点失望,然而从一个展厅进到另一个展厅,除了进门见到的习大大有点恶心之外,渐渐就开始敬佩起这些画家。
喜欢画画的人可以经常上美术馆的官网看看,不定期的会举办一些展览。
下面是三幅震撼到我的画:
这原本是一副很大的画,这里的两位只是画的一小部分,记得画的左边还有一位在回眸,右边也还有两位。
远看真的像是一副照片,细节部分也是栩栩如生,近看脸部的文理,光影的处理着实让我震惊了。
被萌到的小狗,哈士奇?不认识。
其他令我印象深刻的画作:
塔吉克新娘 官网
美术馆馆藏作品链接
很遗憾,写这篇文章的时候中途忘记保存了,漏掉了一些内容,现在凭感觉补了一些,却再也找不到当时的感觉,虽然只仅仅相隔一天。由此可见随时保存的重要性了。
Method overriding is key to the concept of Polymorphism. 覆盖是多态的核心 True
多态可以概括成“一个接口,多个方法”,运行时决定调用函数。C++
多态利用虚函数实现,虚函数允许子类重新定义方法,子类重新定义方法的做法称为“覆盖”,或者重写。(直接覆盖成员函数和覆盖虚函数,只有重写了虚函数的才能算作是体现了C++
多态性)
封装可以使得代码模块化,继承可以扩展已存在的代码,而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。
最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。
#include <iostream>
using namespace std;
class A
{
public:
void foo()
{
printf("1\n");
}
virtual void fun()
{
printf("2\n");
}
};
class B : public A
{
public:
void foo()
{
printf("3\n");
}
void fun()
{
printf("4\n");
}
};
int main(void)
{
A a;
B b;
A *p = &a;
p->foo();
p->fun();
p = &b;
p->foo();
p->fun();
return 0;
}
输出
1 2
1 4
基类指针指向基类对象,调用基类函数;基类指针指向子类对象, p->foo() 指针是个基类指针,指向是一个固定偏移量的函数,因此此时指向的就只能是基类的foo()函数的代码了,因此输出的结果还是1。而p->fun() 指针是基类指针,指向的fun是一个虚函数,由于每个虚函数都有一个虚函数列表,此时p调用fun()并不是直接调用函数,而是通过虚函数列表找到相应的函数的地址,因此根据指向的对象不同,函数地址也将不同,这里将找到对应的子类的fun()函数的地址,因此输出的结果也会是子类的结果4。
上面例子,还有一种问法
B *ptr = (B *)&a; ptr->foo(); ptr->fun();
输出
3 2
从原理上来解释,由于B是子类指针,虽然被赋予了基类对象地址,但是ptr->foo()在调用的时候,由于地址偏移量固定,偏移量是子类对象的偏移量,于是即使在指向了一个基类对象的情况下,还是调用到了子类的函数,虽然可能从始到终都没有子类对象的实例化出现。而ptr->fun()的调用,可能还是因为C++多态性的原因,由于指向的是一个基类对象,通过虚函数列表的引用,找到了基类中fun()函数的地址,因此调用了基类的函数。由此可见多态性的强大,可以适应各种变化,不论指针是基类的还是子类的,都能找到正确的实现方法。
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下: (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。 (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
纯虚函数,virtual ReturnType Function()= 0;
C++支持两种多态性:编译时多态性,运行时多态性。
虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态覆盖(Override) 包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
Which objected oriented design concept is key to the factory design pattern?
Inheritance
Which of the following describe the C++ programming language?
Compiled Declarative
The friend keyword is used to grant access to private class members. True
friend <类型><友元函数名>(<参数表>);
友元函数只是一个普通函数,并不是该类的类成员函数,它可以在任何地方调用,友元函数中通过对象名来访问该类的私有或保护成员
#include <iostream>
using namespace std;
class Base{
public:
Base(int _data):data(_data){};
friend int getData(Base& _base);
private:
int data;
};
int getData(Base& _base){
return _base.data;
}
int main() {
Base b(2);
std::cout << getData(b) << endl;
return 0;
}
friend class <友元类名>;
友元类的声明在该类的声明中,而实现在该类外。
#include <iostream>
using namespace std;
class Base{
public:
Base(int _data):data(_data){};
friend class FClass;
private:
int data;
};
class FClass{
public:
int getData(Base _base){
return _base.data; // call friend class private data
}
};
int main() {
Base b(2);
FClass c;
cout << c.getData(b) << endl;
return 0;
}
Choose word or words to describe UML language.
只有 Picture 正确
The Unified Modeling Language (UML) is a general-purpose, developmental, modeling language in the field of software engineering, that is intended to provide a standard way to visualize the design of a system.
为啥没有 Relation 有点神奇~ UML 图能够看出类与类的关系的啊
Generalization is used by UML to describe Inheritance and the deriving of one class from another.
Generaliztion 是从属关系,可以表示继承,或者派生
http://www.uml-diagrams.org/generalization.html
#include <iostream>
void f0(int& sum){
sum = 3+2*7;
}
int main() {
int *p, sum = 0;
(*p)++;
sum = sum * 3;
f0(sum);
std::cout << sum << ",";
return 0;
}
(*p)++ 一行有问题
具体问题内容请看这里
Linux 内核是开源类 Unix 系统宏内核。仅仅一个内核并不是一套完整的操作系统。有一套基于 Linux 内核的完整操作系统叫作 Linux 操作系统。Kernel 是 Linux 系统的核心,主要负责硬件的支持。
Linux 内核提供了安全补丁, bugfix 和新特性。
Linux 内核在 GNU 通用公共许可证第 2 版之下发布。
Linux 的 Kernel 主要提供以下五个基本的功能 1:
修改启动内核版本需要谨慎,每一步在确认知道自己在做什么的情况下再操作。Linux 内核版本变更可能导致网络访问异常,声音异常,甚至是桌面环境无法启动。在安装和移除内核时,确保已经已经阅读过相关帮助,确保自己知道如何选择不同版本的内核,如何恢复之前的版本,以及如何检查 DKMS 状态。
Linux 内核版本号由 3 组数字组成:第一个组数字。第二组数字。第三组数字
在 Linux 机器上执行如下命令查看当前正在使用的内核版本
uname -r
使用如下命令查看当前系统安装的内核版本
dpkg -l | grep linux-image
如果使用的是 Linux Mint 那么在 Update Manager 中,选择 View -> Linux Kernels 可以查看当前安装的版本和正在使用的版本,或者选择安装新的版本切换。
sudo apt search linux-image
sudo apt install xxx
sudo apt-get purge xxx
一个系统可以同时安装多个内核,但是运行时只能选择一个,当启动电脑时,在显示 GRUB 菜单时可以选择加载哪一个内核。(当只有一个系统安装时,GRUB 菜单可能被跳过,强制显示 GRUB 菜单可以在启动电脑时一直按住 Shift 按键)
在 Advanced options
选项中,可以选择系统上安装的内核版本,在启动时选择一个即可。
DKMS 全称是 Dynamic Kernel Module Support,它可以帮我们维护内核外的这些驱动程序,在内核版本变动之后可以自动重新生成新的模块。
sudo apt-get install dkms
内核包含了所有的开源驱动,一般都可以正常工作,私有的驱动(DVIDIA,AMD,Broadcom… 等等)不包含在其中。这些私有驱动(proprietary drivers)需要在安装时手动编译到每一个内核中。这个操作可以用 dkms 来完成。如果私有驱动无法正常编译到内核中,可能导致启动异常,所以需要提前检查
dkms status
《UNIX AND LINUX SYSTEM ADMINISTRATION HANDBOOK》第十一章 ↩
从 Android 开发官网下载 Android SDK,从事过 Android 开发的应该知道 adb 和 fastboot 工具,在完整 SDK 中这两个工具在 platform-tools 文件夹下。如果想要方便的使用这两个工具,可以将文件路径加入到系统环境变量中,这样以后就可以在任何目录使用 adb 和 fastboot 命令。
救砖,或者在 recovery 下没有备份又无法开机的情况下只能刷回原厂镜像救砖机。因此折腾需谨慎,刷机前请一定使用 recovery 备份系统及数据。可以从 Google 官网下载镜像。
https://developers.google.com/android/nexus/images#shamu
解压之后应该会有如下文件
bootloader-shamu-moto-apq8084-71.15.img 2016/01/06 07:19 10,636,288
flash-all.bat 2016/01/06 07:19 985
flash-all.sh 2016/01/06 07:19 856
flash-base.sh 2016/01/06 07:19 814
image-shamu-mmb29q.zip 2016/01/06 07:19 1,009,825,337
radio-shamu-d4.01-9625-05.32+fsg-9625-02.109.img 2016/01/06 07:19 118,272,512
解锁 bootloader 会抹去手机一切内容,需谨慎,总之只需要一句命令
fastboot oem unlock
然后利用音量键及电源键来确认解锁 bootloader, 之后运行
fastboot reboot
重启手机。
root 工具及教程来自 @Chainfire ,在此由衷的感谢他。
第三方的 Recovery 有以下的功能:
刷入 recovery
执行以下命令
fastboot flash recovery recovery.imgrecovery.img 即下载的 Recovery 镜像。
安装完 recovery 之后就能够快速的备份系统,恢复出厂设置,恢复备份数据,刷入新ROM,刷入ZIP
一张图解释什么是 kernel
Nexus 6 第三方的 kernel 有很多选择 比如 franco.kernel,这里推荐 ElementalX,有如下功能
安装 ElementalX kernel
6.0.1 (MMB29Q) 有效
下载文件,教程中需要用的软件及文件 https://yunpan.cn/cxCaHyqkKPwg9 提取码 db02
还有这里
具体步骤参考nexus6破解电信教程
简单来说破解4G步骤:
破解完成后请在手机拨号面板那输入 *#*#4636#*#*
看下首选网络是不是LTE/GSM/CDMA auto(prl)
部分内容为 《Linux 命令速查手册》读书记录。
uname -a # 查看内核 / 操作系统 /CPU 信息
head -n 1 /etc/issue # 查看操作系统版本
cat /proc/cpuinfo # 查看 CPU 信息
hostname # 查看计算机名
lspci -tv # 列出所有 PCI 设备
lsusb -tv # 列出所有 USB 设备
lsmod # 列出加载的内核模块
env # 查看环境变量
监视系统资源,包括跟踪正在运行的程序 (ps,top)终止进程(kill),列出打开的文件(lsof),报告系统内存占用(free),磁盘空间占用(df,du)等等。
ps aux # 查看系统正在运行的进程
ps -ef # 查看所有进程
ps f # 查看进程树
top # 实时显示进程状态
kill -9 PID # 终止正在运行的进程 -9 强制中断, -15 正常中止
lsof # 列出打开的文件
free -m # 查看内存使用量和交换区使用量
df -h # 查看各分区使用情况
du -sh 《目录名》 # 查看指定目录的大小
grep MemTotal /proc/meminfo # 查看内存总量
grep MemFree /proc/meminfo # 查看空闲内存量
uptime # 查看系统运行时间、用户数、负载
cat /proc/loadavg # 查看系统负载
mount | column -t # 查看挂接的分区状态
fdisk -l # 查看所有分区
swapon -s # 查看所有交换分区
hdparm -i /dev/hda # 查看磁盘参数(仅适用于 IDE 设备)
dmesg | grep IDE # 查看启动时 IDE 设备检测状况
这里列举了常用和网络相关的命令,包括查看本地 IP(ifconfig),判断网络连通性(ping,traceroute) 等等。其中 ifconfig, iwconfig ,route 等等命令都有双重用途,不仅能够查看网络连接属性,也能够进行配置。
ifconfig # 查看所有网络接口的属性
ifup eth0 # 开启网络
ifdown eth0 # 关闭 eth0 网卡
iwconfig # 查看无线接口属性
iptables -L # 查看防火墙设置
ping # 网络连通性
route -n # 查看路由表
netstat -lntp # 查看所有监听端口
netstat -antp # 查看所有已经建立的连接
netstat -s # 查看网络统计信息
traceroute https://google.com # 显示数据包从计算机路由到指定的主机经过的每一步
mtr # traceroute 更好的代替
host # 查看网站 DNS 结果
dhclient -r eth0 # 使用 DHCP 获得新网络地址
mtr 使用介绍
w # 查看活动用户
id 《用户名》 # 查看指定用户信息
last # 查看用户登录日志
cut -d: -f1 /etc/passwd # 查看系统所有用户
cut -d: -f1 /etc/group # 查看系统所有组
crontab -l # 查看当前用户的计划任务
chkconfig --list # 列出所有系统服务
chkconfig --list | grep on # 列出所有启动的系统服务
wc 命令是 Linux 下 Word Count 的缩写,用来统计文件中的字节数,字数,行数等等。
非常简单
wc [options] files
-c, --bytes 统计字节数
-l, --lines 统计行数
-m, --chars 统计字符数,不能和 -c 一起使用
-w 统计字数,一个字定义为由空白、空格或者换行分割的字串
-L, --max-line-length 最长行的长度
命令:wc file.txt
比如有如下文件:
cat file.txt
Linux
Debian
Ubuntu
Linux Mint
命令有如下结果
wc file.txt
4 5 31 file.txt
wc -l file.txt
4 file.txt
wc -c file.txt
31 file.txt
wc -w file.txt
5 file.txt
wc -m file.txt
31 file.txt
wc -L file.txt
10 file.txt
直接使用命令 wc file.txt
输出的内容对应
wc file.txt
4 5 31 file.txt
行数 单词数 字节数 文件名
使用管道命令或者重定向来避免命令打印文件名
wc 命令如果从管道命令或者重定向命令中接受输入,则不产生文件名输出,参考如下例子:
当 wc 接受文件名作为参数时,打印出文件名
wc -l /etc/passwd
41 /etc/passwd
当文件以管道形式或者标准输入时不打印文件名
cat /etc/passwd | wc -l
41
unusual redirection, but wc still ignores the filename
< /etc/passwd wc -l
41
typical redirection, taking standard input from a file
wc -l < /etc/passwd
41
由此可以看到,当文件被当成 wc 的参数传递过去的时候会打印出文件名,而其他标准输入时候不会打印出文件名。某些情况下,你可能希望打印文件名,因此有必要知道何时会打印文件名,而何时不会打印。
MultiTail是一个开源的ncurses的实用工具,可用于在一个窗口或单一外壳,显示实时一样的尾巴命令,该命令拆分控制台为更多子窗口的日志文件的最后几行(很像显示多个日志文件到标准输出屏幕命令 )。 它还支持颜色突出显示,过滤,添加和删除窗口等。
他和tail的区别就是他会在控制台中打开多个窗口,这样可以同时监控多个日志。
apt install multitail
如果要在 CentOS,基于 Red Hat 的发行版中使用,需要开启 EPEL repository,然后安装
yum install -y multitail
监控两个日志文件,窗口上下
multitail /var/log/syslog /var/log/auth.log
如果要让窗口左右排布
multitail -s 2 /var/log/syslog /var/log/auth.log
同理,-s num
来表示后接多少个文件
进入 multitail 之后,有一些交互式命令
h
来打开帮助b
来选择打开的文件,使用上下键选择文件,一旦选择文件 multitail 会显示文件最后 100 行,使用 jk 移动光标,或者 gg/G 来快速移动到文件顶部或者最后,q 退出a
用来添加另外的监控日志文件Cache
在实际场景中有着非常广泛的使用,通常情况下如果遇到需要大量时间计算或者获取值的场景,就应当将值保存到缓存中。Cache
和 ConcurrentMap
类似,但又不尽相同。最大的不同是 ConcurrentMap
会永久的存储所有的元素值直到他们被显示的移除,但是 Cache
会为了保持内存使用合理,而配置自动将一些值移除。
通常情况下,Guava caching 适用于以下场景:
先来看一下 Guava 中 Cache 接口的定义:
com.google.common.cache.Cache
com.google.common.cache.Cache#asMap
com.google.common.cache.Cache#cleanUp
com.google.common.cache.Cache#get
com.google.common.cache.Cache#getAllPresent
com.google.common.cache.Cache#getIfPresent
com.google.common.cache.Cache#invalidate
com.google.common.cache.Cache#invalidateAll()
com.google.common.cache.Cache#invalidateAll(java.lang.Iterable<?>)
com.google.common.cache.Cache#put
com.google.common.cache.Cache#putAll
com.google.common.cache.Cache#size
com.google.common.cache.Cache#stats
Cache 接口定义的方法大都一目了然,值得一说的就是 stats()
方法,这个方法会返回一个 CacheStats
对象,这个对象包括了该 Cache 的一些统计信息,包括 hitCount
, missCount
,loadSuccessCount
,loadExceptionCount
,totalLoadTime
和 evictionCount
。
Cache
通过 CacheBuilder
类的 Builder 模式获取,常见的用法:
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(MY_LISTENER)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
如果使用的场景中对应着 key 的值有默认的值,那么可以选择使用 CacheLoader
,如果没有默认值,那么仍然可以原子的 get-if-absent-compute
方法,在 get
方法中提供一个 Callable
,或者元素也可以通过 Cache.put
来直接插入到缓存中。
LoadingCache
是一个附加着 CacheLoader
的 Cache。LoadingCache<K,V>
在 Guava 中是一个 interface,通常是用来本地 Cache 缓存 k-v 数据,value 会一直保存在内存中直到被移除或者失效。实现这个接口的类期望是线程安全的,能够安全的在多线程程序中被访问。
当第一次调用 get()
方法时,如果 value 不存在则会触发 load()
方法,load 方法不能返回 null,否则会报错。
LoadingCache 是不支持缓存 null 值的,如果 load 回调方法返回 null,则在 get 的时候会抛出异常。
如果在 CacheLoader 中抛出异常,那么 Cache 会认为没有完成,所以新的值不会被 Cache。基于这一条规则,那么如何避免在 CacheLoader 中因为缓存 null 而抛出异常,那就是编程者自己处理 null 异常。
最正统的查询 LoadingCache
的方法是调用 get(k)
方法,这个方法如果查询到已经缓存的值会立即返回,否则使用缓存的 CacheLoader
自动加载一个新值到缓存并返回。因为 CacheLoader
可能会抛出异常,那么如果有异常,则LoadingCache.get(k)
会抛出 ExecutionException
异常。而如果 CacheLoader 抛出 unchecked 未检查的异常,则 get(k)
方法会抛出 UncheckedExecutionException
异常。
此时可以选择使用 getUnchecked(k)
方法,这个方法会将所有的异常包装在 UncheckedExecutionException 异常中。需要注意的是,如果 CacheLoader 声明了检查异常,也就是 CacheLoader 显式的定义了异常,就不能调用 getUnchecked(k)
方法
CacheBuilder 在构建 Cache 时提供了两种定时回收的方法
调用 LoadingCache 的 invalidate
方法可以使得 key 失效
Let’s Encrypt 是一个免费 SSL 证书发行项目,自动化发行证书,证书有 90 天的有效期。于是有了另外一个项目可以自动安装,自动续期。
直接上网站
选择 WEB 服务器版本,系统版本,然后执行脚本即可。
执行完成之后执行 certbot run
跟着步骤就行了。
在 crontab -e
编辑文件
0 0 1 * * /usr/bin/certbot renew --force-renewal
定时每天检查,如果要过期则自动延期。
使用 -d
来指定域名
certbot --nginx -d yourdomain.com
acme.sh 是使用 Shell 编写的 acme 客户端,用来申请 Let’s Encrypt 证书。
curl https://get.acme.sh | sh
certbot 做了什么
listen 443 ssl;
ssl_certificate /path/to/pem;
ssl_certificate_key /path/to/pem;
include /path/to/ssl.conf;
ssl_dhparam /path/to/pem; # 参数,加密强度
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphes "..." # 安全套件