一、系统知识
1. profile
、bashrc
、bash_profile
之间的关系
/etc/profile
: 此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置。/etc/bashrc
: 为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取。~/.bash_profile
: 每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件。~/.bashrc
: 该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取。~/.bash_logout
: 当每次退出系统(退出bash shell)时,执行该文件. 另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc /profile中的变量,他们是”父子”关系。~/.bash_profile
是交互式、login 方式进入 bash 运行的- ~/.bashrc 是交互式 non-login 方式进入 bash 运行的通常二者设置大致相同,所以通常前者会调用后者。
2. service的几个知识
2.1. service linux服务管理
- service有两种管理方式,一个是用service命令,一个使用systemctl,自己感觉没啥区别,都需要写一个service文件
- service文件位置:
/usr/lib/systemd/system/
- 服务文件内容一般如下,具体作用查看
man systemd.service
1 | [Unit] |
- 配置了WantedBy后,使用
systemctl enable xxx
可以设置服务在某个模式下启动,会创建一个连接到/etc/systemd/system/xxx.target.wanted/
- 一般配置开机启动设置WantedBy为
multi-user.target
,然后执行上一行的命令即可 Type=forking
会检测pidfile的进程状态
2.2. 查看服务启动日志
1 | -f 跟踪日志 |
3. 开机启动脚本
update-rc.d enable/disable/defaults
4. 设备event事件查看
- 使用下面命令可以查看键盘插入或者触摸板移动等信息
1 | -w 跟踪 |
- 使用下面命令查看usb拔插事件
1 | udevadm monitor --environment --udev |
5. 用户组
5.1. 几个基本用法
1 | 将用户变更主组到group_name |
6. 查看系统启动时间
1 | ######### who命令 ########## |
7. 定时任务
7.1. cron格式说明
1 | * * * * * * |
8. 进程的几种状态
9. /dev 介绍
9.1. /dev/random
和/dev/urandom
- 用于产生真随机数,其中
/dev/random
依赖系统中断,所以较慢,但是随机性更好 /dev/urandom
不依赖系统中断,随机性较差- 它们都依赖一个系统熵
- 熵足够,两个都是真随机
- 熵不足,
/dev/random
会阻塞,/dev/urandom
不会阻塞,依赖算法
- 查看熵池大小:
/proc/sys/kernel/random/poolsize
- 查看熵池可用的数量:
/proc/sys/kernel/random/entropy_avail
/dev/random
和/dev/urandom
都是字符型设备,可以当作文件直接读取
1 | => stat /dev/random |
如果不存在,可以通过下面命令挂载
1 | mknod /dev/random c 1 8 |
10. /proc介绍
- /proc内存放了进程的信息
10.2. /proc/[pid]
进程信息
/proc/self
为当前进程信息,可以直接在程序中进行读取
1) fd 保存当前进程打开的句柄
- 0: 标准输入
- 1: 标准输出
- 2: 标准错误输出
2) maps 进程内存空间信息
- 加载了什么库及其地址
- 进程的基地址信息
3) limits 显示进程的一些限制
- unlimited就是没有限制
1 | => cat /proc/self/limits |
硬限制和软限制
- 硬限制只能由root用户进行扩大
- 软限制由用户自己修改,不能超过硬限制
4) cwd 当前工作目录
- cwd是一个软连接,指向对应的工作目录
- 查看进程当前工作目录
1 | => ll /proc/57733/cwd |
10.3. /proc/sys
保存内核的参数
- 修改可以查看sysctl
1) 列举几个内核参数含义
/proc/sys/fs/file-max
: 系统最多能打开的文件句柄数/proc/sys/kernel/threads-max
: 系统最大线程数量/proc/sys/kernel/pid-max
: pid的最大数
2) /proc/sys/net/ipv4/conf/interface/rp_filter
- 对应sysctl变量
net.ipv4.conf.[interface].rp_filter
- 内核取值会取all和当前进入的网卡较大的那个值
rp_filter
设置成1则会在当前网卡收包处理时,如果发现源地址作为目的地址路由不是指向此网卡,将会丢包,具体原理看上面链接- 设置值的说明见 rp_filter|sysctl-explorer.net
11. 管道
- 进程间通信可以使用管道
- 管道的本质是起了两个子进程,一个进程的标准输出为另一个进程的标准输入
11.1. 示例
- 使用read让管道两边的进程阻塞
1 | => { echo "aaa"; read n } | { cat; read p } |
- 查看进程树
1 | => ps -auxf |
- 明显看到父进程起了两个子进程
- 再查看它们的句柄
1 | => ls -l /proc/10342/fd |
- 左边进程的标准输出到管道,右边进程的标准输入为管道
12. 文件类型
- linux下存在很多种文件类型,一切皆文件
- 使用
ls -l
可以查看文件类型
几种类型
-
: 普通文件,文本或二进制d
: 目录l
: 链接b
: 块设备,磁盘就是块设备,可以向前向后读c
: 字符型设备,比如/dev/zero
、/dev/random
等,只能读取当前s
: 套接字文件,用于链接建立等p
: 管道文件,不过一般是命名管道,正常的管道一般不可见
13. 进程
13.1. 最多能创建多少线程
- 取决于进程的虚拟内存大小和每个线程需要占用的栈大小
- 32位系统下,4G虚拟内存,内核占用1G,剩余3G。每个线程栈大小,由
ulimit -s
可以查看,假设8M。那么最多创建300多个线程就会内存不足 - 64位系统下,取决于linux系统下的线程最大数量、全局pid号数量限制、进程可以拥有的VMA数量
13.2. 最大能打开的文件句柄数
14. 可执行文件的结构
14.1. 查看可执行文件的大小
1 |
|
1 | => gcc -g main.cpp |
14.2. 解析
1) bss 未初始化数据区
- Block Started by Symbol 以符号开始的段,通常指未初始化的数据段
- 代码中定义的未初始化的全局变量和静态变量存放到此区域
- 此区域会被内核初始化成0,所以为什么没有初始化的全局变量和静态变量会是0的原因
1 |
|
1 | => gcc -g main.cpp |
- 可以看到bss段增加了
4 * 1000
字节
2) data 静态数据和全局初始化的数据区
- 初始化的静态变量和全局变量会放到此区域
- 初始化成0的变量会被编译器优化放到bss段
1 |
|
1 | => gcc -g main.cpp |
- 可以看到定义了两个int型变量,一个增加了data段,一个增加了bss段,各4个字节
3) text 代码段,存放代码指令
1 |
|
1 | => gcc -g main.cpp |
- bss和data都没增加,text段增加了代码指令
二、有用的几个技巧
1. linux启动到文本界面和到图形界面
1 | 启动到文本界面 |
2. 修改硬盘的uuid
1 | 随机生成uuid写入 |
3. hostname立即生效
1 | hostname "$(cat /etc/hostname)" |
4. bpf 主要用于网络数据分析
原理参考 Linux超能力BPF技术介绍及学习分享
- 新版tcpdump就是基于bpf技术实现的
5. 设置无操作用户自动退出
- 修改
/etc/profile
,添加
1 | export TMOUT=15 # 无操作15秒自动退出 |
6. 系统时间和硬件时间同步
- 使用hwclock命令
- 下面是几种基本用法
1 | 显示硬件时间,启动就会读取的时间,和系统不一致就是每次重启时间都不对 |
7. 设置时区
1 | ln -sf /usr/share/zoneinfo/Asia/Beijing /etc/localtime |
8. 添加一个用户
1 | 添加用户 |
8.1. 给用户执行sudo的权力
- 需要安装sudo包,然后执行
visudo
- 在打开的sudoers文件中,找到以下行:
root ALL=(ALL) ALL
。 - 在该行下面添加以下内容:
username ALL=(ALL) ALL
,其中username是你要授予管理员权限的用户名。 - 保存并关闭sudoers文件。
9. journalctl 检查服务日志
9.1. 选项
-u <unit>
: 显示具体服务当前的日志
10. 命令行配置socks5代理
1 | export http_proxy="socks5://127.0.0.1:1080" |
三、c/c++编程
1. 获取系统信息
- sysinfo结构体定义
1 | // sysinfo.h |
- 获取系统信息
1 |
|
2. 获取进程id
1 | // unistd.h |
3. 获取系统时间
- 一般获取系统时间有两个函数
gettimeofday
和clock_gettime
1 | // /usr/include/time.h |
clock_gettime
有下面几种类型
1 | // /usr/include/bits/time.h |
4. errno
- errno线程唯一,不用担心多线程问题
- errno在头文件
unistd.h
strerror()
在头文件string.h
四、虚拟内存
1. 基础知识
- 虚拟内存是每个进程有自己的虚拟地址空间,不同的进程之间的虚拟地址空间一样,但是对应的物理地址空间不一样
- 32位下,每个进程拥有4G虚拟地址空间,其中1G为内核空间,3G为用户空间
- 每个进程有一个页表,存放在进程的信息中,mmu处理每个进程的虚拟地址到物理地址映射时要读取不同进程的页表,通过页表寄存器指定页表地址
五、进程
1. 进程间通信
- 进程间通信有管道、命名管道、信号、信号量、消息队列、共享内存、套接字
1.1. 管道
1) 特点
- 数据只能向一个方向流动
- 只能用于父子进程或兄弟进程
- fifo的读出和写入
- 缓冲区有限,本身存在于内存中,分配了一个page大小
2) 创建
- 通过shell的
|
创建 - 通过代码的创建
1 | int pipe(int fd[2]); |
- 管道的创建需要在父进程,然后再fork出子进程使用,或给两个兄弟子进程使用
1.2. 命名管道
1) 特点
- 需要提供一个文件路径,两个进程通过路径进行联系,所以可以没有亲缘关系的进程通信
- 内部没有fifo,读写会阻塞
- 其他和管道一致
2) 创建
- shell通过
mkfifo xxx
创建管道,使用>
和<
进行读取写入 - 通过代码创建,正常按照文件一样打开和读写即可
1 | int mkfifo(const char *pathname, mode_t mode); |
1.3. 信号
1) 特点
- 进程不知道信号什么时候来,类似于中断
- 信号通俗讲就是系统定义的信号,也就是kill可以发出的信号
2) 使用
- 代码注册信号
1 | /* |
1.4. 信号量
1) 特点
- 主要用于进程间共享资源访问控制机制
- 两种类型
- 二值信号量:只能0和1
- 计算信号量:非负值
2) 使用
- 创建使用
1 | int semget(key_t key, int num_sems, int sem_flags) |
- 操作函数
1 | // 改变信号量 |
1.5. 消息队列
1) 特点
- 就是在命名管道上加了个fifo,避免阻塞
- 可以通过消息类型有选择的接收数据
2) 使用
1 | // 创建或获取已存在的消息队列 |
1.6. 共享内存
1 | int shmget(key_t key, size_t size, int shmflg); |
1.7. 套接字
六、nss: Name Service Switch
Name Service Switch(NSS)是一个在Linux和其他类Unix操作系统中使用的系统组件,它提供了一种机制来管理系统中各种名称服务的配置。名称服务包括用户帐户、组、主机名、网络协议、服务和其他系统信息。NSS允许系统管理员配置系统以使用不同的名称服务,例如本地文件、NIS、LDAP等。NSS还提供了一种机制来缓存名称服务数据,以提高系统性能。在Linux系统中,NSS通常由glibc库实现。
1. 配置文件
1 | => cat /etc/nsswitch.conf |
- 上面配置的files等对应一个个插件,对应命名
libnss_xxx.so
- 修改了之后,从
glibc 2.33
后,会自动重新加载此文件,之前的版本只在进程起来的时候加载一次
2. 插件位置
1 | => ls /usr/lib/libnss_* |
3. 自定义插件
- 可以自定义so库,满足此命名,然后放到系统库路径后,添加到配置文件中
- 需要满足nss对应的库的符号要求
3.1. 自定义dns解析库
- dns解析由hosts处理
1 |
|
- 编译
1 | gcc -shared -fPIC -o libnss_test.so.2 -Wl,-soname,libnss_test.so.2 test_nss.c |
- 放到
/usr/lib
下后,重启要使用gethostbyname
的进程就好了
4. hosts dns解析服务
mymachines
: 由systemd提供,应该是处理容器类型的dns解析resolve
: 由systemd提供,是systemd-resolved.service
的处理服务files
: 由glibc提供,处理/etc/hosts
myhostname
: 由systemd提供,处理localhost
、_gateway
、_outbound
等域名使用,主要是查本地网卡的一些信息dns
: 由glibc提供,处理dns的网络请求使用
七、二进制文件格式
参考 ELF文件格式
1. 链接视图和执行视图
- 链接视图是以节(section)为单位,用于在链接时使用,可以是静态库、编译过程文件、动态库等
- 执行视图是以段(segment)为单位,是在执行时用到的视图。
- 目标文件.o里的代码段.text 是section(汇编中.text同理),当多个可重定向文件最终要整合成一个可执行的文件的时候(链接过程),链接器把目标文件中相同的 section 整合成一个segment,在程序运行的时候,方便加载器的加载
2. elf文件
小技巧和踩坑记
1. 报错[xxxx] pcieport 0000:00:1c.5 xxxx
刷屏,无法关机
- 在
/etc/defaults/grub
里面修改,在GRUB_CMDLINE_LINUX_DEFAULT=
后面追加splash pci=nomsi
2. 报错perl: warning: Falling back to the standard locale ("C").
- 由于系统设置的语言包,系统不识别,需要安装
1 | 这个可以解决不识别 zh_CN.UTF-8 |
3. 分辨率怎么调都不行,总是达不到1080
- 可以考虑下是线的问题,被一根VGA线坑了一年的人真诚提醒
4. 中文乱码
- 部分中文出现乱码很有可能时中文字体没有安装,一般安装
wqy-microhei
就可以解决
5. vmware在linux下偶现虚拟机卡死
- 可能是内核选项
vm.compaction_proactiveness
的问题,此参数决定了内核在后台应该压缩内存的力度 - 参考 kcompacd0-using-100-CPU-with-VMware-Workstation-16 可以设置
sudo sysctl -w vm.compaction_proactiveness=1
解决
6. 调整分区大小导致无法mount分区
- 使用分区管理器调整大小的时候,如果连续调整同时生效,很有可能出现调整失败,原分区也无法mount的情况
- 报错提示超级块里面的大小和分区表的大小不一致
解决
- 使用parted命令处理分区,使用resizepart将分区大小调整到原来的大小,和报错里面的一致就基本可以了
7. 查看机器内存情况
- 下面命令查看几个插槽插了几个内存条
- 可以看到四个插槽,插了两个DDR4的16G内存,速度
3200 MT/s
1 | => sudo dmidecode | grep -A16 "Memory Device$" |