第三周
一、C程序编译过程
C语言程序的编译主要经过四个过程:
# 分步骤编译运行
$ gcc -E hello.c -o hello.i # 对hello.c文件进行预处理,生成hello.i文件
$ gcc -S hello.i -o hello.s # 对预处理文件进行编译,生成汇编文件
$ gcc -C hello.s -o hello.o # 对汇编文件进行编译,生成了目标文件
$ gcc hello.o hello # 对目标文件进行链接,生成了可执行文件
# 一步实现编译过程
$ gcc hello.c -o hello # 直接编译链接成可执行目标文件
二、包管理
RedHat 使用rpm作为包管理器,软件包为后缀名是rpm文件。
Debian 使用dpgk作为包管理器,软件包为后缀名是deb文件。
软件包通常存在依赖关系,为了能够正常运行,被依赖的包必须提前安装。软件包管理器可以自动解决依赖关系并提前安装好所有额外的软件包。
自动解决依赖关系软件包管理器:
-
dnf:红帽系列rpm包管理工具
-
apt-get:deb包管理工具
-
zypper:suse的rpm管理工具
获取软件包的途径:
- 操作系统发行版本光盘
- 文件服务器
- 镜像站点
包管理命令
Action | RedHat | Debian |
---|---|---|
配置文件 | /etc/yum.repos.d/*.repo | /etc/apt/sources.list |
日志 | /var/log/dnf.log | /var/log/dpkg.log |
按名安装包 | dnf install | apt install |
按名移除包 | dnf remove | apt remove |
通过软件名、描述、简短描述来搜索包 | dnf search | apt search |
查看可更新的包 | dnf list --upgrades | apt list --upgradable |
升级包 | dnf upgrade | apt upgrade |
清除本地缓存 | dnf clean all | apt autoclean |
移除不再需要的依赖 | dnf autoremove | apt autoremove |
将作为依赖安装的包指定为手动/依赖安装 | dnf mark install | remove | apt-mark manual | auto |
仅下载而不安装包 | dnf download | apt download |
显示指定包的信息 | dnf info | apt show |
显示指定本地包信息 | rpm -qi | dpkg -s |
显示本地包提供的文件 | rpm -ql | dpkg -L |
显示远程包提供的文件 | dnf repoquery -l | apt-file list |
查询提供某个文件的包(installed only) | rpm -qf | dpkg -S |
查询提供某个文件的包(everything) | dnf provides | apt-file search |
列出仓库所有的包 | dnf list | apt list |
列出已经安装的包 | dnf list --installed | apt list --installed |
显示本地所有的包 | rpm -qa | dpkg -l |
三、搭建私有yum仓库
软件包存储在成为仓库(repository)的服务器上,基于C/S架构。可以利用Linux本地的软件包管理器(dnf,apt)来访问,在其搜索新的软件包,或是更新系统中已安装的软件包。
yum服务器的仓库可以多种形式存在:
-
file:// 本地路径
-
http://
-
https://
-
ftp://
搭建私有yum库
服务器:
# 安装http服务器
$ yum -y install httpd
# 创建仓库目录
$ mkdir -p /var/www/html/centos/8
# 将光盘的内容拷贝到仓库目录
$ mkdir /media/sr0
$ mount /dev/sr0 /media/sr0
$ cp -ar /media/sr0/* /var/www/html/centos/8
# 下载extras和epel源的包和元数据
$ yum reposync --repoid=extras --download-metadata -p /var/www/html/centos/8
$ yum reposync --repoid=epel --download-metadata -p /var/www/html/centos/8
# 下载密钥
$ wget https://mirrors.aliyun.com/epel/RPM-GPG-KEY-EPEL-8 -P /var/www/html/centos/8/
# 启动httpd服务
$ systemctl enable --now httpd
客户端:
$ vim redhat.repo
[baseos]
name=baseos
baseurl=http://172.16.20.10/centos/8/BaseOS
enable=1
gpgcheck=1
gpgkey=http://172.16.20.10/centos/8/RPM-GPG-KEY-redhat-release
[appstream]
name=appstream
baseurl=http://172.16.20.10/centos/8/AppStream
enable=1
gpgcheck=1
gpgkey=http://172.16.20.10/centos/8/RPM-GPG-KEY-redhat-release
[extras]
name=extras
baseurl=http://172.16.20.10/centos/8/extras
enable=1
gpgcheck=0
[epel]
name=epel
baseurl=http://172.16.20.10/centos/8/epel
enable=1
gpgcheck=1
gpgkey=http://172.16.20.10/centos/8/RPM-GPG-KEY-EPEL-8
$ yum repolist
repo id repo name status
appstream appstream 4,795
baseos baseos 1,662
extras extras 38
epel epel 8,955
四、常用初始化步骤
-
关闭SELinux
-
关闭防火墙
-
设置IP地址
-
设置yum仓库
-
安装常用软件包
bash-completion vim-enhanced tree autofs gcc make git wget lrzsz sysstat psmisc tcpdump rsync lsof zip unzip bzip2
五、一键安装http脚本
解读脚本
#!/bin/bash
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2021-12-22
#FileName: install_httpd.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2021 All rights reserved
#********************************************************************
## 定义变量
# 获取cpu核心数
CPUS=`grep -c processor /proc/cpuinfo`
# httpd版本
HTTPD_VERSION=2.4.52
# 安装目录
INSTALL_DIR=/apps/httpd
# 设置颜色
COLOR="echo -e \E[32;1m"
END="\E[0m"
. /etc/os-release # 导入文件
# 如果ID是rocky或者centos,就执行下面的语句,否则就执行elif语句
if [ $ID = 'rocky' -o $ID = "centos" ];then
# 关闭防火墙
systemctl disable --now firewalld
# 下载编译器、依赖包等工具
yum -y install gcc make apr-devel apr-util-devel openssl-devel pcre-devel redhat-rpm-config bzip2
# 如果ID是ubuntu,就执行后面的语句,否则就打印"不支持此系统"并退出脚本。
elif [ $ID = 'ubuntu' ];then
# 升级包
atp update
# 安装编译器、依赖包
apt -y install libapr* libpcre3* libssl-dev make
else
$COLOR"不支持此系统"$END
exit
fi
# 进入目录
cd /usr/local/src
# 查询系统中是否存在wget包,如果不存在就下载wgwt
rpm -q wget || yum -y install wget
# 下载httpd源码,如果下载失败就打印"下载失败,退出"并退出脚本
wget https://dlcdn.apache.org//httpd/httpd-${HTTPD_VERSION}.tar.bz2 || { $COLOR "下载失败,退出" $END;exit ; }
# 解压包
tar xf httpd-${HTTPD_VERSION}.tar.bz2
# 进入解压后的目录
cd httpd-${HTTPD_VERSION}
# 执行configure脚本
./configure --prefix=${INSTALL_DIR} --enable-ssl --disable-status
# 开始编译,然后生成相应目录文件
make -j $CPUS && make install
# 创建软链接
ln -s /apps/httpd/bin/apachectl /usr/local/bin/
# 启动apachectl,如果启动成功就打印"安装成功"
apachectl start && $COLOR"安装成功!"$END
# 打印主页url
$COLOR"请访问:http://`hostname -I`"$END
一键安装httpd脚本
#!/bin/bash
Download_DIR=/usr/local/src
Install_DIR=/apps/httpd
Httpd_VERSION=$1
CPU=$(cat /proc/cpuinfo | grep -c processor)
[ -d $Install_DIR ] || mkdir -p $Install_DIR
download () {
. /etc/os-release
if [ $ID == "rocky" -o $ID == "centos" ];then
rpm -q wget &> /dev/null || dnf -y install wget
yum -y install gcc make apr-devel apr-util-devel openssl-devel pcre-devel redhat-rpm-config
elif [ $ID == "ubuntu" ];then
dpkg -s wget || apt -y install wget
apt -y install libapr* libpcre3* libssl-dev make
else
echo "不支持该系统,退出"
exit
fi
systemctl disable --now firewalld &> /dev/null
wget https://archive.apache.org/dist/httpd/httpd-${Httpd_VERSION}.tar.gz -P ${Download_DIR} || { echo "下载失败,退出脚本";exit; }
}
install () {
cd $Download_DIR
tar xf httpd-${Httpd_VERSION}.tar.gz
cd httpd-${Httpd_VERSION}
./configure --prefix=${Install_DIR} --enable-ssl --disable-status
make -j $CPU && make install
ln -s ${Install_DIR}/bin/* /usr/local/bin/
}
start () {
apachectl start && echo "安装成功"
echo "请访问:http://$(hostname -I | awk '{print $1}')"
}
download
install
start
六、OSI参考模型
基本单位 | 功能 | 协议 | |
---|---|---|---|
应用层 | 报文 | 为应用程序提供服务并制定应用程序中通信的相关细节 | HTTP,TLS,FTP,DNS,SMTP |
表示层 | 报文 | 负责格式的转换,压缩与解压缩,加密与解密 | |
会话层 | 报文 | 负责建立与断开通信连接 | |
传输层 | 报文分组 | 提供端到端的、可靠的或不可靠的传输 | TCP,UDP |
网络层 | 数据包 | 负责IP寻址,路由选择,IP分包和组包 | IPv4,IPv6,ARP,ICMP,IPSec |
数据链路层 | 数据帧 | 负责MAC寻址,将比特流转换为具有意义的数据帧 | Ethernet,PPP,PPPoE,HDLC |
物理层 | 比特 | 负责比特流与高低电平之间的转换 | IEEE802.3,FDDI |
七、 调整动态端口
Q:调整动态端口范围为20000-60000
查看端口范围:
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
修改端口范围:
# 临时修改
$ sysctl net.ipv4.ip_local_port_range="20000 60000"
# 永久生效
$ sysctl net.ipv4.ip_local_port_range="20000 60000" >> /etc/sysctl.conf
八、TCP
TCP首部结构
+-------------------------------+-------------------------------+
| Source Port | Destination Port |
+-------------------------------+-------------------------------+
| Sequence Number |
+---------------------------------------------------------------+
| Acknowledgment Number |
+-------+-----------+-+-+-+-+-+-+-------------------------------+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-------+-----------+-+-+-+-+-+-+-------------------------------+
| Checksum | Urgent Pointer |
+-------------------------------+---------------+---------------+
| Options | Padding |
+-----------------------------------------------+---------------+
| data |
+---------------------------------------------------------------+
字段 | 长度(bit) | 含义 |
---|---|---|
Source Port | 16 | 源端口,标识哪个应用程序发送 |
Destination Port | 16 | 目的端口,标识哪个应用程序接收 |
Sequence Number | 32 | 序列号。TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号 |
Acknowledgment Number | 32 | 确认号,是期望收到对方的下一个报文段的数据的第1个字节的序号,即上次已成功接收到的数据字节序号加1。只有ACK标识为1,此字段有效 |
Data Offset | 4 | 数据偏移,即首部长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,以32比特(4字节)为计算单位。最多有60字节的首部,若无选项字段,正常为20字节 |
Reserved | 6 | 保留,必须填0 |
URG | 1 | 紧急指针有效标识。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据) |
ACK | 1 | 确认序号有效标识。只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效 |
PSH | 1 | 标识接收方应该尽快将这个报文段交给应用层。接收到PSH = 1的TCP报文段,应尽快的交付接收应用进程,而不再等待整个缓存都填满了后再向上交付 |
RST | 1 | 重建连接标识。当RST=1时,表明TCP连接中出现严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立连接 |
SYN | 1 | 同步序号标识,用来发起一个连接。SYN=1表示这是一个连接请求或连接接受请求 |
FIN | 1 | 发端完成发送任务标识。用来释放一个连接。FIN=1表明此报文段的发送端的数据已经发送完毕,并要求释放连接 |
Window | 16 | 窗口:TCP的流量控制,窗口起始于确认序号字段指明的值,这个值是接收端期望接收的字节数。窗口最大为65535字节 |
Checksum | 16 | 校验字段,包括TCP首部和TCP数据,是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部 |
Urgent Pointer | 16 | 紧急指针,只有当URG标志置1时紧急指针才有效。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面) |
Options | 可变 | 选项字段 |
Padding | 可变 | 填充字段,用来补位,使整个首部长度是4字节的整数倍 |
data | 可变 | TCP负载 |
TCP三次握手
TCP四次挥手
九、主机到主机的包的传递过程
主机A的IP地址为10.0.0.1/24,主机B为10.0.0.2/24。
下面是主机A向主机B发起ping请求的过程:
由于两台主机处于同一个网络中,主机A向主机B发起ARP请求报文,然后主机B向主机A返回自己的MAC地址。主机A封装ICMP报文,源MAC是自己,目的MAC是主机B,源IP是自己,目的IP是主机B。主机B收到数据包后进行解包,发现源MAC是自己,继续解包,再次看到目的IP是自己,然后封装ICMP报文返回给主机A。至此双方完成一次通信。
十、IP地址的分类
IP地址=网络位+主机位,全1为网络位,全0为主机位。
A类:1 - 126
Lo: 127
B类:128 - 191
C类:192 - 223
D类:224 - 239
E类:240 - 255
十一、掩码计算
Q:201.222.200.111/18 主机数?子网掩码?
11111111.11111111.11000000.00000000 => 255.255.192.0
网络地址和广播地址不可用,所以可容纳2^14 - 2=16382台主机
子网掩码是255.255.192.0
十二、如何判断是否在同一个网段
Q:当A(10.0.1.1/16)与B(10.0.2.2/24)通信,A如何判断是否在同一个网段?A和B能否通信?
假设两台主机在同一个广播域中
- A向B发起ping请求,首先A用自己的掩码与B的IP地址做与运算:
11111111.11111111.00000000.00000000
00001010.00000000.00000010.00000010
00001010.00000000.00000000.00000000 ==> 10.0
- 得到的结果与自己的网络位(10.0)一样,所以A就判断和B是在同一个网段。然后A就会发送ARP请求报文获取B的MAC地址。由于A和B在同一个广播域中,B自然会收到A的ARP请求。
-
当B收到A的ARP请求后,就会向A回应自己的MAC地址。A获取到B的MAC后,接着向B发送ICMP包,源IP是自己,目的IP是B。
-
B收到数据包后,用自己的掩码与目的(A)IP地址做与运算:
11111111.11111111.11111111.00000000
00001010.00000000.00000001.00000001
00001010.00000000.00000001.00000000 ==> 10.0.1
- 得到的结果与自己的网络位(10.0.2)不一样,由于B主机没有设置网关,所以将包丢弃。
所以,当两台主机在同一个广播域,A不能与B通信。
十三、将10.0.0.0/8划分32个子网
8位子网掩码换算成二进制如下:
11111111.00000000.00000000.00000000
由于2的5次方是32,所以网络位需要向主机位借5位:
11111111.11111000.00000000.00000000 ==> 255.248.0.0
所以每个子网的掩码是:255.248.0.0 。
每个子网可容纳2^19-2=524286台主机。
十四、设置IP地址
# 为一个设备名为eth0的网卡添加一个名为eth0的网卡名
$ nmcli connection add con-name eth0 ifname eth0 type ethernet
Connection 'eth0' (3c3ceeac-ec30-438d-8404-ccaf6dc9b4bf) successfully added.
# 设置eth0网卡,IP地址设置为手动,依此设置IP地址,网关,dns
$ nmcli connection modify eth0 ipv4.method manual ipv4.addresses 172.16.20.80/24 ipv4.gateway 172.16.20.254 ipv4.dns 172.16.20.254
# 开启网卡
$ nmcli connection up eth0
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/132)
# 查看网卡状态
$ nmcli connection show
NAME UUID TYPE DEVICE
eth0 3c3ceeac-ec30-438d-8404-ccaf6dc9b4bf ethernet eth0
# 测试
$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=72.7 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=72.7 ms
十五、网卡配置文件解析
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE=Ethernet # 设备类型
PROXY_METHOD=none # 代理
BROWSER_ONLY=no # 仅浏览器
BOOTPROTO=none # IP地址获取方式
DEFROUTE=yes # 默认路由
IPV4_FAILURE_FATAL=no # 是否开启错误检查
NAME=eth0 # 网卡逻辑名
UUID=e2af7ace-b863-4605-9db1-5d4ab83fb4a5 # UUID标识
DEVICE=eth0 # 设备名
ONBOOT=yes # 开机自动激活
IPADDR=172.16.20.80 # IP地址
PREFIX=24 # 掩码
GATEWAY=172.16.20.254 # 网关
DNS1=172.16.20.254 # DNS服务器
十六、配置bind0
# 添加bond0设备,模式为轮询
$ nmcli connection add con-name bond0 ifname bond0 type bond bond.options mode=0
Connection 'bond0' (67d29733-8f6c-482b-83f0-be30e138bbac) successfully added.
# 将eth1添加至bond0
$ nmcli connection add con-name bond-port1 ifname eth1 type ethernet slave-type bond master bond0
Connection 'bond-port1' (678095af-017c-4612-b868-4f1efb61aac6) successfully added.
# 将eth2添加至bond0
$ nmcli connection add con-name bond-port2 ifname eth2 type ethernet slave-type bond master bond0
Connection 'bond-port2' (2a9d7639-1e3c-4d6e-a9a9-cf9f6f4a8866) successfully added.
# 设置bond0地址
$ nmcli connection modify bond0 ipv4.addresses 172.16.20.100/24
# 启动bond0设备
$ nmcli connection up bond0
测试:
关闭一个网卡
$ ip link set eth1 down
没有影响
[C:\~]$ ping 172.16.20.100 -t
正在 Ping 172.16.20.100 具有 32 字节的数据:
来自 172.16.20.100 的回复: 字节=32 时间<1ms TTL=64
来自 172.16.20.100 的回复: 字节=32 时间<1ms TTL=64
来自 172.16.20.100 的回复: 字节=32 时间<1ms TTL=64
来自 172.16.20.100 的回复: 字节=32 时间<1ms TTL=64
来自 172.16.20.100 的回复: 字节=32 时间<1ms TTL=64
来自 172.16.20.100 的回复: 字节=32 时间<1ms TTL=64
十七、shell
17.1 通过ifconfig命令查找IP
$ ifconfig | grep "inet " | awk '{print $2}'
172.17.0.1
172.16.20.81
127.0.0.1
17.2 扫描主机
#!/bin/bash
NET=172.16.20
for i in {1..254};do
{
ping -c1 -W1 172.16.20.$i &> /dev/null && echo "172.16.20.$i is up" || echo "172.16.20.$i is down"
}&
done
wait
17.3 计算所有用户ID的和
#!/bin/bash
ALL_UID=0
while read line;do
let UID_ALL+=$(echo $line | awk -F: '{print $3}')
done < /etc/passwd
echo $ALL_UID