[{"content":"模块化，事件驱动，异步，单线程，非阻塞架构，成为nginx代码的基础。\nNginx的架构基础 Nginx进程结构 多进程结构\nApache在使用多线程的时候，因为线程之间是共享同一个地址空间的，当有一个第三方模块引发了一个地址空间引发的段错误时，在地址越界出现时，可能导致整个 Apache 进程崩溃。\n而Nginx多进程的模型往往不会出现这种问题，避免了单个进程的崩溃影响整个服务。\n事件驱动架构 事件 Nginx是一个事件驱动的框架，所谓事件指的是网络事件，Nginx每一个连接会自然对应两类网络事件，一个读事件，一个写事件。\n事件它本身是一个生产者，是网络中自动生产到nginx中的，我们对每种事件要建立一个消费者\n比如连接建立事件的事件消费者，就是我们对accept()的调用，那么http模块就会去建立一个新的连接 还有很多读事件或者写事件，在http的状态机中，不同的事件，我们会调用不同的方法，也就是每一个消费者去处理。 通过三次握手感受Nginx网络事件处理\n三次握手的过程：\n当浏览器向Nginx服务器发起请求时，会经历经典的TCP三次握手： 第一次握手：浏览器向服务器发送SYN包，表示请求建立连接。 第二次握手：服务器收到SYN包后，返回SYN+ACK包，表示同意建立连接。 第三次握手：浏览器收到SYN+ACK包后，再发送一个ACK包，表示确认连接已经建立。 浏览器和操作系统的通信：\n在三次握手的过程中，浏览器发出的数据包（SYN和ACK等）通过操作系统的TCP/IP栈处理，网络层负责实际的数据包传输。 这期间，Nginx服务器并不会立即被通知到，操作系统的内核会负责处理这个TCP连接的建立。 操作系统通知Nginx进程：\n只有在三次握手成功完成后，操作系统才会将这个新的连接通知给Nginx。这是因为，在握手过程中，连接还没有正式建立，操作系统只是在处理网络数据包。 当操作系统收到浏览器发送的最后一个ACK包（三次握手的第三步），连接才被认为成功建立。这时，操作系统会通知Nginx服务器进程，告诉它有一个新的连接已经建立，并触发Nginx的读事件。\nNginx的读事件： Nginx作为一个事件驱动的服务器，会等待内核的通知，通常通过epoll（或kqueue在BSD系统上）监听新连接的到来。内核收到ACK包后，Nginx的事件循环就会被唤醒，并触发相应的读事件（也就是开始处理来自浏览器的HTTP请求）。这个读事件对应的是一个建立新连接，所以nginx此时应该调用accept()这个方法，去建立一个新的连接\nWorker 进程与事件循环（Event Loop） 每个 Worker 进程运行一个事件循环，持续监听和处理各种事件（如新连接、数据读取、数据写入等）。事件循环的核心是一个无限循环，依次获取事件并调用相应的处理程序。\n每个 Worker 进程维护一个事件循环，主要包括以下步骤：\n等待事件：通过操作系统的事件通知机制（如 epoll_wait）等待新事件的到来。 获取就绪事件：当有事件发生时，获取所有就绪的事件列表。 处理事件：遍历就绪事件列表，根据事件类型调用相应的回调函数进行处理。 循环等待：处理完所有就绪事件后，继续等待下一个事件。 这种方式避免了线程切换的开销，同时通过单线程的事件驱动模型有效管理大量并发连接。\nepoll epoll 是 Linux 提供的一种高效的 I/O 事件通知机制，尤其适用于需要处理大量并发连接的场景。\n相比于传统的 select 和 poll，epoll 可以处理大规模并发连接，而不会随着监听的文件描述符数量增加而线性增长。\n原因：\nepoll 内部维护一个红黑树（或其他高效的数据结构）来存储所有监视的文件描述符，并维护一个就绪事件的就绪列表（Ready Double Linked Link List）。这种设计允许 epoll 在 O(1) 的时间复杂度内处理事件。 两种主要数据结构\n红黑树 存储，管理epitem的定时器 所有epitem的定时器都在树上 红黑树的根节点始终是 最近即将超时的定时器。 O(logN) 就绪双向链表 当连接上有可读或可写事件时， epoll 会将epitem标记为活跃，并添加到链表中。 只存储有有就绪事件（可读/可写）的epitem O(Nready) epoll工作流程：\n创建 epoll 实例：通过 epoll_create 创建一个 epoll 实例，返回一个文件描述符（epoll_fd）。 注册和修改事件：使用 epoll_ctl 向 epoll 实例中添加、修改或删除感兴趣的文件描述符及其事件。 等待和处理事件：通过 epoll_wait 阻塞等待事件的发生，并获取就绪事件列表，进行相应的处理。 epoll 的关键系统调用\nepoll_create\n1 int epoll_create(int size); 参数: size：建议传递大于需要监控的文件描述符数量，但自 Linux 2.6.8 之后，此参数被忽略，建议传递任意正整数。 返回值：成功时返回一个新的 epoll 文件描述符，失败时返回 -1 并设置 errno。 epoll_ctl\n1 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 参数： epfd：epoll 实例的文件描述符，由 epoll_create 返回。 op：操作类型，可以是 EPOLL_CTL_ADD、EPOLL_CTL_MOD 或 EPOLL_CTL_DEL。 fd：需要监视的文件描述符。 event：指向 epoll_event 结构的指针，描述感兴趣的事件。 返回值：成功时返回 0，失败时返回 -1 并设置 errno。 epoll_wait\n1 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); 参数： epfd：epoll 实例的文件描述符。 events：用户空间数组，用于存储就绪事件。 maxevents：events 数组的最大容量。 timeout：等待的毫秒数。-1 表示无限等待，0 表示立即返回。 返回值：成功时返回就绪事件的数量，失败时返回 -1 并设置 errno。 epoll_event 结构\n1 2 3 4 struct epoll_event { uint32_t events; // 事件类型 epoll_data_t data; // 用户数据 }; events：位掩码，表示感兴趣的事件类型，如 EPOLLIN、EPOLLOUT 等。 data：用户自定义的数据，可以是指针、文件描述符或其他数据类型，用于在事件处理时识别具体的资源。 100w个并发连接，但我可能只接收到几百个活跃的连接，我只需要处理几百个活跃的请求，而select或者poll，它们的实现是有问题的，因为每一次我去取操作系统的事件的时候，我都需要把这100w个连接统统的扔给操作系统，让它去依次判断哪些连接上面有事件进来了，所以可以看到这里操作系统做了大量的无用功，它扫描了大量不活跃的连接\nepoll使用了一种特性，因为高并发连接中，每次处理的活跃连接数量占比很小\n内核空间结构\nepitem 即“epoll item”。用于表示被 epoll 监视的每一个文件描述符（File Descriptor, FD）及其相关的事件信息。\n就绪双向链表允许 epoll 在调用 epoll_wait 时，能够高效地遍历和处理这些已就绪的事件。\nrdllink 的全称为 \u0026ldquo;Ready Double Linked List Link\u0026rdquo;，即 “就绪双向链表链接”。 rdllist，是就绪双向链表的起始。 红黑树用于管理连接的定时器。\nrbn 对 rb_node 的简称。rb_node 是红黑树（Red-Black Tree）中的一个节点结构。 rbr，红黑树的根节点。 示例：\n初始化阶段\n调用 epoll_create() 创建 epoll 实例 ( fd )。 初始化红黑树 初始化就绪双向链表（rdllist） 调用epoll_ctl()注册listen_fd，监听EPOLLIN（可读）事件 新连接到来\n内核会将客户端的请求从SYN 队列转移到 accept 队列。 listen_fd 的可读状态变为 true，并触发EPOLLIN 事件。 listen_fd的epitem的指针被引用到rdllist（就绪链表） epoll_wait()取出rdllist里的就绪事件fd Nginx 使用 accept() 从 accept 队列中取出新连接的 client_fd epoll_ctl() 将 client_fd 注册到 epoll，并加入红黑树中（定时器） 第一个请求\nclient_fd有读事件，它的epitem的指针被引用到rdllist（就绪链表） epoll_wait()取出rdllist里的就绪事件fd 刷新连接的定时器。 将红黑树中的旧节点删除。插入新的超时节点，更新超时时间。 Nginx 处理http请求 将生成的响应数据存入缓冲区 调用 epoll_ctl(EPOLL_CTL_MOD)，将 client_fd 的事件类型改为 EPOLLOUT（可写事件）。等待 socket 可写。 写事件处理\n当 socket 可写时，内核将 client_fd 的 epitem 加入到 rdllist。\nepoll_wait() 返回写事件。\nNginx调用连接的 write 回调函数，将缓冲区的数据写入客户端。\n如果响应数据发送完成且连接关闭：\n调用 epoll_ctl(EPOLL_CTL_DEL) 将 client_fd 从 epoll 中移除。 将连接资源释放，返回到空闲连接池。 如果是长连接，则继续监听读事件（EPOLLIN）。\nNginx中的连接池 worker_connections 数组 Nginx 维护的“连接池（连接数组）”是 Nginx 用来高效管理客户端连接的一个重要机制。\n每个新的 client_fd（客户端连接的文件描述符）会在 Nginx 中与一个 ngx_connection_t 结构体关 联，这个结构体用来管理和表示与这个客户端连接的所有相关数据和上下文。\n连接数组的本质是一个静态分配的 ngx_connection_t 结构体的数组。\n每个 ngx_connection_t 代表一个客户端的 TCP 连接。\n这些数组会在Nginx worker 进程启动时提前分配好，不在请求的过程中动态分配。\n用户空间中，Nginx使用ngx_connection_t结构体数组（连接池）存放所有连接。\n内核空间中，内核使用epitem结构体存放连接的信息，红黑树存放所有连接的定时器，rdllist存放有就绪事件的连接。\nepitem 属于内核态，管理文件描述符的事件（监听哪些事件、是否就绪等）。\nngx_connection_t 属于用户态，提供对文件描述符及其事件的逻辑处理。\n用户通过 epoll_ctl() 将 ngx_connection_t 的文件描述符注册到 epoll。\n内核会为该文件描述符创建一个 epitem。\n当 epitem 触发事件时，epoll_wait() 返回该文件描述符，用户态通过这个文件描述符找到对应的 ngx_connection_t。\n连接池的核心结构\nNginx 在每个 worker 进程中都会维护一个连接池，这个连接池是一个数组。 这个数组的大小是 worker_connections ，所以每个 worker 进程最多可以管理的并发连接数是 worker_connections。 连接池的分配和回收\n新连接到来时，从连接池中取出一个可用的 ngx_connection_t，并将 client_fd 赋值给它。 连接关闭时，将这个 ngx_connection_t 重新放回到空闲连接池，以供复用。 Nginx 使用一个空闲链表 (free_connections) 来维护当前未使用的连接对象。\n当新的client_fd 到来时，Nginx 会从free_connections 链表头中获取一个 ngx_connection_t。\n当连接关闭时，将 ngx_connection_t 放回到 free_connections 链表头，实现复用连接对象的目 的。\n连接分配的过程\n当有一个新的客户端请求到来时，Nginx 需要分配一个 ngx_connection_t ，这个过程如下：\n从 free_connections 中取出一个 ngx_connection_t： Nginx 检查 free_connections 是否为空。 如果空闲链表不为空，则将 free_connections 链表的第一个节点从链表中移除，并将其作为 新连接的 ngx_connection_t。 更新 free_connection_n，减少 1。 初始化 ngx_connection_t： 设置 client_fd：将 accept() 返回的 client_fd 存入 ngx_connection_t-\u0026gt;fd 。 分配内存池：为这个连接分配一个512 字节的内存池 ngx_pool_t。 监听事件：将 client_fd 注册到 epoll 中。 连接释放的过程\n当客户端关闭连接时，Nginx 需要释放这个连接，这个过程如下：\n释放内存池： Nginx 销毁这个连接的 内存池 (ngx_pool_t)。 将 ngx_connection_t 重新放回 free_connections ： 将这个 ngx_connection_t 连接重新加入到 free_connections 链表头。 更新 free_connection_n，增加 1。 读事件和写事件数组 在 Nginx 启动时，除了worker_connections 数组外，Nginx 还会创建两个同样长度的读事件和写事件 的数组。这两个数组分别用于管理读事件和写事件，这也是 Nginx 的事件驱动模型的核心。\n同一连接的worker_connections 数组，读数组与写事件数组的索引相同。\nNginx处理请求流程 进入Nginx后，有三个大的状态机处理三种流量不同流量\n一个是处理TCP，UDP的传输层状态机\n一个处理应用程的HTTP状态机\n以及处理邮件的MAIL状态机\nnginx中，核心的深绿色的框，它使用非阻塞的事件驱动处理引擎，也就是EPOLL\n当整个内存已经不足以缓存住所有的文件缓存信息时\n会退化成阻塞的磁盘调用，通常使用线程池处理磁盘阻塞调用 对于每一个处理完成的请求\n记录access日志和error日志，这两个日志也是记录磁盘中的，可以通过rsyslog，把它记录到远程主机上 更多的时候，nginx作为负载均衡和反向代理使用 这个时候可以把请求协议级传输到后面的服务器 也可以通过例如：应用层的一些协议，fasetcgi、uWSGL，SCGL等代理到相应的应用服务器 Http请求处理 解析请求行与请求头 这里处理请求和处理连接是不一样的，处理连接的话，可能我只需要把连接收到我的nginx内存中就ok，但处理请求可能需要进行大量的上下文分析，去分析http协议，分析每一个header，所以此时要分配一个请求内存池，请求内存池默认分配4k，因为请求的上下文通常涉及业务，因此分配的会大一点，4k通常是比较合适的数值\n分配完内存池后，nginx会使用状态机解析请求行，解析请求行的时候可能会发现有的url特别大，已经超过了刚刚分配的1k的内存，此时就要分配一个更大的内存large_client_header_buffers:4 8k（这里并不是直接分配32k，而是先分配1个8k，然后将1k的内容拷贝到这里，此时还剩7k，我们用剩余的7k内存再去接收httpurl，看url是不是解析完了，如果8k的url实在是太长了，8k还没有接收完，就会再分配第二个8k，最多分配32k）\n当我完整的解析完请求行，通过解析到\\of\\path，我就可以标识url，那么标识完url，nginx会继续解析http的各首部字段header\n状态机解析header各字段，然后如果当前分配的内存不足以放header的各字段，就还会分配内存，这里接受请求行的内存和接收header各字段的共用一个内存，共用4*8k的内存\n接收完完整的header后，标识header，标识header的过程中，但是收到hosts的字段时会确定哪个server块来处理这个请求，当我标识完所有的header后，会移除超时定时器，client_header_timeout: 60s\n开始11个阶段的http请求处理，上述所有的过程都是nginx的框架处理的，后续的内容才是http模块来处理。\nHttp状态机 11个阶段\n阶段名称 索引位置 状态机执行的操作 NGX_HTTP_POST_READ_PHASE 0 读取请求体，调用相关的请求体过滤器。 NGX_HTTP_SERVER_REWRITE_PHASE 1 服务器级别的 URL 重写，执行 rewrite 指令。 NGX_HTTP_FIND_CONFIG_PHASE 2 查找 location {} 的匹配规则，确定请求的处理方式。 NGX_HTTP_REWRITE_PHASE 3 location 级别的 URL 重写阶段，调用相关模块的重写规则。 NGX_HTTP_POST_REWRITE_PHASE 4 URL 重写结束后的阶段，执行重写后的收尾操作。 NGX_HTTP_PREACCESS_PHASE 5 权限检查前的阶段，预处理权限相关逻辑。 NGX_HTTP_ACCESS_PHASE 6 访问控制阶段，控制 IP 地址、白名单等访问权限。 NGX_HTTP_POST_ACCESS_PHASE 7 访问控制后的阶段，通常用于访问控制的后续处理。 NGX_HTTP_TRY_FILES_PHASE 8 执行 try_files 指令，根据配置尝试匹配文件路径。 NGX_HTTP_CONTENT_PHASE 9 生成响应的阶段，调用模块的 content 指令处理响应内容。 NGX_HTTP_LOG_PHASE 10 记录日志阶段，通常记录到 access.log 或 error.log。 可以挂载钩子函数的阶段\n阶段名称 阶段索引 是否可挂钩子函数 常见用途 NGX_HTTP_POST_READ_PHASE 0 ✅ 是 用于读取和过滤请求体，解析请求的预处理。 NGX_HTTP_SERVER_REWRITE_PHASE 1 ✅ 是 服务器范围的 URL 重写，可插入自定义 URL 转发逻辑。 NGX_HTTP_FIND_CONFIG_PHASE 2 ❌ 否 查找 location {} 配置的阶段，不允许挂钩子函数（核心内部逻辑）。 NGX_HTTP_REWRITE_PHASE 3 ✅ 是 location {} 范围的 URL 重写规则。 NGX_HTTP_POST_REWRITE_PHASE 4 ✅ 是 URL 重写结束后的收尾阶段，适合处理重写后需要额外处理的逻辑。 NGX_HTTP_PREACCESS_PHASE 5 ✅ 是 权限检查前的阶段，可插入预处理逻辑（如用户身份初始化）。 NGX_HTTP_ACCESS_PHASE 6 ✅ 是 访问控制阶段，用于 IP 白名单、认证模块的扩展。 NGX_HTTP_POST_ACCESS_PHASE 7 ✅ 是 访问控制后的阶段，通常用于访问控制的后续处理逻辑。 NGX_HTTP_TRY_FILES_PHASE 8 ❌ 否 try_files 指令的执行阶段，不允许挂钩子函数（内部优化逻辑）。 NGX_HTTP_CONTENT_PHASE 9 ✅ 是 响应生成阶段，可扩展为动态内容服务或自定义响应模块。 NGX_HTTP_LOG_PHASE 10 ✅ 是 日志记录阶段，扩展日志模块或请求统计逻辑。 钩子函数就是会被某个阶段会被触发的函数。\n可以自己写个函数，将其注册到某一阶段中。当状态到达那一阶段，函数就会被触发。\n零拷贝 传统Linxu中I/O的问题\n大量数据的拷贝，用户态和内核态的频繁切换，会消耗大量的CPU资源，严重影响数据传输的性能\n什么是零拷贝\n零拷贝就是上述问题的一个解决方案，通过尽量避免拷贝操作，来缓解CPU压力 MMAP技术 数据在内核空间，不拷贝到用户空间。\n应用通过用户空间存储的数据地址直接修改内核空间数据。\nSENDFILE 静态资源不需要应用处理，可以直接发送的数据，不经过用户空间。\nDMA辅助的SENDFILE（需要专用硬件支持） nginx 源码安装 ubuntu 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 编译环境准备 apt install build-essential gcc g++ libc6 libc6-dev libpcre3 libpcre3-dev libssl-dev libsystemd-dev zlib1g-dev apt install libxml2 libxml2-dev libxslt1-dev php-gd libgd-dev geoip-database libgeoip-dev # 创建运行用户 useradd -r -s /usr/sbin/nologin nginx # 下载最新版源码并解压 wget https://nginx.org/download/nginx-1.24.2.tar.gz tar xf nginx-1.24.2.tar.gz # 定制配置 cd nginx-1.24.2/ ./configure --prefix=/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module ./configure --prefix=/nginx --user=nginx --group=nginx --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-mail_ssl_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-http_geoip_module=dynamic --with-http_image_filter_module=dynamic --with-http_perl_module=dynamic --with-http_xslt_module=dynamic --with-mail=dynamic --with-stream=dynamic --with-stream_geoip_module=dynamic # 编译安装 make \u0026amp;\u0026amp; make install 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 # 修改目录属主属组并查看 chown -R nginx:nginx /nginx/ # 创建软链接 ln -sv /nginx/sbin/nginx /usr/sbin/nginx # 导入手册 cp man/nginx.8 /usr/share/man/man8/ mandb # 创建PID 目录 mkdir /nginx/run vim /nginx/conf/nginx.conf pid /nginx/run/nginx.pid; # 创建nginx服务脚本 vim /usr/lib/systemd/system/nginx.service [Unit] Description=nginx - high performance web server Documentation=http://nginx.org/en/docs/ After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] Type=forking PIDFile=/nginx/run/nginx.pid ExecStart=/nginx/sbin/nginx -c /nginx/conf/nginx.conf ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID LimitNOFILE=100000 [Install] WantedBy=multi-user.target # 重载服务脚本 systemctl daemon-reload systemctl start nginx Nginx 命令 1 2 3 4 5 6 7 # 检查配置文件语法，并测试配置文件 nginx -t nginx -g \u0026#34;worker_processes 3;\u0026#34; # 前台运行 nginx -g \u0026#34;daemon off;\u0026#34; 信号\n1 2 3 4 5 6 7 8 stop #立即停止，没处理完的请求也会被立即断开，相当于信号 SIGTERM,SIGINT quit #优雅退出，不再接收新的请求，但己建立的连接不受影响，相当于信号 SIGQUIT reopen #重开一个新的日志文件，日志内容写新文件，相当于信号 SIGUSR1 reload #重新加载配置文件，重新生成worker 进程，不中断正在处理的请求， #己建立的连接按旧配置处理，新连接用新配置处理 #同 systemctl reload nginx SIGUSR2 #平滑升级二进制文件，适用于版本升级 SIGWINCH #优雅的停止工作进程，适用于版本升级 1 2 3 4 5 # 服务端发送 stop 信号，客户端会立即断开 nginx -s stop # 服务端发送 quit 信号，服务器完成传输后退出 nginx -s quit 版本更新 平滑升级 Nginx 的平滑升级是指在不中断服务的情况下进行软件版本或配置文件的更新。通过平滑升级，Nginx 能够在运行时应用新的配置或软件版本，继续处理请求，而不影响现有的连接。\n然而，需要注意的是，平滑升级并不适用于所有场景，特别是在某些配置或软件更改可能导致 不兼容性问题的情况下，在进行平滑升级之前，建议先在测试环境中进行充分的测试。\n1 2 3 4 5 6 7 8 9 10 11 12 13 - 新版本或配置准备： 准备好新版本的 Nginx 可执行文件或配置文件，并确保它们没有问题 - 新版本资源替换旧版本资源： 进行资源替换，此步骤要备份旧版本资源，可以用作回滚 - 发送信号： 使用 nginx -s SIGUSR2，nginx -s reload 等方式向 Nginx 主进程发送重新加载的信号 - 新的工作进程启动： Nginx 主进程接收到重新加载信号后，会启动新的工作进程，并使用新的配置文件或软件版本 - 平滑过渡： 新的工作进程逐渐接管现有的连接。现有的连接会在旧的工作进程中继续处理，而新的连接会由新的工作 进程处理 - 旧的进程退出： 当旧的工作进程不再有活动连接时，它会被关闭 1 2 nginx -V # 查看现有版本配置，完全复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ./configure --with-cc-opt=\u0026#39;-g -O2 -fno-omit-frame pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/build/nginx-DlMnQR/nginx 1.25.0=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix map=/build/nginx-DlMnQR/nginx-1.25.0=/usr/src/nginx-1.25.0-2ubuntu7.1 -fPIC Wdate-time -D_FORTIFY_SOURCE=3\u0026#39; --with-ld-opt=\u0026#39;-Wl,-Bsymbolic-functions flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now -fPIC\u0026#39; - prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log path=/var/log/nginx/access.log --error-log-path=stderr --lock path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body - http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with http_ssl_module --with-http_stub_status_module --with-http_realip_module --with http_auth_request_module --with-http_v2_module --with-http_dav_module --with http_slice_module --with-threads --with-http_addition_module --with http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with http_mp4_module --with-http_random_index_module --with-http_secure_link_module - with-http_sub_module --with-mail_ssl_module --with-stream_ssl_module --with stream_ssl_preread_module --with-stream_realip_module --with http_geoip_module=dynamic --with-http_image_filter_module=dynamic --with http_perl_module=dynamic --with-http_xslt_module=dynamic --with-mail=dynamic - with-stream=dynamic --with-stream_geoip_module=dynamic 1 2 3 4 5 make # 不要执行 make install，make install可能会将旧配置替换 # 库文件都是携带版本号的，编译的时候，很多是不带版本号的，所以创建一个软连接 # 编译会报错，哪个库文件报错，创建哪个不带版本号的软链接 ln -s /usr/lib/x86_64-linux-gnu/libperl.so.5.38 /usr/lib/x86_64-linux-gnu/libperl.so ## --with-http_perl_module=dynamic 1 2 # 确认生成的文件 ls objs/ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 新旧版本切换 # 备份旧执行文件 mv /usr/sbin/nginx /usr/sbin/nginx-1.24 # 应用新执行文件 chmod +x ./objs/nginx cp ./objs/nginx /usr/sbin/ # 为了避免版本兼容性相关的问题，删除启用动态功能模块. rm -rf /etc/nginx/modules-enabled/* # nginx 检测，配置文件可用，版本己更新 nginx -t 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # master进程交接 # 向旧版本master进程发起信号 kill -USR2 26077 # kill -USR2 命令会让 Nginx 主进程通过发送 USR2 信号来启动一个新的主进程，该新主进程会加载新的二进制文件（比如升级后的 Nginx 可执行文件）。 # 新版本master挂再旧版本master下 # 让旧版本master下的工作进程 优雅退出；关闭旧的 woker 进程，新请求交由新的 worker 进程处理 kill -WINCH 26077 # 旧版本woker 进程全部退出，但是旧的master进程依然处于存活状态。 # 旧版本master退出 kill -QUIT 26077 # done # 不直接使用QUIT信号的原因 # QUIT会停止nignx的接收后续请求；新请求也不会交给新的 worker 进程处理 平滑回退 旧版本 master 未退出时进行，kill -QUIT 26077 前发现 nginx 工作异常，开始回滚。\n1 2 3 4 5 6 7 8 9 10 11 12 # 执行文件替换 mv /usr/sbin/nginx /usr/sbin/nginx-1.25 mv /usr/sbin/nginx-1.24 /usr/sbin/nginx # 依然是新版本的nginx提供服务访问 # 拉起旧版本master kill -HUP 26077 # 旧master拉起俩worker # 退出新版本master kill -QUIT 31819 新增第三方模块 --add module=PATH\n--add-dynamic-module\n1 2 3 4 0 准备nginx源码- 如果本地没有源码的话，可以从官网下载一个同版本的nginx源码 1 下载模块 2 编译安装 3 测试效果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ngx_http_upstream_hash_module 实现基于哈希的负载均衡，可以根据请求的某些特征（如URL、请求头等）来计算哈希值，并将请求分发到相应的后端服务器。这有助于实现更智能、更均衡的负载均衡策略。 echo-nginx-module 在Nginx中输出一些信息，可以用来实现简单接口或排错。通过配置该模块，可以在Nginx中直接打印变量值、处理结果等信息，方便开发者进行调试和测试。 WebDAV支持模块 为Nginx添加WebDAV（基于HTTP的远程文件访问协议）支持，使得用户可以通过HTTP协议对服务器上的文件进行上传、下载、删除等操作。 Lua脚本集成模块 允许在Nginx中集成Lua脚本，实现更复杂的请求处理和响应生成逻辑。通过Lua脚本，可以灵活地处理请求参数、访问后端服务、生成响应内容等。 https://github.com/vozlt/nginx-module-vts # 第三方流量监控模块 https://github.com/openresty/echo-nginx-module # echo 模块，可以直接输出 1 2 3 4 5 6 7 8 9 10 11 12 13 # 编译安装时带上 --add-module=/usr/local/echo-nginx-module-0.63 # 编译 make # 替换执行文件 mv /usr/sbin/nginx /usr/sbin/nginx-1.24 chmod +x ./objs/nginx cp ./objs/nginx /usr/sbin/ # 重启服务 systemctl restart nginx nginx 配置 nginx.conf 核心配置\n1 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 # --- 全局配置段 -- user ...; worker_processes ...; ... # --- 事件驱动相关的配置 -- events { ...; } # --- http/https 协议相关配置段 --- http { ...; server { ...; location { ...; } } } # --- mail 协议相关配置段，默认被注释 -- mail { server { ...; } } # --- stream 协议相关配置 -- stream { ...; } 全局配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 user \u0026lt;user\u0026gt; [group]; # 指定worker 进程运行时的用户和组，默认值为 nobody worker_processes auto|N; # worker 进程数量 worker_cpu_affinity auto|cpumask; # 绑定CPU核心 # 几个CPU几个0 # 双核：01 10 # 四核：0001 0010 0100 1000 pid /path/file; # pid 文件路径 worker_priority N; # worker 进程优先级，默认值为0 # 此处设定的是 nice 值，取值为 -20 到 19 worker_rlimit_nofile N; # 所有worker进程可以打开的文件描述符数量之和，默认不限制 # 此值并不仅仅是指nginx 与客户端的连接数，包括与后端服务的连接数 daemon on|off; # 默认值为on, 表示以后台守护进程方式运行，off 表示前台运行 master_process on|off; # 默认值为on, 表示以 master-worker 模式运行，off 只有master进程，用于开发调试 include /path/file; # 文件包含,指定要包含的文件路径及规则，可以使用通配符 evnets 配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 events { worker_connections N; # 默认值512，单个worker进程所支持的最大并发连接数 multi_accept on|off; # 默认值 off，on 表示worker 进程一次可以接收多个新的连接请求 accept_mutex on|off; # 默认值 off，表示master 进程获得客户端请求后， # 会通知所有的worker 进程，由当前状态最佳的worker进程处理请求； # 此过程也被称为 惊群。多个worker同时竞争致性能问题 # on 表示 master 进程轮流给 worker进程分配要处理的连接，此处建议设置为 on use method; # 指定事件驱动模型,默认不设置此项，nginx 会根据当前系统自行选择 # 可用值 select|pool|kqueue|epoll|/dev/poll|eventport } http 配置 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 http { charset charset|off; # 是否在响应头 Content-Type 行中添加字符集，默认 off # 中文字符集 utf-8 sendfile on|off; # 默认值 off，on表示使用 sendfile 函数来传送数据,即零拷贝 # on：在文件描述符之间传输数据，不需要在用户态和内核态之间反复切换。静态文件的高效传输 # 零拷贝技术，数据不经过用户缓冲区 # 1. sendfile 将静态数据直接从内核缓冲区发出 # 2. 内存映射（Memory Mapping，mmap）将内核空间地址映射到用户空间，这就可用直接处理内核空间的数据 tcp_nopush on|off; # 默认值 off。减少 TCP 数据包的分片，提升传输效率。将小数据合并 tcp_nodelay on|off; # Nagle 算法 相关的配置项，主要用于优化小数据包的发送。 # off：小数据包延迟0.2秒发送 # on：禁用 Nagle 算法。小数据包会立即发送，无需等待缓冲区填满或接收到ACK。 # tcp_nopush与tcp_nodelay同时开启时，小数据包会被合并，0.2秒后一起发送 keepalive_timeout timeout [header_timeout]; # 会话保持的时长，单位为秒，第二个值会出现在响应头中，可以和第一个值不一样 keepalive_requests number; # 一次请求不断开连接的情况下最多可以传送多少个资源 # 默认值 keepalive_requests 1000; types_hash_max_size N; # 默认值1024，用于设置 MIME 类型哈希表大小 server_tokens on|off|build|string; # 默认值on，是否在响应头中显示 nginx 信息，off 表示不显示 server_names_hash_bucket_size N; # 默认值32|64|128，服务器名哈希桶大小，当配置了大量虚拟主机时， #此项可用来提升性能 server_name_in_redirect on|off; # 默认值off,表示在重定向时响应头中不包含 Server行 # on 表示显示 Server 头 include /etc/nginx/mime.types; # #规定了各种后缀文件在响应报文中的 Content-Type 对应的值 default_type application/octet-stream; # 除了上述映射外，其它类型文件都用此值 ssl_protocols [SSLv2] [SSLv3] [TLSv1|.1|.2|.3]; # 当前nginx 可支持的 ssl协议版本 ssl_prefer_server_ciphers on|off; # 默认off，表示在 SSL/TLS 握手时优先使用客户端加密套件 access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; error_log file [level]; error_page code ... [=[response]] uri; # 定义指定状态码的错误页面，可以多个状态码共用一个资源 # 压缩配置 gzip on|off; gzip_vary on|off; #在启用了压缩的情况下，是否在响应头中添加 Vary: Accept-Encoding 行，默认off gzip_proxied off|expired|no-cache|no-store|private|no_last_modified|no_etag|auth|any ...; gzip_comp_level N; gzip_buffers number size; gzip_http_version N; gzip_min_length length; # 资源体积多大才启用压缩，默认20， gzip_types mime-type ...; # 根据 MIME 来决定是否对数据进行压缩,默认值text/html # 站点配置 server { ... } # 见下文 } http 中 server 配置 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 server { listen address[:port] [default_server] [ssl]; listen port [default_server] [ssl]; listen unix:path [default_server] [ssl]; # default_server：将当前 server 块设置为默认服务器，处理未匹配任何 server_name 的请求。 # ssl：启用 SSL/TLS（HTTPS）支持 ssl_certificate file; ssl_certificate_key file; ssl_session_cache off|none|[builtin[:size]] [shared:name:size]; # 是否启用 ssl 缓存，默认 none ssl_session_timeout N; # 客户端连接可以复用 ssl session cache 中缓存的有效时长，默认5m ssl_ciphers ciphers; # 指定 SSL/TLS 加密算法，默认值 HIGH:! aNULL:! MD5; ssl_prefer_server_ciphers on|off; # 默认 off，表示在 SSL/TLS 握手时优先使用客户端加密套件， # on 表示优先使用服务端套件 server_name example.com; # 虚拟主机域名，可以写多个值，客户端请求头中的 Host 字段会与此处匹配 # 默认值是 \u0026#34;\u0026#34;，用来匹配请求头中 Host 字段值为空的请求 # 还可以写成 _,@ 等用来表示无效域名，和 listen 中的 default_server 配合 root /nginx/html; # 当前虚拟主机网页文件目录，写在 location 中，文件路径是 root+location index index.html index.htm; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 server { listen 80 default_server; server_name www.a.com; root /data/server/nginx/web1; } server { listen 80; server_name www.b.com; root /data/server/nginx/web2; } server { listen 80; server_name www.c.com; root /data/server/nginx/web3; } server 中 Location配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Location / { ... } Location /string { ... } Location [ = | ~ | ~* | ^~ ] uri { ... } # = ：精确匹配。 # ~ ：区分大小写的正则匹配。 # ~* ：不区分大小写的正则匹配。 # ^~：优先的前缀匹配（用于关闭正则匹配）。 Location @name { ... } # 定义一个 name 的动作，供调用 error_page 404 = @not_found; location @not_found { return 404 \u0026#34;Custom 404 Page Not Found\u0026#34;; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Location { alias path; # 定义路径别名，把访问路径重新映射到其它目录 root path; # 定义网站在文件系统上的家目录 index file ...; return code [text]|code URL|URL; # 直接给客户端返回状态码+字符串或 URL proxy_pass URL; # 设置反向代理，将符合规则的请求转发到后端服务器进行处理 fastcgi_pass address; fastcgi_index name; fastcgi_param parameter value [if_not_empty]; deny address|CIDR|unix:|all; # 拒绝访问的客户端，黑名单 allow address|CIDR|unix:|all; # 允许访问的客户端，白名单，可以是具体 IP try_files file ... uri|file ... = code; # 按顺序查询文件是否存在，并返回匹配到的信息 } url匹配 匹配优先级\n当多个 location 指令可能匹配同一个 URI 时，Nginx 会按照以下顺序选择最优的匹配规则：\n精确匹配 (=)： 如果找到了精确匹配，则立即使用。 普通前缀匹配： 如果 URI 匹配多个普通前缀，选择最长匹配的前缀。 优先前缀匹配 (^~)： 如果 URI 匹配了 ^~ 前缀规则，则立即使用此规则，不再继续检查正则匹配。 正则匹配 (~ 和 ~\\*)： 如果没有精确匹配或优先前缀匹配，则检查正则规则，并选择第一个匹配的规则。 默认前缀匹配： 如果没有匹配到任何规则，使用默认的前缀匹配（通常是 location /）。 精确匹配 (=) 1 2 3 location = /login { return 200 \u0026#34;This is the login page.\u0026#34;; } 请求 /login：匹配此规则。 请求 /login/ 或 /login.html：不会匹配此规则。 正则匹配 (~ 和 ~*) 1 2 3 location ~ \\.php$ { fastcgi_pass 127.0.0.1:9000; } 请求 /index.php：匹配。 请求 /INDEX.PHP：不匹配。 1 2 3 4 ocation ~* \\.(jpg|jpeg|png|gif|ico)$ { expires max; log_not_found off; } 请求 /image.JPG 或 /image.jpg：匹配。 请求 /image.TXT：不匹配。 优先前缀匹配 (^~) 1 2 3 location ^~ /static/ { root /var/www/static; } 请求 /static/css/style.css：匹配此规则，且不会再检查其他正则规则。 请求 /dynamic/script.php：不匹配此规则，会继续检查其他规则。 root \u0026amp; alias 1 2 3 4 5 6 7 8 9 10 11 location /img/ { alias /var/www/image/; } # http://localhost/img/，nginx 找/var/www/image/目录下的文件 location /img/ { root /var/www/image; } # http://localhost/img/，nginx 找/var/www/image/img/目录下的文件 # 一般情况下，在 location /中配置 root，在 location /other 中配置 alias 访问控制 配合正则\n在上面的规则更强\n1 2 3 4 5 6 7 location /web3/ { alias /data/server/nginx/web3/; allow 127.0.0.1; # 放行 127.1 deny 10.0.0.13; # 拒绝 10.0.0.13 allow 10.0.0.0/24; # 放行 10.0.0.0/24 所有 IP，但 10.0.0.13 在上一条被拒绝 deny all; } 错误页面，重定向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 server { listen 80 default_server; error_page 400 502 503 504 error.html; location = /error.html { root /data/server/nginx/errors/; } location = /error2.html { # 通过 302 临时重定向到 index.hmtl error_page 400 404 = 302 /index.html; } error_page 404 @error; location @error { default_type text/html; return 200 \u0026#34;page not found\\n\u0026#34;; } } try_files url条件判断 1 2 3 4 5 6 7 8 9 10 server { listen 80 default_server; try_files $uri $ uri.html $uri/index.html /index.html; # 如果有 web1 或 web1.html 会匹配到，返回状态码是 200，如果没有则返回 404 错误页面 location /web1 { try_files $uri $ uri.html = 404; } } 内置变量 Nginx 变量可以在配置文件中使用，用作判断或定义日志格式等场景，Nginx 变量可以分为内置变量和自定 义变量两种\n1 2 # 自定义变量 set $variable value; 请求相关变量\n变量 描述 示例值 $remote_addr 客户端的公网 IP 地址。 203.0.113.1 $proxy_add_x_forwarded_for 包含代理链中的所有 IP（由 X-Forwarded-For 添加的 IP 列表）。 203.0.113.1, 192.168.1.1 $remote_port 客户端的随机端口号。 52345 $remote_user 通过 HTTP Basic Auth 验证的用户名（如果启用认证）。 admin $request_method 客户端请求的 HTTP 方法。 GET、POST、DELETE $request_uri 完整的请求 URI，包括参数。 /index.html?user=admin $document_uri 不包含参数的 URI。 /index.html $args 请求 URL 中的所有参数。 user=admin\u0026amp;action=delete $is_args 是否有参数，值为 ?（有参数）或为空（无参数）。 ? 或空 $http_user_agent 客户端的 User-Agent 信息。 Mozilla/5.0 $http_cookie 请求头中的所有 Cookie。 session=abc123; user=admin $cookie_\u0026lt;name\u0026gt; 获取指定的 Cookie 值。 $cookie_session -\u0026gt; abc123 $arg_\u0026lt;name\u0026gt; 获取指定的 URL 参数值。 $arg_user -\u0026gt; admin $http_\u0026lt;name\u0026gt; 获取指定请求头字段的值，字段名中的 - 替换为 _。 $http_x_forwarded_for -\u0026gt; 203.0.113.1 服务器相关变量\n变量 描述 示例值 $server_addr 服务器的 IP 地址。 192.168.1.100 $server_name 服务器的主机名。 example.com $server_port 服务器监听的端口号。 80 或 443 $scheme 请求的协议（HTTP/HTTPS）。 http 或 https $server_protocol 客户端请求的协议版本（HTTP/1.0、HTTP/1.1、HTTP/2.0）。 HTTP/1.1 $document_root 当前资源在服务器文件系统上的根目录。 /var/www/html $request_filename 当前资源在文件系统上的完整路径。 /var/www/html/index.html 响应相关变量\n变量 描述 示例值 $sent_http_\u0026lt;name\u0026gt; 获取指定响应头字段的值，字段名中的 - 替换为 _。 $sent_http_content_type -\u0026gt; text/html 限速，限制客户端并发连接数，请求限制 目前 Nginx 中主要的三种限速操作分别是：限制请求数（request），限制连接数 （connection），限制响应速度（rate），对应在 Nginx 中的模块指令分别是 limit_req， limit_conn 和 limit_rate 三部分。\n1 2 3 4 limit_rate rate; #对单个客户端连接限速，默认单位为字节，其它单位需要显式指定， #表示每秒的下载速度，限速只对单一连接而言，同一客户端两个连接， #总速率为限速 2 倍，默认值 0，表示不限制 limit_rate_after size; #在传输了多少数据之后开始限速，默认值 0，表示一开始就限速 限制客户端并发连接数\n1 2 3 4 5 6 7 8 limit_conn_zone key zone = name: size; # 定义一个限速规则，供 limit_req 指令调用 limit_conn zone number; # zone 表示要调用的规则，number 表示要限制的连接数，不能写变量 # 定义一个名为 perip 的共享内存区域，用于存储基于客户端二进制 IP 地址的连接状态，内存大小为 10MB。 limit_conn_zone $binary_remote_addr zone = perip: 10m; # 限制每个客户端最多允许 20 个并发连接。 limit_conn perip 20; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 limit_conn_zone \\$binary_remote_addr zone = mylimit: 10m; server { listen 80 default_server; root /data/server/nginx/web1; location /100M.img { limit_rate 10k; #每秒下载速度为 10K limit_rate_after 1m; #前 1M 不开启限速 } location /200M.img { limit_rate 10k; #每秒下载速度为 10K limit_conn mylimit 2; #限制每个客户端最多允许 2 个并发连接。 } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 定制 mylimit 内存区域，用于存储客户端二进制 IP 地址的连接状态，内存大小为 10MB。限制每秒请求数为 2 个。 # 2r/s，也就是说 nginx 在 500ms 里面可以处理 1 个请求 limit_req_zone \\$binary_remote_addr zone = mylimit: 10m rate = 2r/s; server { listen 80 default_server; root /data/server/nginx/web1; location / { limit_req zone = mylimit burst = 5 nodelay; # 调用请求规则 # burst = 5：允许额外的 5 个突发请求。 # nodelay：立即处理突发请求，不引入额外延迟。 } } Https 1 2 3 4 5 6 7 8 9 10 11 12 13 ssl on|off; ssl_buffer_size size; # 在读取和写入 SSL/TLS 握手数据时使用的缓冲区大小，无关数据发送，默认值 16k ssl_certificate file; # 虚拟主机的证书和 CA 机构的证书 ssl_certificate_key file; # 私钥 ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3]; ssl_session_cache off|none|[builtin[: size]] [shared:name:size]; # 配置 SSL 缓存 ssl_session_timeout time; # 配置 SSL/TLS 会话缓存的超时时间，默认值 5m 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 server { listen 443 default_server ssl; server_name l00n9.icu; ssl_certificate /nginx/conf/ssl/cert.pem; ssl_certificate_key /nginx/conf/ssl/secret.key; ssl_session_cache shared: SSL: 1m; ssl_session_timeout 5m; ssl_ciphers HIGH:! aNULL:! MD5; ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } } 防盗链 Referer头信息，告 诉服务器我是从哪个页面链接过来的。\n1 2 3 4 5 6 7 location ~* \\.(jpg|jpeg|png|gif|mp4|webp)$ { valid_referers none blocked yourdomain.com *.yourdomain.com partner.com; if ($invalid_referer) { return 403; } } Rewrite 模块 rewrite 指令用于重写 URI，允许 Nginx 修改客户端请求的 URI\n模块指令\n1 2 3 4 5 6 7 8 9 10 11 12 break; # break 命令之后，ngx_http_rewrite_module 模块其他指令则不再生效，比如 set 和 return return code [text]; return code URL; return URL; # 不写 code ，默认值为 302 # 直接向客户端返回状态码，字符串，或者 URL， # 如果返回的字符串中包含空格，要加引号，如果返回 URL，要写完整 # 此指令后的其它指令或配置将不再执行，作用域 server, location, if set $variable value; if 条件判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 if (condition) { ... } # if 指令仅能做单次判断，不支持 if else 多分支 # 支持的运算符 # = 比较变量和字符串是否相等 # != 比较变量和字符串是否不相等 # ~ 区分大小写，是否匹配正则，包含 # !~ 区分大小写，是否不匹配正则，包含 # ~* 不区分大小写，是否匹配正则，包含 # !~* 不区分大小写，是否不匹配正则，不包含 # -f|!-f 判断文件是否存在|不存在 # -d|!-d 判断目录是否存在|不存在 # -x|!-x 判断文件是否可执行|不可执行 # -e|!-e 判断文件(包括文件，目录，软链接)是否存在|不存在 1 2 3 4 5 6 7 8 9 10 server { listen 80 default_server; root /data/server/nginx/web1; location /file { if (!-e \\$request_filename){ return 200 \u0026#34;\\$request_filename 文件不存在\u0026#34;; } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 server { listen 80 default_server; root /data/server/nginx/web1; location /noslow.img { break; set $slow 1; if ($slow) { limit_rate 10k; } } location /slow.img{ set $slow 1; if ($slow) { limit_rate 10k; } } } 重定向 1 rewrite regex replacement [flag]（可选）; 常用的 rewrite 标志包括：\n标志 含义 last 停止当前 location 的处理，重新开始新的匹配（类似于内部重定向）。改完url，去找新匹配到的location。 break 停止重写，不进行其他的 rewrite 或规则处理，但继续在当前 location 内处理请求。\n改完url，继续在当前location。 redirect 返回 302 临时重定向，告知客户端重新发起请求（URL 替换时会包含完整域名）。 permanent 返回 301 永久重定向，告知客户端新的 URL 是永久有效的（更适合 SEO）。\n客户端应该将其缓存并在未来访问新地址。 反向代理 正向代理（Forward Proxy）\n正向代理是一个代理服务器，位于客户端与目标服务器之间，为客户端提供代理服务。\n客户端通过正向代理间接访问目标服务器。\n用途：\n突破访问限制：用于绕过网络访问限制，访问受限制的资源\n隐藏客户端身份：客户端可以通过正向代理隐藏其真实 IP 地址\n缓存加速： 正向代理可以缓存一些常用资源，提升访问速度。\n内容过滤： 如企业对员工访问的网络内容进行控制。\n反向代理（Reverse Proxy）\n反向代理是一个代理服务器，位于客户端与目标服务器之间，为服务器提供代理服务。 客户端不知道目标服务器的实际地址，所有请求都由反向代理转发。 用途： 负载均衡： 将客户端请求分发到多个后端服务器，提升性能和可靠性。 隐藏服务器身份： 客户端无法直接接触后端服务器，增强安全性。 SSL卸载： 反向代理可以处理SSL加密，减少后端服务器的负担。 缓存加速： 缓存静态资源，减少后端服务器负载。 安全防护： 提供防火墙功能，过滤恶意流量 Nginx 和 LVS（Linux Virtual Server） 都是流行的代理和负载均衡解决方案，但它们有一些不 同的特点和应用场景。 选择使用 Nginx 还是 LVS 取决于具体的应用需求和复杂度。Nginx 更适合作为 Web 服务器和应用 层负载均衡器，而 LVS 更适用于传输层负载均衡。\n特性 Nginx LVS 工作层次 应用层（L7） 传输层（L4） 协议支持 HTTP、HTTPS、WebSocket 等 TCP、UDP 性能 优秀，适合中等流量 极高，适合大规模流量 负载均衡算法 丰富（轮询、最少连接、IP 哈希等） 较简单（IP 哈希、加权等） 健康检查 支持复杂的健康检查（主动和被动） 依赖外部工具（如 Keepalived） SSL 支持 支持 SSL 卸载 不支持 配置难度 简单，易于上手 复杂，需深入理解内核和网络 典型应用场景 应用层的 Web 服务负载均衡 大规模高并发服务的四层负载均衡 反向代理配置 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 location{ proxy_pass URL; # 转发的后端服务器地址，可以写主机名,域名，IP地址，端口 proxy_pass_header field; # 显式指定要回传给客户端的后端服务器响应头中的字段 proxy_pass_request_body on|off; # 是否向后端服务器发送客户端 http 请求的body proxy_pass_request_headers on|off; # 是否向后端服务器发送客户端 http 请求的头部信息 proxy_hide_header field; # 指定不回传的响应头字段 proxy_connect_timeout time; # Nginx与后端服务器建立连接超时时长 proxy_read_timeout time; # 等待后端服务器返回数据的超时时长 proxy_send_timeout time; # Nginx 向后端服务器发送请求的超时时长 proxy_set_body value; # 重新定义传给后端服务器的请求的正文 proxy_set_header field value; # 更改或添加请求头字段并发送到后端服务器 proxy_http_version 1.0|1.1; # proxy_ignore_client_abort on|off; # 客户端中断连接，Nginx 是否继续执行与后端的连接 proxy_headers_hash_bucket_size size; # 设置nginx保存HTTP报文头的hash表的大小，默认值 64 proxy_headers_hash_max_size size; # hash表的大小上限，默认值 512 proxy_next_upstream error|timeout|invalid_header|...| off ...; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 server { listen 80 default_server; root /data/server/nginx/web1; location / { proxy_pass http://10.0.0.13:81; # 交给后端的81端口服务 proxy_connect_timeout 2s; # 设置连接超时时间为2s } location /1 { proxy_pass http://10.0.0.13:88; # 交给后端的81端口服务 } } server { listen 81 default_server; root /data/server/nginx/web2; access_log /var/log/nginx/access_client.log; } # 如果后端服务不可用，从客户端访问会返回502 # 如果连接后端服务器超时，会报504 动静分离 Nginx的动静分离是一种在Web服务器架构中优化资源处理和提高系统性能的方法。\n动静分离是指将Web 服务器上的静态页面与动态页面或者静态内容接口和动态内容接口分开，由不同的系统或服务器进行处理。这 样做的目的是提升整个服务访问的性能和可维护性。\n代理缓存 Nginx代理缓存允许Nginx作为反向代理服务器时，缓存从后端服务器获取的资源（如网页、文件等）。\n当客户端请求这些资源时，Nginx会首先检查缓存中是否存在对应的资源。\n如果缓存命中，Nginx将直接返回 缓存中的资源，而无需再次向后端服务器发起请求。这样可以显著减少后端服务器的负载，提高网站的响应速 度和用户体验。\n1 2 3 4 5 6 7 8 9 10 11 12 proxy_cache zone|off; # 是否启用代理缓存 proxy_cache_path path [args]; # 开启代理缓存后指定缓存数据的存放路径 proxy_cache_key string; # 指定缓存数据的key，不同的key 对应不同的缓存文件 # 默认$scheme$proxy_host$request_uri proxy_cache_valid [code ...] time; # 为不同响应状态码的数据设置不同的缓存时长 proxy_cache_use_stale error|timeout|invalid_header|...|off ...; # 在后端服务器报哪些错误的情况下，直接使用过期缓存数据响应请求 proxy_cache_methods GET|...; # 缓存哪些请求类型的数据，默认值 GET HEAD 1 2 3 4 proxy_cache_path /tmp/proxycache levels=1:2 keys_zone=proxycache:20m inactive=60s max_size=1g; # 这条proxy_cache_path指令配置了一个名为/tmp/proxycache的缓存目录，具有两级目录结构， # 一个20MB的内存区域用于存储缓存键和元数据，缓存项在不活跃60秒后可以被删除，并且整个缓存目录的最大大小为1GB。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 proxy_cache_path /tmp/proxycache levels=1:2 keys_zone=proxycache:20m inactive=60s max_size=1g; server { listen 80 default_server; server_name sswang.magedu.com; root /data/server/nginx/web1; location /static { rewrite ^/static(.*)$ /index.html break; # 重写url proxy_pass http://10.0.0.14; proxy_set_header Host \u0026#34;static.magedu.com\u0026#34;; proxy_cache proxycache; proxy_cache_key $request_uri; proxy_cache_valid 200 302 301 90s; proxy_cache_valid any 2m; } } 1 2 3 4 5 # Apache Benchmark 模拟并发访问 ab -c 100 -n 10000 -H \u0026#34;sswang.magedu.com\u0026#34; 10.0.0.13/static+ # -c 100 并发数 # -n 10000 总请求数 IP透传 （IP透明传输） 1 2 3 4 5 # 记录代理服务器前一个IP proxy_set_header X-Real-IP $remote_addr; # 记录所有IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 其他代理 stream 代理 ngx_stream_proxy_module 是 Nginx 的一个模块，用于实现 TCP 和 UDP 协议的代理功能。这个模块使得 Nginx 能够作为 流量代理 来转发 TCP 和 UDP 流量，而不仅仅是 HTTP 流量。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 stream { upstream mysqlserver{ server 10.0.0.16:3306; } upstream redisserver{ server 10.0.0.14:6379; } server{ listen 3306; proxy_pass mysqlserver; } server{ listen 6379; proxy_pass redisserver; } } FastCGI代理 1 2 3 4 5 6 fastcgi_index name; # 后端 FastCGI 服务器默认资源，默认值为空 fastcgi_pass address; # 指定后端 FastCGI 服务器地址，可以写 IP:port，也可以指定socket 文件 fastcgi_param parameter value [if_not_empty]; # 设置传递给FastCGI服务器的参数值， 1 2 3 4 5 6 location ~ \\.php$ { root /nginx/html/wordpress; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } 负载均衡 负载均衡 是一种分布式计算技术，用于将网络流量和用户请求分散到多台服务器上，以此来提高网络服务的可用性和可 靠性。 它通过优化资源使用、最大化吞吐量以及最小化响应时间，增强了网络、服务器和数据中心的伸缩性和 灵活性。\nNginx的负载均衡功能主要通过其反向代理模式实现。当客户端发送请求到Nginx服务器时， Nginx会根 据预设的负载均衡策略将请求转发给后端服务器，并将后端服务器的响应返回给客户端。 Nginx作为代理服务 器，有效地分摊了请求压力，提高了系统的处理能力。\n1 2 3 4 5 6 upstream name { [...] server address [parameters]; server address [parameters]; ...... } [\u0026hellip;]\n1 2 3 4 5 6 7 8 9 10 hash key [consistent]; # 使用自行指定的 Key 做 hash 运算后进行调度 # consistent 表示使用一致性 hash,最大限度地减少了服务器变动 ip_hash; # 源地址hash调度方法,基于的客户端的remote_addr做hash least_conn; # 最少连接调度算法，优先将客户端请求调度到当前连接最少的后端服务器 keepalive connections; # 配置与后端服务器的 长连接数量 keepalive_time time; # 保持活动连接的超时时间 parameters\n1 2 3 4 5 6 7 8 9 10 weight=number # 指定该 server 的权重，默认值都是1 max_conns=number # 该 Server 的最大活动连接数，达到后将不再给该 Server 发送请求， # 可以保持的连接数=代理服务器的进程数乘以max_conns,默认值0，表示不限制 max_fails=number # 后端服务器的下线条件,后端服务器连续进行检测多少次失败,而后标记为不可用，默认为1 # 当客户端访问时，才会利用TCP触发对探测后端服务器健康性检查，而非周期性的探测 fail_timeout=time # 负载均衡池中被 排除的时间，超时后再次进行健康检查。默认为10秒 backup # 标记该 Server 为备用，当所有后端服务器不可用时，才使用此服务器 down # 标记该 Server 临时不可用，可用于平滑下线后端服务器， # 新请求不再调度到此服务器，原有连接不受影响 Round-Robin 轮流调度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 upstream group1 { # 定制一个 三比一 的权重负载效果 server 10.0.0.16 weight=3; server 10.0.0.15 backup； server 10.0.0.14 max_conns=2; server 10.0.0.14 down; # 新请求不再调度到此服务器，原有连接不受影响 } server { listen 80 default_server; location / { proxy_pass http://group1; } } 为客户端提供服务的服务器一直变动，不利于会话保持。\n源IP哈希 解决会话保持的问题。\n1 2 3 4 5 6 7 8 9 10 11 12 upstream group1 { ip_hash; server 10.0.0.16; server 10.0.0.14; } server { listen 80 default_server; location / { proxy_pass http://group1; } } 但服务器变动时，会话还是保持不了。\n一致性哈希 一致性哈希可以确保即使增加或删除后端服务器，也不会大量影响已存在的请求。\n减少在后端服务器变动时，流量重新分配的影响。\n哈希值会被映射到一个虚拟环（哈希环）上，并根据这个哈希值决定将请求路由到哪个后端服务器。\n1 2 3 4 5 6 7 8 9 10 在一致性哈希中，所有可能的数据节点或服务器被映射到一个虚拟的环上。这个环的范围通常是一个固定的哈希空间， 比如0到2^32-1，每个数据节点或服务器被映射到环上的一个点，通过对其进行哈希计算得到。这个哈希值的范围也是在0到2^32-1之间。 在这个环上，数据会被分散到最接近它的节点。当有新的数据要存储时，首先通过哈希计算得到该数据的哈希值， 然后在环上找到离这个哈希值最近的节点，将数据存储在这个节点上。同样，当要查询数据时，也是通过哈希计算得到数据的哈希值，然后找到最近的节点进行查询。 由于哈希环是一个环形结构，节点的添加和删除对整体的影响相对较小。当添加或删除节点时， 只有相邻的节点受到影响，而其他节点保持不变。这使得一致性哈希算法在分布式系统中能够提供较好的负载均衡性能，同时减小了数据迁移的开销。 总的来说，一致性哈希中的哈希环是通过哈希计算将数据节点映射到环上，以实现数据分片和负载均衡的分布式算法。 1 2 3 4 5 6 7 8 9 10 upstream backend { hash $request_uri consistent; # 一致性哈希，基于请求的 URI least_conn; # 最少连接调度算法 keepalive 32; # 与后端服务器保持 32 个长连接 keepalive_time 60s; # 保持活动连接的时间为 60 秒 server 192.168.1.1; server 192.168.1.2; server 192.168.1.3; } 一致性hash算法：扩容前 一致性hash算法：扩容后 环偏移\n1 2 3 在一致性哈希中，哈希环可能会面临的一个问题是环偏移（Ring Wrapping）。环偏移指的是哈希环上的某个区域过于拥挤，而其他区域相对空闲，这可能导致负载不均衡。为了解决这个问题，一些改进的一致性哈希算法引入了虚拟节点（Virtual Nodes）的概念。 虚拟节点是对物理节点的一种扩展，通过为每个物理节点创建多个虚拟节点，将它们均匀地分布在哈希环上。这样一来，每个物理节点在环上的位置会有多个副本，而不是只有一个位置。这样一来，即使哈希环上的某个区域过于拥挤，也可以通过调整虚拟节点的数量来使得负载更均衡 最少连接数算法 1 least_conn; upstream_zone模块；跨worker进程生效负载均衡 之前所有的负载均衡算法都默认只在一个worker进程生效\nngx_http_upstream_zone_module\n使用共享内存使负载均衡策略对所有worker进程生效:upstream_zone模块\n1 2 3 4 5 6 upstream backend { zone backend_zone 64k; # 创建名为 backend_zone 的共享内存区，大小为64K server backend1.example.com; server backend2.example.com; # ...其他配置如权重、失败重试等 } ","date":"2024-12-10T00:00:00Z","permalink":"https://www.l00n9.icu/p/nginx/","title":"NGINX"},{"content":"DNS，Domain Name System (域名系统) 概念 DNS用于维护主机IP与域名映射关系，域名解析。\n将域名转化为IP地址。\n查询顺序 检查本地缓存 检查 /etc/hosts 文件 DNS 查询 可通过/etc/nsswitch.conf文件调整\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 root@loong:~# cat /etc/nsswitch.conf # /etc/nsswitch.conf # # Example configuration of GNU Name Service Switch functionality. # If you have the `glibc-doc-reference\u0026#39; and `info\u0026#39; packages installed, try: # `info libc \u0026#34;Name Service Switch\u0026#34;\u0026#39; for information about this file. passwd: files systemd group: files systemd shadow: files systemd gshadow: files systemd hosts: files dns\t# 先files 再dns networks: files protocols: db files services: db files ethers: db files rpc: db files netgroup: nis hosts文件 hosts文件是引入DNS服务之前的解析方案\n将域名与IP写入文件\n系统管理员可以将常用的域名和 IP 地址手动写入 /etc/hosts，跳过 DNS 查询。\n1 2 3 4 Windows系统中的hosts文件： %windir%\\System32\\drivers\\etc\\hosts - %windir% 是windows 系统中的环境变量写法，表示 Windows 安装目录，上述路径一般是 C:\\Windows\\System32\\drivers\\etc 1 2 3 4 5 6 7 8 9 10 11 12 13 Linux系统中的hosts文件 /etc/hosts root@loong:~# cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 loong # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters Domain Name 域名 域名分层级。每层用.隔开。\n最上层为顶级域（一级域），之后二级域\u0026hellip;\u0026hellip;\n最上层是根域.（一个点），通常省略\nFQDN：(Fully Qualified Domain Name)全限定域名\n1 2 3 4 5 6 7 8 9 10 11 根域： 全球共有13组IPV4根域名服务器，其中10组在美国，2组在欧洲（英国，瑞典），1组在亚洲（日本） 一级域名： 又称顶级域名，可分为三类，一类代表国家和地区(cn，hk，......)，一类代表各类组织(com， edu，......)，以及新顶级域名（如.xyz、.top等）或其他特殊顶级域名（包括一些基础设施顶级域名 和.arpa用于逆向域名解析，以及国际化域名允许使用非ASCII字符） 二级域名： 某个具体组织，单位，机构，商业公司或个人使用，需要向域名管理机构申请(付费)才能获得使用权 二级域名以下的域名，由使用该域名的组织自行分配 IPV4根域名服务器13组（1主12辅）。Anycast技术，做到多台服务器共用一个IP，直接找最近的。\n13根服务器的原因 为了使数据包不在网络层分片（效率低）。标准UDP数据包的最大有效载荷为 512字节。\n​\t当DNS报文的大小超过512字节时，如果仍然使用UDP进行传输，那么报文将被截断，导致查询失 败。所以DNS协议规定在数据量超过512字节时，应使用TCP协议进行传输，而不是UDP来传输报文，因为TCP 允许传输更大的数据包而不需要分片。\n应答DNS数据包\n1 2 3 4 5 6 7 8 9 10 11 12 13 Head：\t12字节 Question：\t5字节 * 1 （一问） = 5字节 13个A记录（Address）：\t16字节 * 13 = 208 字节 13个NS记录（Name Sever） 31字节 + 15字节（压缩后）* 12 （其余12条NS）= 180字节 总共\t436字节 剩余\t512 - 436 = 76字节 加新根需要\t15 + 16 = 31字节 现实中的约束\n早期根域名服务器还支持 .com、.net. 等顶级域名的查询功能（Priming查询），需要额外的空间来存储其 QNAME 信息。由于这种查询方式需要预留额外的 64 字节空间，因此：\n可用空间：76 - 64 = 12 字节。 12 字节不足以容纳新根服务器的记录。 结论：根服务器数量的实际限制是 13 台。 DNS报文 DNS 报文分为 请求 和 应答 两种，结构是类似的，大致分为五部分：\n头部（ header ），描述报文类型，以及其下 4 个小节的情况；固定12字节； 问题节（ question ），保存查询问题； 答案节（ answer ），保存问题答案，也就是查询结果； 授权信息节（ authority ），保存授权信息；权威DNS服务器的信息 附加信息节（ additional ），保存附加信息； 头部 标识（ identifier ），一个 16 位的 ID ，在应答中原样返回，以此匹配请求和应答； 标志（ flags ），一些标志位，共 16 位； 问题记录数（ question count ），一个 16 位整数，表示问题节中的记录个数； 答案记录数（ answer count ），一个 16 位整数，表示答案节中的记录个数； 授权信息记录数（ authority record count ），一个 16 位整数，表示授权信息节中的记录个数； 附加信息记录数（ additional record count ），一个 16 位整数，表示附加信息节中的记录个数； 标志位：\nQR 位标记报文是一个查询请求，还是查询应答； 0 表示查询请求； 1 表示查询应答； 操作码（opcode）占 4 位，表示操作类型： 0 代表标准查询； 1 代表反向查询； 2 代表服务器状态请求； AA 位表示 权威回答（ authoritative answer ），意味着当前查询结果是由域名的权威服务器给出的； TC 位表示 截短（ truncated ），使用 UDP 时，如果应答超过 512 字节，只返回前 512 个字节； RD 位表示期望递归（ recursion desired），在请求中设置，并在应答中返回； 该位为 1 时，服务器必须处理这个请求：如果服务器没有授权回答，它必须替客户端请求其他 DNS 服务器，这也是所谓的 递归查询 ； 该位为 0 时，如果服务器没有授权回答，它就返回一个能够处理该查询的服务器列表给客户端，由客户端自己进行 迭代查询 ； RA 位表示可递归（ recursion available ），如果服务器支持递归查询，就会在应答中设置该位，以告知客户端； 保留位，这 3 位目前未用，留作未来扩展； 响应码（response code）占 4 位，表示请求结果，常见的值包括： 0 表示没有差错； 3 表示名字差错，该差错由权威服务器返回，表示待查询的域名不存在； 问题 一个问题记录由 3 个字段组成：\n待查询域名（ Name ），这个字段长度不固定，由具体域名决定； 查询类型（ Type ），域名除了关联 IP 地址，还可以关联其他信息，常见类型包括（下节详细介绍）： 1 表示 A 记录，即 IP 地址； 28 表示 AAAA 记录，即 IPv6 地址； etc 类 （ Class ）通常为 1 ，表示 TCP/IP 互联网地址； 应答 回答、权威和附加部分的结构类似，包含DNS服务器返回的资源记录（RR，Resource Record），格式如下：\n字段名称 长度 描述 NAME 可变长度 当前记录适用的域名，通常以压缩格式存储（指针）。 TYPE 16位 记录的类型（如 A、NS、CNAME、MX 等）。 CLASS 16位 记录的类，通常为 IN（互联网）。 TTL 32位 生存时间（秒），表示记录在缓存中存活的时间。 RDLENGTH 16位 数据部分的长度（字节）。 RDATA 可变长度 实际的数据，例如IP地址或域名。 记录的类型：\n原理 迭代查询 客户端逐级向每一级DNS服务器发起查询，请求获得下一步的指引，直到找到最终答案。\n递归查询（缓存服务器） DNS服务器代替客户端完成迭代查询\nDNS地址配置 对应的网卡配置文件中\n/etc/resolv.conf文件中 优先\nrocky中为独立文件，修改后永久保存\nubuntu中为软链接文件，/etc/resolv.conf -\u0026gt; ../run/systemd/resolve/stub-resolv.conf\n由systemd-resolved.service服务管理 重启systemd-resolved.service，或netplan apply后会刷新 1 2 3 4 nameserver 127.0.0.53 options edns0 trust-ad\t# EDNS，DNSsec 相关 search .\t# 自动拼接列表，会非FDQN将域名（不已.结尾）与列表中的值做拼接 ubuntu：/etc/systemd/resolved.conf文件中\nsystemd-resolved服务 resolvectl命令 rocky 安装\n1 yum install -y systemd-resolved 1 2 3 4 5 6 7 8 ## 查看DNS地址配置 resolvectl status ## 查看DNS缓存 resolvectl statistics ## 清理DNS缓存 resolvectl reset-statistics /run/systemd/resolve\n1 io.systemd.Resolve io.systemd.Resolve.Monitor netif resolv.conf stub-resolv.conf 作用 systemd-resolved服务\n缓存 DNS 查询结果，减少重复查询，提高效率。 转发 DNS 查询到上游 DNS 服务器（通过 /run/systemd/resolve/resolv.conf 中配置的 nameserver 条目）。 127.0.0.53#53 本地 DNS 缓存代理服务的地址\n系统的 DNS 查询会首先发送到 127.0.0.53，由 systemd-resolved 代理处理。\nDNS检测命令 dig 贼好用比其他 Domain Information Groper 域名信息查询工具\ndig 命令不会查询本地 hosts文件中定义的域名和IP对应关系\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 dig www.baidu.com ## 指定DNS服务器 dig www.baidu.com @dns-erver dig @dns-erver www.baidu.com ## 反向解析IP dig -x IP ## 指定端口 -p port ## 指定查询类型 -t ## 使用指定IP去查询DNS，一般来说是本地ip地址 -b address#port host 不会查询本地 hosts文件中定义的域名和IP对应关系\n1 2 3 4 5 ## 显示所有信息 host -a wwwbaidu.com ## 指定服务器 host www.magedu.com 114.114.114.114 nslookup 不会查询本地 hosts文件中定义的域名和IP对应关系，也不能查询dns的递归或者迭代\nDNS服务器 bind部署DNS解析服务（named服务） 环境部署\n1 2 3 yum install bind -y\t## 默认不去对外 apt install bind9\t## 默认对外 BIND 的核心进程（named）\nnamed默认会占用TCP和UDP的53端口， 953是给rndc管理工具使用的\n127.0.0.1:53 本地环回自己用\nIP:53 给其他人用\nrndc 管理DNS服务工具 远程管理BIND（Berkeley Internet Name Domain）DNS服务器的工具。\n953/tcp\n1 2 3 4 5 6 7 8 9 10 11 12 常用子命令 status #查看BIND服务状态 reload #重载主配置文件和区域解析库文件 reload zonename #重载区域解析库文件 retransfer zonename #手动启动区域传送，而不管序列号是否增加 notify zonename #重新对区域传送发通知 reconfig #重载主配置文件 querylog #开启或关闭查询日志文件/var/log/message trace #递增debug一个级别 trace LEVEL #指定使用的级别 notrace #将调试级别设置为 0 flush #清空DNS服务器的所有缓存记录 配置文件 rocky 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ## 配置文件，全局选项（options）、日志配置、ACL 规则，也可存放区域定义（zone） /etc/named.conf ## listen-on port 53 { 127.0.0.1; }; 监听地址 ## listen-on-v6 port 53 { ::1; }; ipv6 ## allow-query { localhost; };\t谁可用查询 ### 加上any对外开放 ## listen-on port 53 { 127.0.0.1; any;}; ## listen-on-v6 port 53 { ::1; any;}; ## allow-query { localhost; any;}; ## 专域名条目文件，定义了域名和具体解析规则文件的对应 /etc/named.rfc1912.zones ## 工作目录，存放域解析规则文件 /var/named ubuntu 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ## 配置文件 /etc/bind/named.conf /etc/bind/named.conf.options /etc/bind/named.conf.local /etc/bind/named.conf.default-zones ## options中listen-on-v6为any，开放对外端口 ## 域名条目文件，定义了域名和具体解析规则文件的对应 /etc/bind/zones.rfc1918 ## 工作目录，存放域解析规则文件 /etc/bind /var/cache/bind 解析规则配置 这些文件定义域名的具体解析规则，该文件有多条资源记录组成，每一行都是一条资源记录，在RFC文档 中，DNS解析记录被称为Resource Recode（资源记录），缩写为 RR。\n目录与命名规范 1 2 3 4 5 ## rocky /etc/bind/db.* ## ubuntu /var/named/named.* Resource Record（资源记录） 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Owner：记录的所有者，通常是一个域名。 TTL（Time to Live）：生存时间，指定其他DNS服务器在放弃缓存该记录之前应将其缓存多长时间。 CLASS：类，指示记录所属的类别。最常用的类别是IN（Internet类）。 TYPE：类型，指示记录的类型， A记录\t将域名映射到 IPv4 地址 AAAA记录\t将域名映射到 IPv6 地址 NS记录\t指定域名的权威名称服务器，用于管理该域的 DNS 记录。 PTR记录\t域名指针，用IP地址反向解析域名 SOA记录\t标志权威区域的开始 后接权威 DNS 服务器信息及区域同步参数。 主权威服务器的名称 管理员的邮箱地址 同步参数（Serial, Refresh, Retry, Expire, Minimum TTL） CNAME 记录\t将一个域名设置为另一个域名的别名 RDATA：资源数据，随CLASS和TYPE的变化而变化，用于描述与记录相关的具体信息。 SOA示例\n1 2 3 4 5 6 7 8 9 10 ## dns缓存的存货时间 单位秒，可使用D，W，M $TTL 100 ## 域名 class type 主权威服务器的名称 管理员的邮箱地址 从属服务器同步参数 example.com. IN SOA ns1.example.com. hostmaster.example.com. ( 2024112201 ; 序列号 3600 ; 刷新时间 1800 ; 重试时间 1209600 ; 记录失效的时间 86400 ; 负向缓存的存活时间 ) 缩写示例\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # @ 的值由 SOA 记录或 zone 定义的域名决定 $TTL 100 @\tIN\tSOA\tns1.example.com.\thostmaster.example.com.\t( 2024112201 3600 1800 1209600 86400 ) # 之后的可用缩写，前面的要写全 ## 域名为空就是 @ ## 不为空,并且末尾无.,是非FQDN,会再后补上@ ### www == www.@ == www.example.com. ### www. == www.\t不补 IN NS ns1.example.com. IN NS ns2.example.com. www IN A 192.0.2.1 mail IN A 192.0.2.2 A 记录 和 AAAA记录 1 www.magedu.com. 86400 IN A 10.0.0.21 CNAME 别名记录 用于将一个域名（别名，Alias）指向另一个域名（规范名称，Canonical Name）。\n1 abc.magedu.com. 86400 IN CNAME def.magedu.com. 当需要为主域名（如 example.com）提供多个子域名（如 www.example.com、ftp.example.com）时，可以通过 CNAME 指向主域名，而不是为每个子域名单独设置 A 记录。\n1 2 www.example.com. IN CNAME example.com. ftp.example.com. IN CNAME example.com. NS 记录 指定域名的权威名称服务器\n域名从哪域名服务器找\n域名服务器地址\n1 2 3 4 5 magedu.com. 86400 IN NS dns1.magedu.com. magedu.com. 86400 IN NS dns2.magedu.com. dns1.magedu.com. 86400 IN A 10.0.0.208 dns2.magedu.com. 86400 IN A 10.0.0.208 PTR 记录 1 2 3 4 5 # A记录 blog.magedu.com. 86400 IN A 10.0.0.167 # 与其对应的PTR记录, 格式：IP地址\u0026#34;反着写\u0026#34;，后面跟 .in-addr.arpa. 167.0.0.10.in-addr.arpa. 86400 IN PTR blog.magedu.com. DNS服务器实践 不能有特殊字符，包括制表符。 主服务器 1 2 3 4 zone \u0026#34;noob\u0026#34; { type master; file \u0026#34;/etc/bind/db.noob\u0026#34;; }; 1 2 3 4 5 6 7 8 9 10 11 12 $TTL 1D @ IN SOA noob. loong.noob.com. ( 3 300 100 1D 86400 ) IN NS ns ns IN A 123.123.123.1 loong IN A 123.123.123.2 1 2 named-checkzone noob /etc/bind/db.noob rndc reload 1 2 # 测试 dig noob @10.0.0.12 主从同步服务器 主 1 2 3 4 5 6 7 8 9 10 11 12 13 14 zone \u0026#34;example.com\u0026#34; IN { # IN 可以省略不写 type master; # type 为 主角色 file \u0026#34;/etc/bind/db.example.com\u0026#34;; allow-transfer { 10.0.0.12; }; # 【可选】从服务器的IP地址 allow-update { none; }; # 【可选】该DNS区域不允许动态更新。 notify yes; also-notify { 10.0.0.11; }; }; zone \u0026#34;noob\u0026#34; { type master; file \u0026#34;/etc/bind/db.noob\u0026#34;; allow-transfer { 10.0.0.11; }; }; 加上从dns的NS，与A\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $TTL 1D @ IN SOA noob. loong.noob.com. ( 3 300 100 1D 86400 ) IN NS ns slave IN NS slave-dns ns IN A 123.123.123.1 slave-dns IN A 10.0.0.11 loong IN A 123.123.123.2 从 1 2 3 4 5 6 7 8 9 10 11 zone \u0026#34;example.com\u0026#34; { type slave; # 定义此服务器为从 DNS 服务器 file \u0026#34;slaves/db.example.com\u0026#34;; # 从服务器的区域文件，自动同步主服务器的数据 masters { 192.168.1.10; }; # 定义主服务器的 IP 地址 }; zone \u0026#34;noob\u0026#34; IN { type slave; file \u0026#34;slaves/named.noob\u0026#34;; masters {10.0.0.12; }; }; DNS子域 指在主域名（或称为父域）下创建的更小的、相对独立的域。\n将子域委派给其它的DNS服务器解析，实现分布式DNS服务\n父域 l00ng 1 2 3 4 zone \u0026#34;l00n9\u0026#34; { type master; file \u0026#34;/etc/bind/db.l00n9\u0026#34;; }; 1 2 3 4 5 6 7 8 9 $TTL 1D @ IN SOA l00n9-dns. loong.noob.com. ( 20 3H 15M 1D 1W ) @ IN NS ns sub IN NS sub-dns @ IN A 123.123.123.200 ns IN A 123.123.123.200 sub-dns IN A 10.0.0.11 子域 sub.l00n9 1 2 3 4 zone \u0026#34;sub.l00n9\u0026#34; IN { type master; file \u0026#34;named.sub.l00n9\u0026#34;; }; 1 2 3 4 5 6 7 @ IN SOA dns.sub.l00n9. loong.noob.com. ( 4 1W 1D 2W 3W ) @ IN NS ns @ IN A 123.123.123.201 ns IN A 123.123.123.201 no1 IN A 123.123.123.202 DNS转发 当前我们配置的DNS，如果在自己无法解析后，将直接请求根域的DNS服务器解析。\n在某些特定环境下，我们可以设置DNS转发服务，将当前无法解析的域名，转发给另外的DNS解析，如果 还是无法解析，再提交互联网。\n转发模式：\nFirst模式 本地DNS服务器收到一个无法解析的域名请求时，它会首先尝试将该请求转发到指定的上游DNS服务 器。 上游DNS服务器也无法解析该域名，或者没有响应，那么本地DNS服务器会尝试自己进行递归查询。 Only模式 本地DNS服务器收到一个无法解析的域名请求时，它会首先尝试将该请求转发到指定的上游DNS服务 器。 上游DNS服务器无法解析或没有响应，本地DNS服务器不进行递归查询，直接返回无法解析的结果给 客户端。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 options { ...... dnssec-validation no; #关闭加密验证 【很重要】 forwarders { 10.0.0.14; }; #转发服务器 forward first; #转发策略，如果间接DNS没有返回，则直接DNS再次向 根域请求解析 }; options { ... forwarders { 10.0.0.14; }; forward only; }; named-checkconf 特定域转发 1 2 3 4 5 zone \u0026#34;golang-magedu.com\u0026#34; IN { type forward; forward first; forwarders {10.0.0.14;}; }; 反向解析 1 2 3 4 zone \u0026#34;123.123.123.in-addr.arpa\u0026#34; IN { type master; file \u0026#34;named.123.123.123.in-addr.arpa\u0026#34;; }; 1 2 3 4 5 6 $TTL 1D @ IN SOA ptr.noob. loong.noob.com. ( 1 13H 15M 1D 1W ) IN NS ptr.ns.noob. 9 IN PTR no5.noob. DNS view（视图） DNS视图是一种根据客户端的来源IP地址来解析不同DNS记录的功能。它允许DNS服务器根据请求者的IP 地址范围，返回不同的解析结果。这种功能在需要为内部网络和外部网络提供不同访问服务时非常有用.\n例如，公司内部的员工和外部客户访问同一个域名时，可以解析到不同的IP地址。这样可以做到将客户端 解析到距离其物理地址最近的机房内，以达到加快访问速度，以及分流的目的。\n取消默认的zone入口 增加 acl规则和 view视图 定制各自的zone文件 综合测试 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 #include \u0026#34;/etc/bind/named.conf.default-zones\u0026#34;; #注释此行 options { ... }; # 定义一个名为test_net的ACL，包含IP地址范围192.168.8.0到192.168.8.255的所有客户端。 acl test_net{ 192.168.8.0/24; }; # 定义一个名为prod_net的ACL，包含IP地址范围10.0.0.0到10.0.0.255的所有客户端。 acl prod_net{ 10.0.0.0/24; }; # 定义一个名为other_net的ACL，包含所有客户端（即any） acl other_net{ any; }; # 定义一个名为test_view的视图 view test_view{ match-clients { test_net; }; include \u0026#34;/etc/bind/named.conf.default-zones\u0026#34;; include \u0026#34;/etc/bind/named.conf.test-zones\u0026#34;; }; # 定义一个名为prod_view的视图 view prod_view{ match-clients { prod_net; }; include \u0026#34;/etc/bind/named.conf.default-zones\u0026#34;; include \u0026#34;/etc/bind/named.conf.prod-zones\u0026#34;; }; # 定义一个名为other_view的视图 view other_view{ match-clients { other_net; }; include \u0026#34;/etc/bind/named.conf.default-zones\u0026#34;; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat /etc/bind/named.conf.test-zones zone \u0026#34;sre-magedu.com\u0026#34; { type master; file \u0026#34;/etc/bind/db.test.sre-magedu.com\u0026#34;; }; cat /etc/bind/db.test.sre-magedu.com $TTL 86400 @ IN SOA sre-magedu-dns. admin.sre-magedu.com. ( 123 3H 15M 1D 1W ) NS dns1 dns1 A 192.168.8.13 www A 192.168.8.111 1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat /etc/bind/named.conf.prod-zones zone \u0026#34;sre-magedu.com\u0026#34; { type master; file \u0026#34;/etc/bind/db.prod.sre-magedu.com\u0026#34;; }; cat /etc/bind/db.prod.sre-magedu.com $TTL 86400 @ IN SOA sre-magedu-dns. admin.sre-magedu.com. ( 123 3H 15M 1D 1W ) NS dns1 dns1 A 10.0.0.13 www A 10.0.0.111 CDN CDN的全称是Content Delivery Network，即内容分发网络。\n内容分发网络 (Content Delivery Network, CDN) 是一种分布式服务器系统，旨在通过将内容分发到离用户最近的服务器节点，优化内容交付速度、可靠性和可用性，同时减轻源服务器的压力。\nCDN 的主要作用是通过在全球分布的边缘节点缓存和分发你的内容，加快访问速度，减轻源站压力，并提升可靠性和安全性。\nCDN的作用就是将我主机上的内容先缓存到各个CDN服务商的边缘节点，使访问加速\n内容分发网络(CDN)是一个经策略性部署的整体系统，包括内容存储、负载均衡、网络请求的 重定向和内容管理4个要件。而内容管理和全局的网络流量管理(Traffic Management)是CDN的核心所在。 通过用户就近性和服务器负载的判断，CDN确保内容以一种极为高效的方式为用户的请求提供服务。\nCDN 的工作原理 核心概念 缓存内容：CDN 在全球分布的节点服务器上缓存静态资源（如 HTML、CSS、JavaScript 文件、图片、视频等）。 用户访问：当用户发起请求时，CDN 会将用户的请求路由到离其最近的节点。 内容提供 如果该节点缓存了请求的资源，则直接返回内容。 如果节点没有缓存该内容，则向源服务器请求，并缓存到节点中供未来访问。 CDN 的主要组成部分 边缘节点（Edge Server）（CSDN服务商的）： 部署在全球各地，负责响应用户的内容请求。 提供缓存内容，减少用户访问延迟。 源站（Origin Server）（源主机，自己的）： 存储原始数据的服务器。 CDN 在缓存内容失效时回源请求资源。 分布式控制系统： 管理和分配请求路由。 确保负载均衡、缓存同步等功能。 DNS 调度系统： 根据用户的地理位置和网络状况，将用户请求智能地调度到最佳节点。 CDN 的优缺点 优点： 加速网站和应用：提高加载速度，减少延迟。 高可用性：通过节点冗余，确保即使部分服务器失效也能提供服务。 节省成本：减少对源服务器的请求，降低带宽费用。 增强安全性：内置 DDoS 防护、WAF 和流量清洗功能。 缺点： 缓存更新延迟：动态内容或频繁更新的内容可能需要额外配置来避免缓存过期问题。 成本：对于流量需求较大的企业，CDN 服务可能增加成本。 复杂性：需要额外配置和监控以确保最佳性能。 GLSB 全局负载均衡 GLSB 是在广域网上，对不同地域的服务器间的流量进行调度，通过判断服务器的负载，带宽的负载等， 决定服务器的可用性，同时判断客户端与服务器之间的链路状况，选择与客户端最佳匹配的服务器，并将客户 端请求调度到该服务器上。\nGLSB的实现有三种方式：\n​\t基于DNS实现、基于重定向实现、基于路由协议实现，其中最通用的是基于DNS的实现。\nGLSB 的使用范围：\n​\t常用于有异地机房的WEB系统，或在CDN系统中作为核心的流量调度系统。\n作用是找到最近CDN边缘节点。\nCDN 的优缺点 优点： 加速网站和应用：提高加载速度，减少延迟。 高可用性：通过节点冗余，确保即使部分服务器失效也能提供服务。 节省成本：减少对源服务器的请求，降低带宽费用。 增强安全性：内置 DDoS 防护、WAF 和流量清洗功能。 缺点： 缓存更新延迟：动态内容或频繁更新的内容可能需要额外配置来避免缓存过期问题。 成本：对于流量需求较大的企业，CDN 服务可能增加成本。 复杂性：需要额外配置和监控以确保最佳性能。 智能DNS 智能DNS会自动判断用户的来路，做出一些智能化的处理，判断哪个IP地址离用户最近，然后将该地址返 回给用户。同时智能DNS还有一定程度的故障检测功能，如果发现解析的A主机出现问题，那么会将一个合格的 B主机地址返回给用户，从而提供一个高可靠永不宕机的服务。\nwhois 获取域名相关信息 用于查询域名和IP地址注册信息的工具\n帮助用户获取有关域名或IP地址的所 有者、注册商、注册日期、到期日期以及其他相关信息。\nAnycast技术 NSCD 缓存服务 用于缓存命名服务（如 DNS、用户和组信息）的查询结果，以提高系统性能并减少查询延迟。\n尽管 NSCD 在过去被广泛使用，但随着现代系统需求的变化，其使用频率逐渐降低。一些替代方案。\nNSCD 的作用 NSCD 的主要功能是缓存以下类型的查询结果：\nDNS 缓存： 缓存主机名解析（通过 /etc/resolv.conf 和 /etc/hosts 配置的 DNS 查询）。 减少对外部 DNS 服务器的重复查询，提升性能。 用户信息缓存： 缓存 /etc/passwd 中的用户信息（如用户名和 UID）。 用于用户身份认证相关操作。 组信息缓存： 缓存 /etc/group 中的组信息（如组名和 GID）。 减少对组信息的重复查询。 1 2 3 4 5 6 7 ndcd -g sudo nscd -I all sudo nscd -i hosts # 清理 DNS 缓存 sudo nscd -i passwd # 清理用户缓存 sudo nscd -i group # 清理组缓存 ","date":"2024-11-23T00:00:00Z","permalink":"https://www.l00n9.icu/p/dns/","title":"DNS"},{"content":"流程图 引导程序（Bootstrap Program） BIOS 其代码存储在主板的一颗ROM存储芯片上，ROM是只能读不能写的\n修改的数据是存储在另外一颗RAM存储芯片上，RAM掉电后数 据就会消失，所以主板上有一颗纽扣电池来给这个RAM供电，当这颗纽扣电池没电了，BIOS里面的设置项，就 又恢复成出厂设置了。\nPOST： Power-On-Self-Test （加电自检），是硬件程序BIOS芯片中的一个主要功能，负责完成对CPU、主 板、内存、硬盘子系统、显示子系统、串并行接口、键盘等硬件情况的检测。 ROM： Read-Only Memory （只读存储），该存储器上的数据只能读出，不能写入 RAM： Random Access Memory （随机存取存），这里的随机取存，是指通电后，随时可在任意位置单元存 取数据信息，不过断电后内部信息也随之消失。 系统启动自举程序： 搜寻并加载操作系统引导记录（MBR）的程序。 按照RAM中保存的启动顺序，搜寻有效的启动驱动器（如硬盘、光盘驱动器、网络服务器等）。 读入操作系统引导记录。 将系统控制权交给引导记录，由引导记录完成系统的启动。 BIOS只支持传统的MBR（主引导记录）磁盘分区格式\nBIOS里面的 boot 指定我们要启动的位置，0:0 == [第一块磁盘的第一个分区]\nEFI，UEFI UEFI（统一可扩展固件接口）是一种新的启动方式，它在BIOS的基础上进行了改进，可以看作是BIOS的 升级版。UEFI模式具有许多优势：\n启动速度快： UEFI支持硬件加速和并行处理，可以在几秒钟内启动操作系统，而BIOS通常需要几十秒。 支持大容量硬盘： UEFI基于GPT（全局唯一标识分区表）分区结构，能够支持超过2TB的硬盘容量。 功能丰富： UEFI拥有更加现代化的图形界面，可以更方便地进行设置和管理。 它支持网络启动、安全启动等高级功能，并提供灵活的驱动程序支持。 兼容性好： UEFI可以识别MBR和GPT两种分区格式，因此可以兼容不同版本的Windows和Linux操作系统。 在UEFI模式下,直接由EFI系统分区中的 .efi 引导程序来引导操作系统。\nEFI 系统分区（ESP）起始于第 2048 扇区，用于存储 .efi 引导文件。\nbootloader 启动加载器 Bootloader叫引导加载器，引导程序。\n独立的软件，运行在BIOS之后，操作系统启动之前。它的主要作用就是引导操作系统启动。\nMBR（1.0阶段） 第 0 扇区（512 字节）存储了 MBR（主引导记录），其空间非常有限，只能容纳引导加载器的第一阶段（Stage 1）。\nStage 1 主要负责定位和加载后续阶段的引导代码，而文件系统驱动程序可能体积较大，需要额外空间。\n1-2047扇区（1.5阶段） 用于加载文件系统驱动程序，支持解析磁盘上的文件系统。\n在 1-2047 扇区中存储文件系统驱动或支持代码，使第二阶段引导程序（Stage 2）能够读取磁盘上的文件系统（如 /boot 分区）。\nGRUB（2.0阶段） CentOS 5，6 GRUB 0.97（GRUB Legacy）， CentOS 7 以后使用 GRUB 2.xx\nGRUB（GRand Unified Bootloader）是一个启动加载程序，用于启动操作系统。其配置文件在 Linux系统的启动过程中起着至关重要的作用。\n目前grub的配置文件主要有两种样式：\ngrub1的配置文件在 /boot/grub/grub.conf grub2的配置文件在 /boot/grub2/grub.cfg 读取 /boot/grub 下的配置文件和操作系统内核。选择和加载内核。\n1 2 3 4 5 6 7 8 # GRUB 2 的主配置文件 cat -n /boot/grub2/grub.cfg | grep \u0026#39;###\u0026#39; # 其中 ### BEGIN /etc/grub.d/10_linux ### 是linux系统启动的选择区域 # 系统启动信息配置文件，放置在另外一个目录下 ls /boot/loader/entries/ # ed2606c630314e8ebc3fe115115cb13e-0-rescue.conf 救援模式的 # ed2606c630314e8ebc3fe115115cb13e-5.14.0-427.13.1.el9_4.x86_64.conf 正常的 vmlinuz是一个压缩的内核镜像文件，包含了Linux内核的压缩版本以及相关的启动信息。\n在系统启动时，引导加载程序（如GRUB）会加载vmlinuz文件，并将其解压缩到内存中。\n然后，操作系统的控制权会转移到内核镜像，从而启动Linux操作系统。\nmlinuz文件包含了操作系统的核心功能、驱动程序和必要的文件系统支持，负责初始化硬件设备、管理进程、提供系统调用接口等。\ninitramfs（initial ramdisk filesystem）是一个在内存中的临时根文件系统。\n它在Linux内核启动之前被加载到内存中。initramfs包含了内核启动所需的文件系统模块和驱动程序，使得内核能够顺利地加载真正的根文件系统。一旦真正的根文件系统加载完成，initramfs就会被卸载，系统将转移到真正的根文件系统上运行\ninitramfs（initial ramdisk filesystem）是一个在内存中的\u0026quot;临时根文件系统\u0026quot;，它在Linux内核启动之前被加载到内存中。\ninitramfs包含了内核启动所需的文件系统模块和驱动程序，使得内核能够顺利地加载真正的根文件系统。一旦真正的根文件系统加载完成，initramfs就会被卸载，系统将转移到真正的根文件系统上运行。\n提供必要的文件系统支持： initramfs中包含了内核启动所需的文件系统模块和驱动程序，它们使得内核能够识别和挂载真正的根文件系统。 从而定位到 init 程序，从而完在真正的系统启动。\n简化内核启动过程： 通过提前加载必要的文件系统支持和驱动程序。 它可以在内核启动的早期提供一个用户态环境，用于完成在内核启动阶段不易完成的工作。\n支持特定的启动需求： initramfs可以根据系统的需求进行定制，包含特定的文件系统支持和驱动程序，以满足特定的启动需求。\n提供系统维护和故障排除的功能： 在系统无法正常启动时，可以通过initramfs进入救援模式进行修复。initramfs中可以包含一些系统维护和故障排除工具，这些工具可以帮 助用户诊断和解决系统启动过程中遇到的问题。\n1 2 3 4 dnf install -y dracut-tools 查看文件内容 lsinitrd initramfs-5.14.0-427.13.1.el9_4.x86_64.img GRUB 管理 GRUB修复 /boot下全删 进入光盘troublshooting模式\n1 continue（这会自动将原根挂载到/mnt/sysroot下）\nubuntu中要自己手动挂载：mount /dev/vg/lvm /mnt 切根：chroot /mnt/sysroot\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 dnf install grub2 # 重新安装grub到启动设备 grub2-install /mnt/sysimage # 生成GRUB配置文件： grub2-mkconfig -o /mnt/sysimage/grub2/grub.cfg dnf install kernel 注意： 如果无法安装的话，可以先卸载内核，然后再安装内核即可 这里安装的软件有：kernel 、kernel-core、kernel-modules、kernel-modules-core root口令绕过 init=/bin/bash 1 2 3 4 5 6 7 8 9 10 11 按 e ，进入内核编辑模式，然后修改内核的启动参数 \u0026#34;ro\u0026#34; 改成 \u0026#34;rw\u0026#34; rhgb 后面添加 init=/bin/bash Ctrl+x 进行保存启动 如果开启SElinux 设置 SElinux 重启标记 touch /.autorelabel 最后重启系统： exec /usr/sbin/init rd.break 1 2 3 4 5 6 7 8 9 按 e ，进入内核编辑模式，然后修改内核的启动参数 \u0026#34;ro\u0026#34; 改成 \u0026#34;rw\u0026#34; rhgb 后面添加 rd.break 进入紧急模式，切根 chroot /sysroot 如果提示sh没有chroot，使用根的chroot /sysroot/usr/sbin/chroot /sysroot 无限重启 添加参数 systemd.unit=multi-user.target 然后 ctrl+x\n其他的一些target\ndesired.target、multi-user.target、emergency.target、rescue.target\n内核 流程 探测可识别到的所有硬件设备 加载硬件驱动程序（借助于initramfs加载驱动） 挂载根文件系统 以只读方式挂载根文件系统。确保系统完整性。 将根文件系统重新挂载为读写模式。 启动用户空间第一个应用程序 systemd 内核启动的时候，依赖的大量内核模块文件\n修复vmlinuz文件 CD中获取vmlinuz文件 dracut 制作 dracut /boot/initramfs-$(uname -r).img $(uname -r) 修复initramfs文件 CD中获取initramfs文件 mkinitrd 制作 mkinitrd /boot/initramfs-$(uname -r).img $(uname -r) 系统启动 1 2 3 systemctl get-default systemctl multi-user.target 系统初始化 init初始化 1 2 3 4 5 6 7 8 9 init进程是内核启动的第一个用户级进程，它的进程ID（PID）通常为1。在Linux系统中，init进程负责如下作用： - 系统初始化： init进程在系统启动时执行一系列初始化操作，如设置系统环境、挂载文件系统等。 该程序是内核启动之后的第一个进程，也是进程树中的树根，所以其进程ID始终为1。 - 启动其他进程： 根据系统配置文件（如Linux中的/etc/inittab），init进程会启动其他必要的系统进程和服务。 - 监控与管理： init进程还会监控系统中的其他进程，确保它们正常运行，并在必要时进行重启或终止。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 初始化脚本 sysinit 系统初始化脚本功能 1. 设置主机名 2. 设置欢迎信息 3. 激活udev和selinux 4. 挂载/etc/fstab文件中定义的文件系统 5. 检测根文件系统，并以读写方式重新挂载根文件系统 6. 设置系统时钟 7. 激活swap设备 8. 根据/etc/sysctl.conf文件设置内核参数 9. 激活lvm及software raid设备 10. 加载额外设备的驱动程序 11. 清理操作 /etc/rc.d/rc 控制服务脚本的开机自动运行\nchkconfig 管理服务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 查看所有服务在不同运行级别下的停启情况 [root@c6 ~]# chkconfig --list NetworkManager 0:off 1:off 2:on 3:on 4:on 5:on 6:off abrtd 0:off 1:off 2:off 3:on 4:off 5:on 6:off ...... 查看指定服务 [root@c6 ~]# chkconfig --list crond crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off 查看链接 [root@c6 ~]# ll /etc/rc3.d/*cron* lrwxrwxrwx. 1 root root 15 Aug 29 05:40 /etc/rc3.d/S90crond -\u0026gt; ../init.d/crond 修改服务 [root@c6 ~]# chkconfig --level 3 crond off 再次查看，变成了K开头 [root@c6 ~]# ll /etc/rc3.d/*cron* lrwxrwxrwx. 1 root root 15 Aug 30 14:49 /etc/rc3.d/K60crond -\u0026gt; ../init.d/crond crond在3模式下变成了off [root@c6 ~]# chkconfig --list crond crond 0:off 1:off 2:on 3:off 4:on 5:on 6:off service 手动管理服务 1 2 3 service crond stop service crond start service crond status xinetd 管理非独立服务 1 2 3 有很多服务不是常用服务，使用频率不高，如果这种服务也加入开机启动，则会消耗服务器资源，为了平衡资源与服务使用之间的关系，我们可以用一个代理服务来管理这些不常用的服务。 这些被代理的服务就称之为非独立服务 systemd初始化 unit 1 2 3 4 5 6 7 在systemd中，unit是一个基本概念，表示一个系统功能或服务。 unit表示不同类型的systemd对象，systemd会根据配置文件和设置，启动各种units， 包括服务（service）、设备（device）、挂载点（mount）、监听(socket)等。 每个unit都有一个名称和一个类型，systemd使用依赖关系来确保正确的启动顺序。 查看unit类型 [root@rocky9 ~]# systemctl -t help 服务管理 1 2 3 4 5 1. systemd执行默认target配置，配置文件/etc/systemd/system/default.target 2. systemd执行sysinit.target初始化系统及basic.target准备操作系统 3. systemd启动multi-user.target 下的本机与服务器服务 4. systemd执行multi-user.target 下的/etc/rc.d/rc.local 5. Systemd执行multi-user.target下的getty.target及登录服务 1 2 3 4 5 6 7 # 查看依赖 systemctl list-dependencies # 分析启动时间 systemd-analyze systemd-analyze blame systemd-analyze plot \u0026gt; html 服务脚本文件 位于\n1 2 3 /usr/lib/systemd/system/ /run/systemd/system /etc/systemd/system 1 2 3 对于新创建的unit文件，或者修改了的unit文件，要通知systemd重载此配置文件，或者选择重启系统 systemctl daemon-reload init q 内核参数 一些参数 文件系统 1 2 3 4 5 6 7 8 9 10 11 readahead：决定了操作系统在从磁盘读取数据时，预先读取的数据量。增加readahead的值可以提高顺序 读取的性能，但可能会降低随机读取的性能。 dirty_background_ratio：控制当脏页（被修改过的页面）占总可用内存的百分比达到多少时，后台写入 开始将脏页写回磁盘。如果系统中有大量的写操作，可能需要调低这个比例。 dirty_expire_centisecs：指定了一个脏页在被写入磁盘前在内存中停留的最大时间（以百分之一秒为单 位）。减少这个值可以确保脏页更快地被写回磁盘，但太低的值可能会导致频繁的写操作，影响性能。 dirty_ratio：控制当脏页占可用内存的百分比达到多少时，内核开始同步地将脏页写回磁盘。这个值通常应 该比dirty_background_ratio高。 内存管理 1 2 3 4 5 6 7 8 vm.swappiness：控制内核倾向于使用swap空间的程度。值越高，系统越倾向于使用swap空间。适当调整该 参数可以平衡内存使用和swap的使用，从而减少磁盘I/O操作，提高系统性能。 vm.min_free_kbytes：设置系统尝试保留的最少空闲内存量（以KB为单位）。如果空闲内存低于这个值， 内核会采取措施来增加空闲内存量。 shmall和shmmax：分别控制共享内存段的总数量以及单个共享内存段的最大大小。适当调整这些参数可以提 高系统处理进程间通信的能力。 进程和线程相关参数 1 2 3 4 kernel.pid_max：控制系统中可以同时存在的进程数量的上限。 kernel.threads-max：定义了系统中进程数量（包括线程）的最大值。对于多线程应用程序，适当增加此 值以支持更多的线程。 网络相关参数 1 2 3 4 5 6 7 8 9 10 11 net.ipv4.tcp_max_tw_buckets：控制系统中TIME_WAIT套接字的最大数量。增加该值可以减少 TIME_WAIT套接字的数量，适用于高并发的服务器。 net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle：控制TCP TIME-WAIT快速重用。开启这些参 数可以允许快速重用TIME_WAIT状态的连接。 net.ipv4.tcp_fin_timeout和net.ipv4.tcp_keepalive_time：分别控制TCP连接的关闭时限和空闲 超时时间。适当减少这些时间可以加快资源的回收。 net.ipv4.ip_local_port_range：定义UDP和TCP连接的本地端口的取值范围。扩大端口范围以支持更多 的并发连接。 消息队列和共享内存参数 1 2 kernel.msgmnb、kernel.msgmax和kernel.msgmni：分别控制消息队列的最大长度、单个消息的最大长 度和系统中同时运行的消息队列的个数。 sysctl 参数设置 参数以文件的形式显示在 /proc/sys/ 目录中，配 置项就是目录名加文件名，值就是该文件中的内容\n1 2 3 4 5 sysctl -a\t# 显示所有 sysctl -p\t# 重载参数 sysctl -w\t# 设置参数 1 2 3 4 5 6 7 8 9 10 # 临时 [root@rocky9 ~]# echo 123 \u0026gt; /proc/sys/net/ipv4/ip_forward [root@rocky9 ~]# cat /proc/sys/net/ipv4/ip_forward 123 [root@rocky9 ~]# sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 123 # 写配置文件，永久有效 vim /etc/sysctl.conf sysctl -p 1 2 3 4 5 系统在启动时，会按下列顺序加载配置文件，读取参数值 /etc/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /lib/sysctl.d/*.conf /etc/sysctl.conf ","date":"2024-11-22T00:00:00Z","permalink":"https://www.l00n9.icu/p/linux%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%92%8C%E5%86%85%E6%A0%B8%E7%AE%A1%E7%90%86/","title":"Linux启动流程和内核管理"},{"content":"内核，CPU，内存 内核介绍 内核 是操作系统最基本的部分，功能强大：\n系统调用接口 进程管理 内存管理 文件系统管理 设备驱动 硬件抽象 CPU CPU 分片（时间分片，轮转调度），确保了每个进程或线程都能获得一定的 CPU 时间。\n并发，并行\n寄存器 地址寄存器（AR），用来保存 CPU 当前所访问的主存单元的地址 指令寄存器（IR），用来保存当前正在执行的一条指令 程序计数器（PC），指出下一条指令在主存储器中的地址 数据寄存器（DR），CPU 和主存、外设之间信息传输的中转站 通用寄存器（x64，e 变 r，加新的通用寄存器：r8-r15） eax: 通常用来执行加法，函数调用的返回值一般也放在这里面 ebx: 数据存取 ecx: 通常用来作为计数器，比如 for 循环 edx: 读写 I/O 端口时，edx 用来存放端口号 esp: 栈顶指针，指向栈的顶部 ebp: 栈底指针，指向栈的底部，通常用 ebp+偏移量 的形式来定位函数存放在栈中的局部变量 esi: 字符串操作时，用于存放数据源的地址 edi: 字符串操作时，用于存放目的地址的，和 esi 两个经常搭配一起使用，执行字符串的复制等操作 程序状态字寄存器（PSW），用来表征当前运算的状态及程序的工作方式。 段寄存器：段基址+段内偏移段 \u0026hellip;\u0026hellip; 内存 Page Frame(页框) 物理内存管理中的一个基本单位。\n物理内存被划分为固定大小的块，这些块称为 页框（Page Frame）。大小 4K，大页框 2MB。\n页框的状态通常分为以下几种：\n已分配（Allocated） 页框已分配给某个进程的虚拟页。 未分配（Free） 页框当前未被使用，可以分配给新的虚拟页。 脏页框（Dirty Page Frame） 页框中的数据被修改，但尚未写回磁盘。 共享页框（Shared Page Frame） 页框被多个进程共享（如共享库或 IPC 中的共享内存）。 Page（页） 操作系统通过页表将虚拟内存中的 页（Page） 映射到物理内存中的页框。\n脏页（Dirty Page）：内存中被修改过但尚未写回到磁盘上的页。减少 IO\nPage table（页表） 页表实际上存储在 CPU 的 内存管理单元 （MMU ：Memory Management Unit）\n内存地址转换，其实就是这样三个步骤：\n把虚拟内存地址，切分成页号和偏移量； 根据页号，从页表里面，查询对应的物理页号； 直接拿物理页号，加上前面的偏移量，就得到了物理内存地址。 1 2 3 4 | 一级索引 (20 bits) | 页内偏移 (12 bits) | 页表大小： 2^20 * 4bytes = 4MB 多级页表 一级页表查找使用哪个二级页表\n二级页表查物理页号\n1 | 一级索引 (10 bits) | 二级索引 (10 bits) | 页内偏移 (12 bits) | 优化多级页表的地址转换：TLB\nCPU 的 TLB（Translation Lookaside Buffer）来缓存页表条目：\nTLB 命中 如果虚拟地址的页表条目在 TLB 中，直接完成地址转换，无需访问多级页表。 TLB 未命中 如果未命中，需要逐级查找页表获取地址映射，并将结果缓存到 TLB。 页面换入换出（Page Swapping） 当物理内存不足时，操作系统会将不常使用的页面从物理内存换出到磁盘（即页面置换），腾出空间给新页面。这种机制被称为 页面换入换出（Page Swapping）。\n页表条目中会记录页面是否在磁盘上（有效位为 0）。 如果程序访问一个在磁盘上的页面，会触发 缺页异常（Page Fault），操作系统会将页面换入物理内存并更新页表。 buffer（缓冲），cache（缓存） 缓冲区是一个用于 临时存储数据 的内存区域，其主要目的是协调数据生产者和消费者之间的速率差异，或在设备之间传递数据时作为中转。\n缓存区是一个用于 加速数据访问 的高效存储区域，其主要目的是存储热点数据或最近使用的数据，以减少慢速设备或计算的频繁访问。\n堆（heap），栈（stack） 栈（Stack） 一块连续内存区域，用于存储函数调用相关的数据（如局部变量、函数参数、返回地址等）。 栈有一个 ESP 寄存器管理 ESP（栈顶指针）：指向当前栈顶的位置。 EBP（基址指针）：指向当前函数栈帧的基址（底部）。通过 EBP，定位栈上的参数。 调用函数过程： EBP 指 Main 函数栈底 压入 func 参数，ESP 指栈顶 call func：压入返回地址 EBP 指 func 函数栈底 堆（Heap） 由程序员通过动态内存分配函数（如 malloc、new）显式申请的一块内存区域，大小和生命周期由程序员控制。 代码段（.text）： 用来存放可执行文件的操作指令\n数据段（.data）： 用来存放可执行文件中已初始化全局变量\nBSS 段（.bss）： Block Started by Symbol”的缩写, 意为“以符号开始的块，BSS 段包含了程序中未初始化的全局变 量，在内存中 bss 段全部置零。\n内存问题 内存泄露 Memory Leak 申请了内存，但使用完并未释放申请的内存。\n如果一致重复这样的申请，使用的内存会不断增加。\n内存溢出：Memory Overflow 数据超出了其存储空间的范围，导致数据损坏或程序崩溃。：整数溢出和缓冲 区溢出\n申请了 20M 的空间，但是在这个空间写入 20M 以上字节的数据，就是溢出。\n内存不足：OOM Out Of Memory 内存用完了。\nJava 会选一个进程杀死。\n内存淘汰策略 内存淘汰策略的核心目标是 在有限的内存资源下最大限度地减少缺页率\n先进先出（FIFO） 按照页面进入内存的顺序进行淘汰，最早进入内存的页面最先被替换。\n最近最少使用（LRU - Least Recently Used）；加权 LRU 按时间\n淘汰最近最少使用的页面，假设最近使用过的页面在未来可能仍会被使用。\n最不经常使用（LFU - Least Frequently Used） 按访问次数\n淘汰访问次数最少的页面，假设访问频率低的页面未来也不太可能被访问。\n时钟算法（Clock Algorithm，改进型 FIFO）；二级时钟 使用一个环形队列和访问位（Access Bit）。（二级时钟多一个修改位）\n每次访问页面时，将其访问位设置为 1；淘汰时跳过访问位为 1 的页面，并将其访问位清零，最终淘汰访问位为 0 的页面。\n最优页面淘汰（OPT - Optimal）无法在实际系统中实现 淘汰未来最长时间不会被访问的页面。（无法在实际系统中实现，因为未来的页面访问情况是未知的。）\n时间，空间复杂度 进程 概览 进程概念 进程是 系统 进行资源分配与调度的基本单位。\n进程是运行中的程序。\n进程是程序的一次执行过程，它包含了程序的 代码、数据和运行状态 等信息。\ninit：第一个进程（PID = 1），从 CentOS7 以后为 systemd 进程分类 按资源使用划分\nCPU 密集型 IO 密集型 按运行方式划分\n守护进程：daemon，在系统引导中启动的进程 前台进程：前台进程是直接与用户交互的进程 注意：两者可相互转化\n进程结构 每个进程都有自己的资源，由操作系统分配，内存，栈，文件描述符等信息\n进程由程序、数据和进程控制块（Program Control Block，PCB）三部分组成。\n程序是进程要执行的指令集合，\n数据是进程在执行过程中需要处理的信息\n进程控制块则包含了进程的各种信息和控制信息，\n进程标识符（PID）、 状态、 优先级、 程序计数器、 寄存器集合等。 线程 一个进程可以包含多个线程，线程是 **CPU ** 调度和执行的基本单位。\n线程由线程 ID、当前指令指针(PC)、寄存器和堆栈组成。\n线程共享进程资源:\n共享代码段、数据段和打开的文件。 每个线程有自己的寄存器和栈，用于维护独立的执行流。 进程与线程 进程拥有独立的内存单元和资源，而线程则共享进程的资源。这使得线程在切换时开销较小，因为不需要 切换整个进程的上下文\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 查看进程的相关信息 ls /proc/PID # 查看进程中的线程 - 包括进程本身 grep -i threads /proc/PID/status # 查看进程的二进制文件（软链接） ll /proc/PID/exe # 查看进程打开的文件（软链接） ll /proc/PID/fd/ # 查看进程，带pid pstree -p 进程结构 核心数据结构：task_struct\ntask_struct 是 Linux 中用来描述进程的主要结构体。它定义在内核源码的 include/linux/sched.h 文件中，包含以下主要字段：\n基本信息\npid：进程的唯一标识符（Process ID）。 tgid：线程组 ID，在多线程程序中，所有线程共享同一个 tgid。 comm：进程名称，通常是可执行文件的名称（15 字节长度限制）。 状态信息\nstate\n：表示进程的当前状态，例如：\nTASK_RUNNING：正在运行或准备运行。 TASK_INTERRUPTIBLE：可被信号中断的睡眠状态。 TASK_UNINTERRUPTIBLE：不可被信号中断的睡眠状态。 TASK_STOPPED：进程已停止。 TASK_DEAD：进程已终止。 exit_state：当进程退出时记录其状态，如僵尸状态。\n父子关系\nparent：指向父进程的 task_struct。 children：链表，包含当前进程的所有子进程。 sibling：指向同一父进程的兄弟进程。 链表指针\ntasks：用于将所有进程组织成一个全局的双向循环链表，通过 next 和 prev 遍历。 thread_group：线程组链表，用于管理同一线程组的所有线程。 调度信息\nprio：进程的优先级。 static_prio：静态优先级，用户指定。 normal_prio：进程的普通优先级。 rt_priority：实时进程的优先级。 sched_class：调度类（如 CFS 调度器、实时调度器）。 记账信息\nstart_time：进程创建的时间。 utime：用户态运行时间。 stime：内核态运行时间。 real_start_time：从系统启动到该进程开始运行的时间戳。 内存管理\nmm：指向 mm_struct 的指针，描述了进程的内存空间信息。 active_mm：用于内核线程，共享另一个进程的地址空间。 stack：进程的内核栈。 文件和 IO\nfiles：指向 files_struct 的指针，描述进程打开的文件描述符表。 fs：指向 fs_struct 的指针，包含当前工作目录和根目录的信息。 io_context：I/O 调度信息。 信号\nsignal：指向 signal_struct 的指针，包含进程的信号处理信息。 blocked：屏蔽的信号集合。 pending：挂起的信号集合。 内核线程\nflags：用于标记进程的特殊状态，例如是否是内核线程。 thread：用于存储硬件上下文（如寄存器）信息，特别是在上下文切换时使用。 用户空间和内核空间 内存 中一部分分配给 内核使用，一部分分配给 应用程序使用。\n分别称之为 内核空间，用户空间。\n用户空间（User Space）： 应用程序的内存区域 低地址位 API（应用程序接口） 内核空间（Kernel Space）： 内核运行的内存区域 高地址位 System Call Interface（系统调用接口） 用户态（User Mode）和内核态（Kernel Mode）切换 用户态是应用程序运行的环境，权限受限，不能直接访问硬件资源或内核功能。\n内核态是操作系统内核运行的环境，具有最高权限，直接控制硬件和管理系统资源。\n系统调用 用户空间进入内核空间的主要途径 中断和异常 中断是由硬件或外部事件触发的机制，内核通过中断处理程序响应这些事件。 异常是由 CPU 执行指令时检测到的错误（Page Fault，Trap：用户态程序故意触发异常进入内核）触发的。 上下文切换 进程切换，线程切换，用户态内核态切换，中断切换，异常切换 发生条件： 进程被抢占：时间片到期或更高优先级的任务需要执行。 系统调用或中断：用户态程序主动进入内核态。 I/O 等待：进程等待 I/O 完成，需要切换到其他任务。 保存当前状态： 操作系统保存当前进程的 CPU 寄存器、程序计数器、栈指针等状态。 切换到新任务： 恢复另一个任务的状态，包括寄存器、栈、程序计数器等。 CPU 开始执行新任务。 进程状态 新建状态（New） 进程正在创建中，尚未被操作系统调度执行。 操作系统已为进程分配了必要的资源（如 PCB，Process Control Block）。 尚未进入调度队列。 就绪状态（Ready） 进程已分配必要资源，等待 CPU 调度运行。 位于 调度队列中，随时可以获得 CPU。 未占用 CPU。 运行状态（Running） 进程正在 CPU 上运行，执行其指令。 只有一个进程（单核系统）可以处于运行状态。 多核系统中，每个 CPU 核心可以运行一个进程。 阻塞状态（Blocked / Waiting） 进程 等待某种事件完成（如 I/O 操作、信号或资源），暂时无法运行。 阻塞进程不在调度队列中。 只有等待的事件完成后才能转入就绪状态。 终止状态（Terminated） 进程已完成执行或被强制结束。 进程的资源被回收。 挂起状态（Suspended） 阻塞 → 挂起 系统内存不足，进程被换出到外存。 挂起 → 阻塞 系统资源恢复，挂起进程重新加载到内存，但仍等待事件。 状态转换 子进程 父子进程 父进程 父进程可以通过系统调用 fork() 创建子进程。\nfork() 函数：\n创建一个几乎完全相同的子进程。 子进程从父进程的当前位置开始执行。 返回值： 父进程中返回子进程的 PID。 子进程中返回 0。 如果创建失败，返回 -1。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; int main() { pid_t pid = fork(); // 创建子进程 if (pid == 0) { // 子进程 printf(\u0026#34;This is the child process. PID = %d\\n\u0026#34;, getpid()); } else if (pid \u0026gt; 0) { // 父进程 printf(\u0026#34;This is the parent process. PID = %d\\n\u0026#34;, getpid()); } else { // 创建失败 perror(\u0026#34;fork failed\u0026#34;); } return 0; } 子进程 子进程的生命周期\n创建 父进程调用 fork()。 执行 子进程可以执行父进程代码，也可以通过 exec() 执行新程序。 退出 子进程完成任务后调用 exit() 终止。 退出状态会保存在内核中，直到被父进程回收。 回收子进程：\n父进程调用 wait() 或 waitpid() 获取子进程的退出状态，并释放子进程的资源。 wait() 函数 阻塞父进程，直到任意一个子进程退出。 返回退出的子进程的 PID。 waitpid() 函数 父进程使用 SIGCHLD 信号处理子进程退出 当子进程退出或停止时，操作系统会向父进程发送 SIGCHLD 信号。 父进程可以捕获此信号，并在信号处理程序中处理子进程的退出状态。 方式 特点 适用场景 wait() 阻塞父进程，等待子进程退出。 子进程较少，父进程无需执行其他任务。 waitpid() 支持非阻塞模式和指定等待的子进程，灵活性更高。 父进程需要并行处理其他任务或管理多个子进程。 SIGCHLD 信号 异步通知父进程子进程的退出事件，无需阻塞。 父进程需要实时响应子进程状态，且需管理大量子进程。 僵尸进程 僵尸进程是指 已经终止运行，但其退出状态尚未被父进程回收 的子进程。\n杀了，但没有死。\n形成原因\n当子进程结束后，操作系统会通知父进程，父进程需要调用系统调用（如 wait() 或 waitpid()）回收子进程的退出状态。\n如果父进程没有回收子进程状态，子进程就会变成僵尸进程。\n僵尸进程占用进程表条目（PID）。\n孤儿进程 孤儿进程是指 父进程已经终止，但子进程仍在运行 的进程。\n孤儿进程会被操作系统的 init 进程（PID 1） 接管，成为其子进程。\n形成原因\n父进程意外终止或正常结束，但子进程仍在运行。 子进程未完成其任务，继续执行。 进程调度 调度目标 最大化 CPU 利用率：尽量减少 CPU 空闲时间。 最大化吞吐量：单位时间内完成的任务数量。 最小化周转时间：从提交任务到完成所需的总时间。 最小化等待时间：进程在就绪队列中等待的总时间。 最小化响应时间：从请求提交到系统首次响应的时间。 调度层次 长程调度（Long-term scheduling）：\n决定哪些作业被加载到内存中。 控制多道程序的数量，影响系统负载。 中程调度（Medium-term scheduling）：\n负责挂起或恢复进程，通常用于内存管理。 短程调度（Short-term scheduling）：\n决定哪个进程获得 CPU，属于实时决策。 调度频率高，需高效执行。 进程调度策略 先来先服务（FCFS） 按照进程到达的顺序进行调度。 实现简单。 可能导致“队头阻塞”，使短进程等待时间过长。 短作业优先（SJF） 优先调度预计运行时间最短的进程。 能最小化平均等待时间。 需要准确估算运行时间，可能导致“饥饿问题”。 时间片轮转（Round Robin） 分配固定时间片（Time Quantum） 公平、适合交互式系统。 时间片过短会增加切换开销，过长则退化为 FCFS。 优先级调度（Priority Scheduling） 根据优先级高低选择进程调度。 满足不同任务的优先级需求。 可能导致低优先级进程“饥饿”。 多级队列调度（Multilevel Queue Scheduling） 将进程分成多个队列，每个队列有不同的优先级和调度策略。 多级反馈队列调度（Multilevel Feedback Queue Scheduling） 允许进程在不同队列间动态调整，根据其行为改变优先级。 最短剩余时间优先（SRTF, Shortest Remaining Time First） 抢占式版本的 SJF，优先执行剩余时间最短的进程。 进程同步 进程同步是指多个进程在共享资源时协调彼此的操作，以避免竞争条件、死锁或资源不一致等问题。\n同步的目标\n互斥（Mutual Exclusion）：确保同一时刻只有一个进程访问临界区。 死锁避免（Deadlock Avoidance）：防止进程永久等待资源。 公平性（Fairness）：确保每个进程都有机会访问资源。 进度保证（Progress Guarantee）：如果没有进程在临界区，则能迅速分配资源。 进程同步的经典问题 生产者-消费者问题 问题描述：生产者生产数据并放入缓冲区，消费者从缓冲区取数据，需保证缓冲区不溢出或空取。\n解决方法：\n信号量实现（使用 full、empty 和互斥锁 mutex）。 条件变量和锁实现。 读者-写者问题 问题描述：多个读者可以同时读资源，但写者只能独占资源。\n解决方法：\n优先读者策略：读者可以抢占写者。 优先写者策略：写者优先访问，避免饥饿。 哲学家进餐问题 问题描述：五位哲学家围坐圆桌，用餐时需拿起左右两边的筷子，可能导致死锁。\n解决方法：\n限制最多允许四个哲学家同时拿筷子。 哲学家必须先拿左筷子再拿右筷子。 进程同步的实现方法 锁（Locks） 互斥锁（Mutex）：\n用于保证一个进程独占资源。\n示例操作：\nlock(): 加锁。 unlock(): 解锁。 读写锁（Reader-Writer Locks）：\n允许多个读者同时访问资源，但写者需独占。 示例操作： read_lock() 和 read_unlock() write_lock() 和 write_unlock() 信号量（Semaphore）\n定义：计数器，表示资源的可用数量。 两种类型： 计数信号量：值可大于 1。 二值信号量：值为 0 或 1，类似互斥锁。 操作： P(S)（Wait）：如果信号量值大于 0，减 1；否则等待。申请资源 V(S)（Signal）：信号量值加 1，唤醒等待队列中的进程。释放资源 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Semaphore full = 0; // 表示缓冲区中已填充的槽位 Semaphore empty = N; // 表示缓冲区中空的槽位 Semaphore mutex = 1; // 用于互斥 // 生产者 P(empty); P(mutex); // 放入数据 V(mutex); V(full); // 消费者 P(full); P(mutex); // 取出数据 V(mutex); V(empty); 条件变量（Condition Variables）\n用于线程间的信号传递。 wait(condition, mutex): 释放锁并等待条件变量。 signal(condition): 唤醒等待该条件变量的线程。 自旋锁（Spinlock）\n锁空闲时，进程会忙等待。 适用于临界区很短且多核系统中。 管程（Monitors）\n高级同步机制，封装了共享资源、条件变量和方法。 支持条件等待和条件唤醒。 进程通信 管道\n普通管道\n特点： 单向通信。 只能在具有亲缘关系的进程间使用（如父子进程）。 操作： 创建：pipe() 系统调用。 管道有两个文件描述符： 读端：fd[0] 写端：fd[1] 命名管道\n特点：\n双向通信。 可用于无亲缘关系的进程。 持久化存在，直到被删除。 操作：\n创建：mkfifo 或 mknod。 打开：open()。 1 2 3 mkfifo myfifo # 创建命名管道 echo \u0026#34;Message\u0026#34; \u0026gt; myfifo # 写入数据 cat myfifo # 读取数据 消息队列\n共享内存\n特点： 最快的进程通信方式。 允许多个进程共享同一内存段。 需要同步机制（如信号量）保护共享数据。 信号量（Semaphore）\n信号（Signal）\n套接字（Socket）\n文件（File-Based IPC）\n进程优先级 进程优先级是一个数 值，用于表示进程在系统中的执行顺序。\nPRI（系统优先级）：默认优先级，无法修改\nnice 值：-20 ~19（对系统优先级的修正）\n修改 nice 值 nice/renice 进入 top 后按“r”–\u0026gt; 输入进程 PID–\u0026gt; 输入 nice 值 实时优先级 是操作系统中用于实时进程调度的一种高优先级机制，主要用于确保实时任务能够在规定的时间约束内得到处理。实时优先级的进程通常具有比普通进程更高的优先级，因此在调度时会被优先考虑。\nnice 值越低，进程的优先级越高，获得更多的 CPU 时间；\n反之，nice 值越高，进程的优先级越低，CPU 时间的分配就越少。\n管理工具 进程 pidof 获取 pid 1 2 pidof \u0026lt;程序名\u0026gt; pidof -x /usr/sbin/nginx pstree 进程树 1 2 3 4 pstree -p\t# 带pid pstree -c\t# 不压缩显示 # {}内的为线程 ps 进程状态 1 2 3 4 5 6 7 8 9 10 ps aux # a 所有 # u 显示所有者 # x 包括不链接终端的进程 -p pid #显示指pid的进程 # 查看进程的父子关系 ps auxf prtstat 特定进程状态信息 psmisc 包\n1 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 prtstat [options] \u0026lt;PID\u0026gt; prtstat 1 # 输出类似于 /proc/\u0026lt;pid\u0026gt;/status 中的信息，并包含有关进程资源使用情况、权限、线程等的详细信息。 root@loong:~# prtstat 1 Process: systemd State: S (sleeping) CPU#: 1 TTY: 0:0 Threads: 1 Process, Group and Session IDs Process ID: 1 Parent ID: 0 Group ID: 1 Session ID: 1 T Group ID: -1 Page Faults This Process (minor major): 134890 108 Child Processes (minor major): 2535495 1183 CPU Times This Process (user system guest blkio): 14.22 9.30 0.00 0.00 Child processes (user system guest): 201.79 204.24 0.00 Memory Vsize: 23 MB RSS: 14 MB RSS Limit: 18446744073709 MB Code Start: 0x628f1483d000 Code Stop: 0x628f14847b61 Stack Start: 0x7ffc40dd9f60 Stack Pointer (ESP): 0 Inst Pointer (EIP): 0 Scheduling Policy: normal Nice: 0 RT Priority: 0 (non RT) nice/renice 优先级 1 2 3 nice -n \u0026lt;priority\u0026gt; \u0026lt;command\u0026gt;\t# 以特定nice值运行命令 renice -n \u0026lt;priority\u0026gt; \u0026lt;pid\u0026gt;\t# 更改进程的nice值 pgrep 条件查找 PID 1 2 3 4 5 6 7 8 9 pgrep [options] \u0026lt;pattern\u0026gt; pgrep -at pts/1 # -t 指定终端 # -a 显示详细完整的进程信息 # -l 完整进程名 # -u 根据用户 pgrep -f \u0026#34;.*sshd.*\u0026#34; top 实时显示系统的运行状况 1 2 3 4 5 top -n \u0026lt;num\u0026gt;\t# 刷新几次 top -d \u0026lt;num\u0026gt;\t# 刷新间隔（秒） top -p \u0026lt;pid\u0026gt; top -H\t# 线程 top -b\t# 所有进程 1 2 3 4 5 6 7 8 9 10 查看状态 [root@rocky9 ~]# top top - 20:45:41 up 35 min, 1 user, load average: 0.00, 0.00, 0.00 Tasks: 287 total, 1 running, 286 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.0 us, 0.2 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st MiB Mem : 1743.4 total, 480.6 free, 826.2 used, 609.4 buff/cache MiB Swap: 2064.0 total, 2064.0 free, 0.0 used. 917.3 avail Mem 字段解析 us 用户空间 sy 内核空间 ni 调整 nice 时间 id 空闲 wa 等待 IO 时间 hi 硬中断 si 软中断（模式切换） st 虚拟化消耗占比 htop 交互式的系统监视工具 比传统的top命令更丰富的信息和功能，并以彩色方式展示进程列表，使得用户可以更直观地了解系统的运行 状态。\n注意：htop 是增强版的 top 命令，在 centos 中来自于 epel 源\npmap 进程内存映射关系 1 2 3 4 pmap [options] \u0026lt;pid\u0026gt; -p\t# 显示路径 cat /proc/1134/maps vmstat 监测系统的整体负载情况 监测系统的整体负载情况:\n​\t了解系统的CPU、内存、磁盘、网络等性能指标，以及进程数量和状态等信息。\n分析系统性能问题:\n​\t通过观察系统的CPU使用率、内存占用、磁盘I/O等指标，快速定位系统的性能瓶颈，找到导致系统负载 过高、响应变慢等问题的原因。\n监测系统的稳定性:\n​\t通过连续监测系统的负载情况，识别出系统的周期性波动，以及系统负载变化的规律，从而更好地管理系 统资源，保证系统的稳定性\n1 2 3 4 5 6 vmstat -d # 磁盘 -D # 磁盘综合 procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- r b swpd free buff cache si so bi bo in cs us sy id wa st gu 2 0 0 2632984 53788 949184 0 0 8 14 108 0 0 0 100 0 0 0 lsof 查看进程打开文件 lsof：list open files\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 lsof -p\t# pid -c # 程序 -u\t# 用户 -n\t# 不解析 -i\t# 筛选 -t\t# 只显示 pid # 查看当前哪个进程正在使用此文件 lsof /var/log/messages lsof -i : 80 # 查看进程打开文件 ll /proc/6037/fd/ kill 信号发送 1 2 3 4 5 6 7 8 9 10 11 12 1) SIGHUP 无须关闭进程而让其重读配置文件 2) SIGINT 中止正在运行的进程；相当于 Ctrl+c 3) SIGQUIT 相当于 ctrl+\\ 9) SIGKILL 强制杀死正在运行的进程, 可能会导致数据丢失, 慎用! 15) SIGTERM 终止正在运行的进程，默认信号 18) SIGCONT 继续运行 19) SIGSTOP 后台休眠 # 显示信号 kill -l fuser -ki -9 80/tcp jobs，fg，bg 前后台任务 1 2 3 4 # 使程序停于后台 Ctrl+z # 使程序后台运行 COMMAND \u0026amp; 1 2 3 4 5 6 7 8 9 # 使用\u0026amp;将多命令置于后台运行 sleep 3 \u0026amp; sleep 3 \u0026amp; sleep 3 \u0026amp; wait # wait 会阻塞程序，等待所有后台执行完成 # 进程 ID（PID）：指定要等待的特定进程。 # 作业 ID（Job ID）：指定作业号（通常以 % 开头，如 %1）。 # 无参数：如果不指定任何参数，wait 会等待当前 Shell 中所有的后台任务完成。 内存 free 显示内存使用情况 1 2 3 4 free -h\t# 友好显示 -s \u0026lt;num\u0026gt;\t# 刷新间隔 -c \u0026lt;num\u0026gt;\t# 刷新次数 清理缓存 1 2 3 4 5 6 7 8 9 10 向/proc/sys/vm/drop_caches 中写入相应的修改值，会清理缓存。建议先执行 sync（sync 命令将所有未写的系统缓冲区写到磁盘中，包含已修改的 i-node、已延迟的块 I/O 和读写映射文件）。执行 echo 1、2、3 至 /proc/sys/vm/drop_caches, 达到不同的清理目的。 To free pagecache, use: echo 1 \u0026gt; /proc/sys/vm/drop_caches To free dentries and inodes, use: echo 2 \u0026gt; /proc/sys/vm/drop_caches To free pagecache, dentries and inodes, use: echo 3 \u0026gt; /proc/sys/vm/drop_caches CPU uptime CPU负载 w 显示当前登录到系统的用户信息以及系统的负载情况 mpstat 用于监控多核CPU性能和使用情况 sysstat软件包\n1 2 3 4 5 6 7 -P 0 -P 1 -P ALL # 指定 CPU 核心 # 每 5 秒采集一次信息，共采集三次 mpstat -P ALL 5 3 磁盘 iostat 磁盘使用情况和磁盘性能的实时统计信息 sysstat 包\n1 2 3 4 5 6 7 默认显示 CPU 信息和所有设备信息：iostat 只显示 CPU 的信息：iostat -c 每隔 2 秒显示一次设备统计信息，总共输出 3 次：iostat -d 2 3 每隔 2 秒显示一次 sda 及上面所有分区的统计信息，共输出 3 次：iostat -p sda 2 3 以 MB 为单位显示所有信息：iostat -m 显示指定硬盘信息：iostat -d sda 显示设备的详细信息：iostat -x sda iotop 监视磁盘I/O使用状况 iotop 软件包\n网络 iftop 显示网络带宽使用情况 iftop软件包在 epel-release源里面\n1 2 3 4 5 iftop -nNP -i\t# 接口 -P\t# 端口 -n\t# 不解析 ip -N\t# 数字端口 nload 网络实时吞吐量 nload软件包在 epel-release源里面\n1 -m # 所有设备 nethogs 查看进程网络带宽的使用情况 nethogs软件包在 epel-release源里面\niptraf-ng 图形窗口，网络监视工具 实时展示关于IP流量的各种信息。\n综合监控 dstat 实时监测和报告系统的性能指 标，包括CPU、内存、磁盘I/O、网络等方面的使用情况。\nglances 1 glances C/S模式 1 2 3 4 5 6 服务端配置，在 12 主机上进行服务端的部署 [root@rocky9 ~]# glances -s -B 10.0.0.12 新开一个终端，模拟客户端连接服务端 [root@rocky9 ~]# glances -c 10.0.0.12 cockpit 基于Web的Linux服务器管理工具 9090端口\n计划任务 at计划任务，一次性任务 依赖于atd服务，需要启动才能实现at任务\nat队列存放在/var/spool/at目录中，ubuntu存放在/var/spool/cron/atjobs目录下\n作业执行命令的结果中的标准输出和错误以执行任务的用户身份发邮件通知给root\napt install at -y\n1 2 3 4 5 6 7 8 9 # Ctrl+D 退出 at 0:05 at now+1min # 任务列表 at -l # 具体任务内容 at -c 1 cron计划任务，周期性任务 每个用户都有专用的cron任务文件：/var/spool/cron/crontabs/USERNAME 默认标准输出和错误会被发邮件给对应的用户，如：mage创建的任务就发送至mage的邮箱 root能够修改其它用户的作业 用户的cron中默认 PATH=/usr/bin:/bin，如果使用其它路径，在任务文件的第一行加PATH=/path或 者加入到计划任务执行的脚本中 第六个字段指定要运行的命令。 该行的整个命令部分，直至换行符或“％”字符，指定的shell执行，除非使用反斜杠（\\）进行转义，否则该命令中的**“％”**字符将变为换行符，并且第一个％之后的所有数据将作为标 准输入发送到该命令。 1 2 3 4 5 6 /etc/crontab #添加系统级的 cron 任务，写在此文件中 /etc/cron.d/ #配置文件 /etc/cron.hourly/ #脚本 /etc/cron.daily/ #脚本 /etc/cron.weekly/ #脚本 /etc/cron.monthly/ #脚本 1 2 3 4 5 6 7 8 特定关健字 @yearly #每年 1 月 1 日执行一次，相当于 0 0 1 1 * @annually #每年 1 月 1 日执行一次，相当于 0 0 1 1 * @monthly #每月 1 日执行一次，相当于 0 0 1 * * @weekly #每周日执行一次，相当于 0 0 * * 0 @daily #每天 0 时执行一次，相当于 0 0 * * * @hourly #每小时 0 分执行一次，相当于 0 * * * * @reboot #重启后执行一次 1 2 3 4 5 crontab -l\t#列出所有任务 crontab -e\t#编辑任务 crontab -r\t#移除所有任务 crontab -i\t#同-r 一同使用，以交互式模式移除指定任务 crontab -u\t#管理特定用户的 cron, 仅 root 有权限操作 面试题：11月每天的6-12点之间每隔2小时执行/app/bin/test.sh\n1 2 #在 6,8,10,12 点整共 4 次分别执行 test.sh 0 6-12/2 * 11 * /app/bin/test.sh ","date":"2024-11-19T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E8%BF%9B%E7%A8%8B%E7%B3%BB%E7%BB%9F%E6%80%A7%E8%83%BD%E7%AE%A1%E7%90%86%E7%9B%91%E8%A7%86%E5%B7%A5%E5%85%B7%E5%92%8C%E8%AE%A1%E5%88%92%E4%BB%BB%E5%8A%A1/","title":"进程，系统性能管理监视工具和计划任务"},{"content":"网卡配置 OpenEuler 1 2 3 4 5 6 7 8 9 10 # 配置文件内改名为eth0 mv /etc/sysconfig/network-scripts/ifcfg-ens33 /etc/sysconfig/network-scripts/ifcfg-eth0 vim /etc/sysconfig/network-scripts/ifcfg-ens33 # 修改grub启动配置文件 vim /etc/default/grub # GRUB_CMDLINE_LINUX 增加 net.ifnames=0 biosdevname=0 # 配置文件重新生成 grub2-mkconfig -o /etc/grub2.cfg 新增网卡 1 2 3 4 5 6 7 # /etc/sysconfig/network-scripts添加配置文件 # 修改IP后，重启连接生效 nmcli connection down eth1 nmcli connection reload eth1 nmcli connection up eth1 Ubuntu24.04 1 2 3 4 5 6 7 8 9 10 # 修改网卡配置 vim /etc/netplan/50-cloud-init.yaml netplan apply # 修改grub启动配置文件 vim /etc/default/grub # GRUB_CMDLINE_LINUX 增加 net.ifnames=0 biosdevname=0 grub-mkconfig -o /boot/grub/grub.cfg 新增网卡 1 2 3 # 修改/etc/netplan/50-cloud-init.yaml网卡配置 netplan apply Rocky9 2，3顺序不能换，否则网络服务无法启动\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 1.配置文件内改名为eth0 mv /etc/NetworkManager/system-connections/ens33.nmconnection /etc/NetworkManager/system-connections/eth0.nmconnection vim /etc/NetworkManager/system-connections/ens33.nmconnection # 2.绑定网卡名称与MAC vim /etc/udev/rules.d/70-persistent-net.rules # SUBSYSTEM==\u0026#34;net\u0026#34;,ACTION==\u0026#34;add\u0026#34;,ATTR{address}==\u0026#34;00:50:56:24:09: bd \u0026#34;, ATTR{type}== \u0026#34;1\u0026#34;, NAME = \u0026#34;eth0\u0026#34; # 3.修改grub启动配置文件 vim /etc/default/grub # GRUB_CMDLINE_LINUX 增加 net.ifnames=0 biosdevname=0 # 3.配置文件重新生成 grub2-mkconfig -o /etc/grub2.cfg 新增网卡 1 2 3 4 5 6 7 8 # /etc/sysconfig/network-scripts 添加配置文件 vim /etc/NetworkManager/system-connections/eth1.nmconnection # 绑定网卡名称与 MAC vim /etc/udev/rules.d/70-persistent-net.rules # SUBSYSTEM ==\u0026#34;net\u0026#34;, ACTION== \u0026#34;add\u0026#34;, ATTR{address}==\u0026#34; 00:0c:29:08:86:83 \u0026#34;, ATTR{type}== \u0026#34;1\u0026#34;, NAME = \u0026#34;eth1\u0026#34; reboot 命令 hostname/hostnamectl 1 2 hostnamectl status\t# 查看配置 hostname -i\t# IP 地址 ifconfig/ip 用于配置和显示网络接口参数的命令行工具。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 修改 ip ifconfig eth1 10.0.0.55 netmask 255.255.255.0 # 清除网卡 IP 信息 ifconfig eth1 0.0.0.0 ip addr flush dev eth1 # 禁用网络设备 ifconfig eth1 down # 启用网络设备 ifconfig eth1 up # 物理接口 eth0 上创建逻辑网络接口 eth0:1，并分别分配 IP 地址。 # 添加/删除 ip 并取别名，临时 ip addr add 10.0.0.55/24 dev eth1 label eth0:1 ip addr del 10.0.0.55/24 dev eth1 ifconfig eth1:1 10.0.0.200/24 up ifconfig eth1:1 down 1 2 # 流量信息 ifconfig -s route 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 route -n\t# 以 IP 显示 Flg 字段说明 B #该设备已经设置了广播地址 L #该设备是一个回环设备 M #该设备能接收所有经过它的数据包, 而不论其目的地址是否是它本身 N #该设备不能被追踪 O #在该设备上禁用 ARP P #这是一个点到点链接 R #当前设备正在运行 U #当前设备处于活动状态 # 添加路由 route add 10.0.0.99 gw 10.0.0.2 dev eth1 route del 10.0.0.99 dev eth1 ip route add 10.0.0.99 via 10.0.0.2 dev eth1 ip route del 10.0.0.99 dev eth1 # 路由表需要在 /etc/iproute2/rt_tables 定义。 # metric name # 100 eth1_rt ip route add 10.0.0.99 via 10.0.0.2 dev eth1 table eth1_rt ip rule from 10.0.0.21 dev eth1 table eth1_rt 软路由 基于软件实现的路由器技术\n1 2 3 4 5 6 7 8 9 10 11 # iptables 配 NAT iptables -t nat -A POSTROUTING -s 172.24.0.0/16 -o ethN -j MASQUERADE # ubuntu 关闭 ufw ufw disable cat /proc/sys/net/ipv4/ip_forward vim /etc/sysctl.conf vim /etc/sysctl.d/99-sysctl.conf net.ipv4.ip_forward=1 ip 1 2 3 4 5 ip link show ip link set \u0026lt;interface\u0026gt; up ip link set \u0026lt;interface\u0026gt; down ip link set \u0026lt;interface\u0026gt; name \u0026lt;newname\u0026gt; ip link set \u0026lt;interface\u0026gt; mtu \u0026lt;num\u0026gt;\t# 最大传输单元 1 2 3 4 ip a ip address add 10.0.0.114/24 dev ens160 label ens160:114 ip a del 10.0.0.114/24 dev ens160 label ens160:114 ip addr flush dev ens160 1 2 3 4 5 6 ip route ip route add \u0026lt;TARGET\u0026gt; via \u0026lt;GW\u0026gt; dev \u0026lt;IFACE\u0026gt; src \u0026lt;SOURCE_IP\u0026gt; ip route add default via \u0026lt;GW\u0026gt; dev \u0026lt;IFACE\u0026gt; ip route del \u0026lt;TARGET\u0026gt; ip route flush [dev IFACE] [via PREFIX] ip route get \u0026lt;IP\u0026gt;\t# 到达 IP 经过的路由过程 netstat/ss 1 2 3 4 5 6 -r\t# route -t\t# tcp -u\t# udp -n\t# ip，端口数字 -p\t# 进程相关信息 -l\t# listening nmcli 1 2 3 4 5 6 7 8 9 10 nmcli con [show]\t# 查看网络连接 nmcli con show --active\t# 查看活跃连接 nmcli con show ens160\t# 查看指定设备 nmcli con del ens160\t# 删除连接 nmcli con up ens160\t# 启用连接 nmcli con down ens160\t# 禁用连接 nmcli connection reload\t# 刷新连接 nmcli dev status # 显示设备状态 nmcli dev show ens160\t# 网络接口属性 1 2 # 新增网卡生成配置 nmcli connection add con-name con-eth1 ipv4.addresses 172.16.1.111/16 ipv4.method manual type ethernet ifname eth1 网络绑定 bounding（网络聚合） 将多块网卡绑定同一IP地址对外提供服务，可以实现高可用或者负载均衡。直接给两块网卡设置同一IP 地址是不可以的。通过 bonding，虚拟一块网卡对外提供连接，物理网卡的被修改为相同的MAC地址。\n绑定模式 bonding 支持多种模式，可以通过 mode 参数进行设置。以下是常见的绑定模式：\nmode: balance-rr (0)：轮询模式，循环发送数据包，实现负载均衡。 数据包可能乱序传输 mode: active-backup (1)：主备模式，只有一个接口处于活动状态，其他接口作为备份。 容错 无负载均衡 mode: balance-xor (2)：XOR 负载均衡，根据 源和目标的 MAC 地址进行流量分配。 容错 负载均衡 需要交换机配置链路聚合 分配算法依赖于 MAC 地址，不适用于每个连接均匀分配带宽的场景。 mode: broadcast (3)：广播模式，所有数据包通过所有接口发送，适用于高可靠性需求。 容错 带宽利用率低 mode: 802.3ad (4)：IEEE 802.3ad 动态链接聚合（LACP）。 需要交换机支持并配置为 LACP 模式；需要专业的网络设备和配置支持。 mode: balance-tlb (5)：自适应传输负载均衡，根据负载自动调整发送流量。 接收负载均衡不完善，只有发送流量能达到较好的负载均衡效果。 mode: balance-alb (6)：自适应负载均衡，提供传输和接收方向的负载均衡。通过 ARP 协议实现接收负载均衡，主动协调负载，以动态优化带宽。 在高负载场景下，性能可能不如 802.3ad 模式。 1 2 3 4 常用的模式为 0,1,3,6 mode 1、5、6 不需要交换机设置 mode 0、2、3、4 需要交换机设置，而且不同类型的交换机设置的时候会有不一样，如 Cisco 交换机需要在 0,2,3 模式中使用 EtherChannel，在 4 模式中需要使用 LACP 和 EtherChannel openEuler 1 2 3 4 5 6 7 8 9 10 # 网卡绑定配置 cat \u0026gt; /etc/sysconfig/network-scripts/ifcfg-bond0 \u0026lt;\u0026lt;-eof NAME = bond0 TYPE = bond DEVICE = bond0 BOOTPROTO = none IPADDR = 192.168.74.122 PREFIX = 24 BONDING_OPTS = \u0026#34;mode = 1 miimon = 100 fail_over_mac = 1\u0026#34; eof 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 网卡 1 配置 cat \u0026gt; /etc/sysconfig/network-scripts/ifcfg-eth1 \u0026lt;\u0026lt;-eof NAME = eth1 DEVICE = eth1 BOOTPROTO = none MASTER = bond0 SLAVE = yes ONBOOT = yes eof # 网卡 2 配置 cat \u0026gt; /etc/sysconfig/network-scripts/ifcfg-eth2 \u0026lt;\u0026lt;-eof NAME = eth2 DEVICE = eth2 BOOTPROTO = none MASTER = bond0 SLAVE = yes ONBOOT = yes eof 1 nmcli con reload 测试 1 2 3 4 nmcli device nmcli conn ip a cat /proc/net/bonding/bond0 1 2 3 4 5 6 # 另一台主机 ping 192.168.74.122 # 网卡绑定主机 ip link set eth1 down # 查看 ping 的情况 关闭绑定 1 2 3 4 5 nmcli conn down bond0 rm -rf /etc/sysconfig/network-scripts/ifcfg-{bond0, eth1, eth2} nmcli conn reload rocky9 1 2 3 4 5 6 7 8 9 10 11 # bound 配置生成 nmcli connection add type bond con-name bond0 ifname bond0 bond.options \u0026#34;mode = active-backup, miimon = 1000\u0026#34; nmcli connection modify bond0 ipv4.addresses \u0026#39;192.168.8.123/24\u0026#39; ipv4.gateway \u0026#39;192.168.8.2\u0026#39; ipv4.method manual # 网卡 1 配置生成 nmcli connection add type ethernet slave-type bond con-name bond0-port1 ifname ens224 master bond0 # 网卡 2 配置生成 nmcli connection add type ethernet slave-type bond con-name bond0-port2 ifname ens256 master bond0 # 之后同上 Ubuntu 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cat /etc/netplan/bond0.yaml # bound 与网卡配置 network: ethernets: ens37: addresses: [] dhcp4: false ens38: addresses: [] dhcp4: false version: 2 bonds: bond0: addresses: [192.168.8.124/24] interfaces: [ens37, ens38] parameters: mode: balance-rr\t# 轮询模式 网络组 网络组( Network Teaming)是一种聚合物理和虚拟网络接口的方法，以提供高吞吐量或冗余的逻辑接口。网络组使用一个结合了内核模块和用户空间服务来实现数据包流的快速处理。\n高吞吐量：通过聚合多个接口，网络组能够增加可用带宽，从而提高数据传输的总吞吐量。\n冗余性：在一个接口故障的情况下，网络流量会自动转移到其他接口，确保网络连接不中断，提高可靠性。\n负载均衡：网络组能够在多个接口之间分配流量，以提高资源利用率并减少网络延迟。\n灵活性：支持多种模式和策略，可满足不同的网络需求，例如高性能或高可用性场景。\nNetwork Teaming的功能实现，依赖于两个非常重要的事情：teamd软件以及NetworkManager的 team插件。如果这两个软件不存在的话，导致后面网络组设备启动失败\n1 2 3 yum install -y teamd NetworkManager-team apt install libteam-utils -y 网络组的模式 Broadcast（广播） RoundRobin（轮询） Random（随机） ActiveBackup（主动备份） LoadBalance（负载均衡） LACP（链路汇聚控制协议） 基于 IEEE 802.3ad 协议的链路聚合，允许交换机和设备自动协商以实现链路聚合。 openEuler 1 2 3 4 5 6 7 # 配置网络组接口（对外） nmcli connection add type team con-name team0 ifname team0 config \u0026#39;{\u0026#34;runner\u0026#34;: {\u0026#34;name\u0026#34;: \u0026#34;loadbalance\u0026#34;, \u0026#34;hwaddr_policy\u0026#34;: \u0026#34;by_active\u0026#34;}}\u0026#39; ipv4.addresses 192.168.74.22/24 ipv4.method manual # 配置网络组端口 1（网卡 1） nmcli connection add con-name team0-eth1 type team-slave ifname eth1 master team0 # 配置网络组端口 2（网卡 2） nmcli connection add con-name team0-eth2 type team-slave ifname eth2 master team0 测试 \u0026ldquo;hwaddr_policy\u0026rdquo;: \u0026ldquo;by_active\u0026rdquo; 不起效\n1 2 3 4 teamdctl team0 state ip link set eth1 down ip link set eth2 down 关闭 1 2 3 4 nmcli con down team0 nmcli con del team0 nmcli con del team0-eth1 nmcli con del team0-eth2 ubuntu 1 2 3 4 5 6 7 nmcli con add type team con-name team0 ifname team0 config \u0026#39;{\u0026#34;runner\u0026#34;:{\u0026#34;name\u0026#34;: \u0026#34;activebackup\u0026#34;}}\u0026#39; ipv4.addresses 192.168.74.12/24 ipv4.method manual ipv6.method disabled nmcli c modify team_conn config \u0026#39;{\u0026#34;runner\u0026#34;: {\u0026#34;name\u0026#34;: \u0026#34;activebackup\u0026#34;, \u0026#34;hwaddr_policy\u0026#34;: \u0026#34;by_active\u0026#34;}}\u0026#39; nmcli con add con-name team0-eth1 type team-slave ifname eth1 master team0 nmcli con add con-name team0-eth2 type team-slave ifname eth2 master team0 rocky9 1 2 3 4 5 6 7 8 9 10 nmcli connection add type team con-name team0 ifname team0 team.runner activebackup nmcli connection modify team0 ipv4.addresses \u0026#39;192.168.8.123/24\u0026#39; ipv4.gateway \u0026#39;192.168.8.2\u0026#39; ipv4.method manual nmcli c modify team_conn config \u0026#39;{\u0026#34;runner\u0026#34;: {\u0026#34;name\u0026#34;: \u0026#34;activebackup\u0026#34;, \u0026#34;hwaddr_policy\u0026#34;: \u0026#34;by_active\u0026#34;}}\u0026#39; nmcli connection modify team0 team.link-watchers \u0026#34;name = ethtool delay-up = 1000\u0026#34; # 配置网络组端口 1（网卡 1） nmcli connection add con-name team0-eth1 type team-slave ifname eth1 master team0 # 配置网络组端口 2（网卡 2） nmcli connection add con-name team0-eth2 type team-slave ifname eth2 master team0 测试 1 2 3 4 nmcli connection down team0-eth1 nmcli connection down team0-eth2 nmcli connection up team0-eth1 网桥 桥接：把一台机器上的若干个网络接口“连接”起来。其结果是，其中一个网口收到的报文会被复制给其他 网口并发送出去。以使得网口之间的报文能够互相转发。网桥就是这样一个设备，它有若干个网口，并且这些 网口是桥接起来的。与网桥相连的主机就能通过交换机的报文转发而互相通信。\n配置 1 2 3 4 5 nmcli con add type bridge con-name br0 ifname br0 nmcli con up br0 nmcli con add type bridge-slave con-name br0-port0 ifname ens160 master br0 nmcli con add type bridge-slave con-name br0-port1 ifname ens192 master br0 brctl brctl 是用于管理以太网桥的命令行工具，它在 Linux 内核中建立、维护和检查网桥配置。\n1 2 3 4 5 6 7 8 9 10 11 12 13 brctl addbr \u0026lt;name\u0026gt; 创建一个名为 \u0026lt;name\u0026gt; 的桥接网络接口。 brctl delbr \u0026lt;name\u0026gt; 删除一个名为 \u0026lt;name\u0026gt; 的桥接网络接口，但桥接网络接口必须先 down 掉后才能删除。 brctl show 显示当前系统中所有的桥接接口及其状态。 brctl addif \u0026lt;brname\u0026gt; \u0026lt;ifname\u0026gt; 将一个物理接口 \u0026lt;ifname\u0026gt; 加入桥接接口 \u0026lt;brname\u0026gt; 中 brctl delif \u0026lt;brname\u0026gt; \u0026lt;ifname\u0026gt; 从 \u0026lt;brname\u0026gt; 中脱离一个 \u0026lt;ifname\u0026gt; 接口。 brctl stp \u0026lt;bridge\u0026gt; \u0026lt;state\u0026gt; STP（Spanning Tree Protocol）是一种网络协议，用于在交换机网络中防止环路，并确保网络拓扑的稳定性。使用命令可以配置或显示指定网桥的 STP 状态 \u0026lt;state\u0026gt; 可以是\u0026#39;on\u0026#39;或\u0026#39;off\u0026#39;，表示是否加入 STP 树中。 创建网桥 1 2 3 4 5 6 7 8 9 10 11 12 brctl addbr br0 brctl show brctl stp br0 on brctl addif br0 ens33 brctl addif br0 ens37 ip link set br0 up ip link set ens33 up ip link set ens37 up 诊断工具 fping 1 2 3 4 5 6 7 8 9 10 -s\t# 显示报告 -b\t# 包大小\t-c\t# 发包数 -g\t# 范围ping 子网 或 IPa IPb -i\t# 发包间隔 # 不忽略外部主机的ping动作 echo 0 \u0026gt; /proc/sys/net/ipv4/icmp_echo_ignore_all # 忽略外部主机的ping动作 -- 即使主机在线，也不会被ping通 echo 1 \u0026gt; /proc/sys/net/ipv4/icmp_echo_ignore_all tcpdump 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -i \u0026lt;接口名\u0026gt; -c \u0026lt;Num\u0026gt;\t# 抓包数 -w ./target.cap\t# 结果保存到文件 -nn\t# 不要同时解析主机名和端口名 # 列出系统上所有可用于捕获数据包的网络接口 tcpdump -D tcpdump host 10.0.0.100 tcpdump src host 10.0.0.13 tcpdump dst host 10.0.0.13 tcpdump port 3000 tcpdump tcp tcpdump tcp port 22 and src host 10.0.0.100 nmap 1 2 --min-parallelism 指定并发扫描的数量为2000 nmap --min-parallelism 2000 10.0.0.12-15 nc 端口侦听：nc可以作为server以TCP或UDP方式侦听指定端口。 端口扫描：nc可以作为client发起TCP或UDP连接，进行端口扫描。 文件传输：可以在机器之间方便地传输文件，无需使用scp和rsync等工具，从而避免了输入密码的操作。 网络测速：通过传输文件的方式，可以测试两台机器之间的网络速度 1 2 3 4 # Centos系统： yum install nc # ubuntu系统： apt install netcat-openbsd 1 2 3 4 5 6 7 8 # A机，监听8888 nc -l 8888 # B机发起连接 nc 127.0.0.1 8888 # 通过 -e 指定shell的命令解释器，恶意行为者获取访问权限的常见方法是在开放端口上创建此类后门 nc -l 8888 -e /bin/bash ","date":"2024-11-15T00:00:00Z","permalink":"https://www.l00n9.icu/p/linux%E7%BD%91%E7%BB%9C%E9%85%8D%E7%BD%AE%E4%B8%8E%E5%B7%A5%E5%85%B7/","title":"Linux网络配置与工具"},{"content":"1byte = 8bit\n1KB = 1024B\n1MB = 1024KB\n1GB = 1024MB\n1TB = 1024GB\nss 命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # t：tcp # u: udp # l：listen # n：显示端口和地址的数值形式，不进行 DNS 反向解析，以提高显示速度。 # e：estab 已建立的连接 # p：显示相关的进程信息（PID/进程名），需要 root 权限才能看到所有进程。 # a：all ss -tln ss -tenp ss -tna ss -tnulp 网络基础 作用范围分类 广域网 WAN 城域网 MAN 局域网 LAN 带宽（速度） bps(或 b/s)：bits per second（比特/秒）\nMbps：兆比特每秒\n拓扑 总线拓扑\n由一条线缆进行连接。 末端必须采用终结端。 环形拓扑\n环的形式连接 “令牌”沿环移动，并在每台设备处停止。如果一 台设备希望传输数据，则会在令牌中添加数据和目标地址。 单环拓扑\n共用一条线缆，数据单向传输 双环拓扑\n两个环形允许双向传输数据。 星形拓扑\n一个中央连接点，该点是集线器、交换机或路由器等设备 扩展星形拓扑\n一组独立连接设备之外的冗余连接\n全网状拓扑\n成本高、难度大。 n(n-1)/2 部分网状拓扑\nOSI 七层结构 每一层实现各自的功能和协议，并完成与相邻层的接口通信。\n每一层扮演固定的角色，互不打扰。\n序号 名称 英文 协议数据单元 PDU 7 应用层 application 报文 6 表示层 presentation 报文 5 会话层 session 报文 4 传输层 transport 数据段 3 网络层 network 数据包 2 数据链路层 data link 数据帧 1 物理层 physical 比特流 应用层 提供用户接口\n应用程序之间的通信服务。\n表示层 数据编码和转换：\n编解码 加密解密 压缩解压缩 以确保数据在不同系统之间的交换是有效的和安全的。\n会话层 管理（建立，维护，重连，终止）应用程序之间的会话。\n传输层 为应用程序提供 端到端 的数据传输服务， 负责数据的分段、流量控制、错误检测和纠正。 网络层 负责数据包的路由和转发，\n逻辑地址管理。\n数据链路层 提供 点对点 的数据传输服务， 负责将原始比特流转换为数据帧， 检测传输中出现的错误。 物理层 在物理媒介上传输原始比特流\n定义了连接主机的硬件设备和传输媒介的规范。\n其他 三种通讯模式 单播 广播 组播 冲突域和广播域 冲突域 冲突域属于 OSI 第一层：物理层\n同一时间内只能有一台设备发送信息的范围。\n广播域 广播域属于 OSI 第二层：数据链路层\n如果站点发出一个广播信号，所有能接收收到这个信号的设备范围称为一个广播域。\n单双工 局域网 LAN 局域网是在一个局部的地理范围内（如一个学校、工厂、机关或家庭 内），将各种计算机、外部设备和数据库等互相联接起来组成的计算机通信网。\n解决数据链路层和物理层之间的主机通信，通过以太网和 vlan 来实现通信。\n组网设备 router：路由器 网络层 根据路由协议和转发表自动转发数据包，实现不同网络或子网之间转发数据包。\n使用静态或动态路由协议来生成和维护一张路由表。 根据数据包的目标 IP 地址，将数据包从源网络转发到目标网络。 路由器可以执行 NAT，将私有网络内的 IP 地址转换为公共 IP 地址，允许多个内部设备通过单个公共 IP 地址访问互联网。\n动态路由协议 动态路由器使用路由协议与其他路由器交换路由信息。常见的协议包括： RIP（路由信息协议）：一种距离向量协议，基于跃点数选择路径。 OSPF（开放最短路径优先）：一种链路状态协议，根据链路状态来计算最优路径，适合较大的网络。 BGP（边界网关协议）：主要用于互联网骨干网中，负责在不同自治系统之间交换路由信息。\n路由器具有 MAC 地址 路由通过ARP协议缓存MAC地址\n功能 三层交换机 路由器 子网和 VLAN 间通信 支持 支持 局域网（LAN）适用性 非常适合 适合 广域网（WAN）连接 不适合 非常适合 安全性 基础 ACL 支持 高级防火墙和 VPN 支持 NAT 不支持 支持 动态路由协议 基本协议（OSPF、RIP） 全面支持（包括 BGP） 高级流量管理 基础 QoS 支持 详细 QoS 和流量管理功能 switch：交换机 属于数据链路层 交换式以太网协议 根据MAC地址转发数据包，实现局域网内部设备之间的快速通信。\n维护了一张MAC地址表，记录端口号和主机MAC地址的对应关系，而且这个表的数据是交换机不断学习来维护各端口对应主机信息的结果。如果A没有很长时间没发消息到这个1号端口，那这条记录就会过期并被删除。 所有发到交换机的数据，都会先进入交换机的缓存区。接着消息再被转发到对应机器上。\nMAC 地址的目标端口和这个包的源端口，是同一个端口，交换机会直接丢弃这个包。\nMAC表内无目标地址，会转发除源端口的所有端口。目标地址接收到包后会返回响应包。交换机记录MAC。\n通过 以太网2 和 vlan来实现多主机的访问隔离能力。\n特性 一层交换机 二层交换机 三层交换机 更多操作工作层次 物理层（第 1 层） 数据链路层（第 2 层） 网络层（第 3 层） 转发依据 无地址转发 MAC 地址 MAC 地址 + IP 地址 冲突域 所有端口共享一个冲突域 每个端口独立冲突域 每个端口独立冲突域 广播域 所有端口共享一个广播域 所有端口共享一个广播域 可隔离广播域，实现 VLAN 间通信 路由功能 无 无 支持三层路由协议，支持跨子网通信 应用场景 简单信号中继 小型到中型局域网 中型到大型局域网，VLAN 间路由 功能 三层交换机 路由器 子网和 VLAN 间通信 支持 支持 局域网（LAN）适用性 非常适合 适合 广域网（WAN）连接 不适合 非常适合 安全性 基础 ACL 支持 高级防火墙和 VPN 支持 NAT 不支持 支持 动态路由协议 基本协议（OSPF、RIP） 全面支持（包括 BGP） 高级流量管理 基础 QoS 支持 详细 QoS 和流量管理功能 hub：集线器 1 2 3 4 5 6 工作在物理层的设备 共享式以太网协议，CSMA/CD 把数据包发送到与集线器相连的所有节点。发现数据不是给自己的， 则直接丢弃。 如果机器越来越多，每台机器发一条消息，都会被广播，整个网络就有点顶不住了。 中继器 对数据信号的重新发送或转发， 来扩大网络传输的距离。\nmodem：调制解调器（光猫） 用于光电信号转换的设备\n以太网(Ethernet) 有线网络协议\n物理层（第 1 层）和数据链路层（第 2 层） 技术\n随着交换式以太网的引入，冲突减少，因为交换机为设备提供了独立的通信路径，CSMA/CD 机制逐渐被淘汰。\n共享式以太网使用 CSMA/CD 协议用于集线器。\n交换式以太网用于交换机。\n采用带碰撞检测的载波侦听多址访问（CSMA/CD）方法进行介质访问控制。\nCSMA（载波监听多路访问）：在设备发送数据前，首先监听信道是否空闲，只有在没有其他设备传输的情况下，设备才开始发送数据。\nCD（冲突检测）：如果多个设备同时监听到信道空闲并开始发送，数据帧会在传输介质上发生冲突。以太网会检测冲突，停止发送，等待一段随机时间后重新发送。\nMAC 由 48 位二进制数字组成的地址\n00:0c:29:b1:f4:54\n以 6 个十六进制数字\n虚拟局域网 VLAN 网络分段技术\n在数据帧中增加一个 VLAN 标记 字段，以便交换机可以识别和管理不同 VLAN 的数据帧。\n跨 VLAN 通信要通过 三层设备（如路由器或三层交换机）来实现。\nVLAN 通过配置交换机端口或 IP 地址，将局域网划分成多个独立的虚拟子网，使得不同 VLAN 的设备即便物理连接在一起，也不能直接通信，除非通过路由器或三层交换机。\n端口 VLAN：也称为基于端口的 VLAN。将交换机的每个端口分配到不同的 VLAN，通过指定端口来控制 VLAN 成员。\n协议 VLAN：基于网络协议（如 IP、IPX）划分的 VLAN，通常用于管理多种协议环境的网络。\nMAC VLAN：基于设备 MAC 地址划分的 VLAN，可以将特定设备划分到指定 VLAN。\n动态 VLAN：由网络管理员通过 VLAN 管理服务器（如 VMPS）动态分配设备到不同的 VLAN 中。\n网络架构 示例\n一个企业网络可能采用以下设计：\n核心层：两个高性能核心交换机，连接到数据中心的主干网络。 汇聚层：每层楼的交换机通过汇聚交换机连接到核心层，并在此处配置 VLAN 间路由、ACL 等安全策略。 接入层：每个办公室和会议室的二层交换机负责连接终端设备，并配置 VLAN，将不同部门分配到不同 VLAN 中以实现隔离。 这种三层结构可以有效提升网络的稳定性、可管理性和扩展性，适用于大中型企业的复杂网络需求。\n核心层 核心层 是整个网络架构的顶层，负责提供高速的数据交换和流量转发，是整个网络的“骨干”。核心层通常由高性能的核心路由器或交换机构成，设计时应考虑最小化延迟和高吞吐量，确保网络高可用性和快速数据传输。\n主要功能： 提供高速、低延迟的数据传输。 处理跨汇聚层的流量，将不同网络区域互联。 确保高可靠性和冗余，避免单点故障（如通过双核心交换机实现冗余）。 特性： 高性能和高可靠性。 简化的路由设计，专注于快速数据转发。 支持大容量流量的快速传输，不进行任何不必要的数据过滤或安全检查。 设备：通常使用大型、模块化的三层交换机或路由器，具有高带宽、低延迟的特点。 汇聚层 汇聚层 位于核心层和接入层之间，主要负责流量聚合和策略控制，将不同的接入层网络汇聚后再与核心层连接。汇聚层是网络策略控制的主要位置，用于执行网络策略和管理功能，如路由控制、流量过滤和安全性检查等。\n主要功能： 汇聚来自接入层的流量并转发至核心层。 实现访问控制列表（ACL）、防火墙和 QoS（服务质量）等策略，确保安全性。 实现 VLAN 间的路由，使不同 VLAN 之间可以进行通信。 特性： 控制和管理网络流量。 提供基于策略的流量过滤和安全措施。 支持 VLAN 间路由，实现不同网络段的流量隔离和路由。 设备：通常使用三层交换机，支持高级网络策略（如 ACL、VLAN 路由等），并具备一定的冗余功能，确保高可用性。 接入层 接入层 是网络的最底层，直接与终端设备（如计算机、打印机、IP 电话、无线接入点等）相连，负责将这些终端设备连接到网络中。接入层是用户和设备接入网络的入口点，主要关注接入控制和用户管理。\n主要功能： 提供用户和设备接入网络的途径。 配置端口安全、VLAN 等，确保网络的访问控制。 提供 PoE（以太网供电）功能，为无线接入点、IP 电话等设备供电。 特性： 设备连接点，通常是用户终端设备的直接接入层。 提供 VLAN 配置和端口安全，支持基本访问控制。 设备性能一般较核心层和汇聚层低，但具备灵活性和扩展性。 设备：通常使用二层交换机，支持 VLAN 和端口安全管理，适用于大规模连接终端设备的环境。某些接入层设备还支持 PoE，以便为终端设备供电。 TCP/IP 协议栈 传输层协议 传输控制协议/因特网互联协议\nTCP/IP 其实是一个 Protocol Stack 协议族，包括 TCP、IP、UDP、ICMP、RIP、 TELNET、FTP、SMTP、ARP 等许多协议。\n1 准确来说，数据链路层的MAC头部包括两部分：LLD子层+MAC子层，形成数据帧 TCP UDP 是否连接 面向连接 无连接 是否是可靠传 输 可靠传输 不可靠传输 连接目标个数 一对一 支持一对一，一对多，多对一，多对多传 输 是否有序 有序传输 无序传输 首部大小 首部最少 20 字节，最大 60 字节 首部 8 字节 传输方式 面向字节流 面向报文 TCP TCP 是一种面向连接的、可靠的、基于字节流 的传输层通信协议。\nTCP 适用于需要高可靠性、顺序性和完整性传输的应用，如网页浏览器、电子邮件客户端和文件传输工具等。\n面向连接：\n三次握手（Three-way Handshake）过程建立连接\n可靠性：\n使用序列号来确保数据的顺序性，\n使用确 认应答（ACK）来确保数据已被接收\n使用超时重传机制来处理数据丢失的问题\n流量控制\n滑动窗口协议（Sliding Window Protocol）来实现流量控制\n拥塞控制\n慢启动（Slow Start）、拥塞避免（Congestion Avoidance）、快速重传（Fast Retransmit）和快速恢复（Fast Recovery）等算法来动态调整数据传输速率。\n全双工通信\n字节流服务：\n不对数据进行分块或组装，只是简单地将数据从一端传输 到另一端。\nPDU（协议数据单元，Protocol Data Unit） 源端口（Source Port）和 目标端口（Destination Port）：各 16 位 端口号范围为 0-65535，常见的应用端口有 HTTP（80）、HTTPS（443）等。 序列号（Sequence Number）：32 位 用于标识从发送端发出的数据字节流中的位置。在首次建立连接时，会随机生成初始序列号（ISN），然后随着每个数据包的发送而增加，以确保数据顺序不乱。 确认号（Acknowledgment Number）：32 位 表示接收端期望收到的下一个字节序列号。确认号等于接收到的数据的最后一个字节序列号加 1，用于确认数据的接收，确保传输的可靠性。 数据偏移（Data Offset）：4 位 表示 TCP 报文头的长度，以 32 位（4 字节）为单位。由于 TCP 头的最小长度为 20 字节，因此数据偏移的最小值为 5，最大值为 15（即 60 字节）。 保留字段（Reserved）：4 位 当前未使用，保留用于未来扩展，通常置 0。 控制位（Flags）：9 位\n控制位用于指定报文的类型和用途，常见的标志有以下几种：\nURG（紧急标志）：表示报文中存在紧急数据。\nACK（确认标志）：确认接收到的数据，若置 1 表示确认字段有效。\nPSH（推送标志）：要求接收端立即交付数据，应用于实时通信。\nRST（重置标志）：终止连接。\nSYN（同步标志）：用于建立连接。\nFIN（结束标志）：用于释放连接。\n窗口大小（Window Size）：16 位\n表示接收端的缓冲区剩余空间大小，用于流量控制。发送端会根据接收端的窗口大小调节数据的发送速率，以避免数据溢出。 校验和（Checksum）：16 位 用于检验数据在传输过程中的完整性，包括 TCP 头和数据部分。发送端在计算校验和时，会包含源地址、目标地址、协议、TCP 报文长度等内容，以便在接收端进行校验。 紧急指针（Urgent Pointer）：16 位 仅在 URG 标志置位时有效，表示紧急数据在报文中的偏移量，用于通知接收端在处理数据时应优先处理该紧急数据。 选项（Options）：可变长度 TCP 报文中可以包含一些可选字段，用于设置不同的选项，例如 MSS（最大报文段长度）、窗口缩放、时间戳等。 MSS: MAX Segment Size 定义：仅指 TCP 承载数据，不包含 TCP 头部的大小 尽量每个 Segment 报文段携带更多的数据，以减少头部空间占用比率 防止 IP 基于 MTU 拆分, ip 层拆分报文很低效，如果出现报文丢失，所有报文都要重传 数据（Data）：可变长度 这是实际传输的数据内容，数据的长度不固定，由 TCP 头的数据偏移字段和 IP 数据报的总长度来确定。 应用端口 0 到 1023 般固定分配给一些常见的服务。\nHTTP 服务通常使用 80 端口，FTP 服务使用 20 和 21 端口（20 端口用于数据传输，21 端口用于命令控制），SMTP 服务使用 25 端口等。\n从 1024 到 65535，由操作系统动态分配给需要网络通 信的进程。\n1024-49151 端口范围：\n​\t用户端口或注册端口，但要求并不严格，分配给程序注册为某应用使用，常见的有：\n​\t1433/tcp(SqlServer), 1521/tcp(oracle), 3306/tcp(mysql), 11211/tcp/udp (memcached)\n49152-65535 端口范围：\n​\t动态或私有端口，客户端随机使用端口\n1 2 # 常用服务及端口对应关系 cat /etc/services 三次握手 SYN，ACK（确认位）：报头 Flags 标志位中\nseq，ack（确认号）：报头中\n第一次握手：SYN 标志开始连接；seq 是自身发包的序列号\nSYN = 1 的报文段不能携带数据，但要消耗一个序号\n1 2 3 C-\u0026gt;S: SYN=1 seq=x(随机) 第二次握手：SYN 标志开始连接；ACK 是对方发来包的序列号，表示确认受到；seq 是自身发包的序列号；ack 是想收到包的序列号。\n1 2 3 4 5 S-\u0026gt;C: SYN=1 ACK=1 seq=y（随机） ack=x+1 第三次握手：\n1 2 3 4 C-\u0026gt;S: ACK=1 seq=x+1 ack=y+1 四次挥手 FIN，ACK（确认位）：报头 Flags 标志位中\nseq，ack（确认号）：报头中\nFIN = 1：表示不再发送数据\n第一次挥手：FIN 标志开始断开\nm 为 C 前面正常发送数据的字节序号加 1\n1 2 3 C-\u0026gt;S: FIN=1 seq=m 第二次挥手：ACK 确认受到断开请求，之后将可能剩余的数据包传完。\nn 为 S 前面正常发送数据的字节序号加 1\n1 2 3 4 S-\u0026gt;C: ACK=1 seq=n ack=m+1 第三次挥手：传完可能剩余数据包，发送 FIN 表示数据包发完，开始断开\nk 为 S 前面正常发送数据的字节序号加 1\n1 2 3 4 5 S-\u0026gt;C: FIN=1 ACK=1 seq=k ack=m+1 第四次挥手：ACK 表示收到断开请求\n1 2 3 4 5 6 7 C-\u0026gt;S: ACK=1 seq=m+1 ack=k+1 C等待2MSL，没有收到S的重传请求，则表明S收到了自己的确认。 S没收到最后的确认，会重复发送FIN 服务端收到断开请求后才关闭连接 MSL：TCP 报文段的最大生存时间。\n三次握手少一次 防止重复的连接请求\n确保双方的接收和发送能力\n同步初始序列号，确保数据的有序性和完整性\n四次挥手少一次 连接关闭不彻底\n数据丢失\n资源未及时释放。\n有限状态机 11 个状态\n第二，三次挥手可合并位一次挥手\nFIN 与 ACK 同时在第二次挥手时发送。\n服务端的 FIN 和 ACK 一同发出是一种优化行为，表示服务端在确认客户端的 FIN 请求时，服务端没有待处理的数据，自己也准备好关闭连接，因而将 ACK 和 FIN 合并为一个数据包。这在 TCP 四次挥手中较为常见，有助于提高关闭连接的效率。\nCLOSING 状态表示连接关闭过程中出现了一个特殊情况：双方几乎同时发起关闭请求。也就是说，客户端和服务端几乎同时发送了 FIN 包，导致双方都需要等待对方的 ACK 来完成连接关闭。\nFast Open 降低时延 第一次握手建立连接时。服务端生成 cookie 与 SYN+ACK 一起发送给客户端。之后的建立连接只需要将 cookie 与请求发送，就会得到逍遥的数据。减少握手带来的 RTT 时延。\n注意：某些网络设备或防火墙可能不支持 TFO，此外，在某些情况下，TFO 可能会引入安全隐患，因此需 要根据具体情况谨慎使用\nPAWS (Protect Against Wrapped Sequence number) 防止序列号回绕：timestamp 使用 timestamp 时间戳\ntimestamp 也可以更加精确的 RTO（重传时间）计算\n滑动窗口：流量控制 发送端：\n发送窗口：与接收端的接送窗口大小一样 可用发送窗口：还可以发送数据的大小，发送窗口的大小 - 未确认的数据的大小 可用发送窗口大小会变为返回的 ACK 中的窗口大小 接收端：\n接收窗口：大小与内存缓冲区有关，表示接收方在当前时刻还能接收的数据量。 接收到多少缩多少 处理完多少恢复多少 可用缓冲区大小：ACK 报文中包含一个 窗口大小（Window Size） Linux 中对 TCP 缓冲区的调整方式\nnet.ipv4.tcp_rmem = 4096 87380 6291456 读缓存最小值，默认值，最大值，单位字节，覆盖 net.core.remem_max net.ipv4.tcp_wmem = 4096 16384 4194304 写缓存最小值，默认值，最大值，单位字节，覆盖 net.core.wmem_max net.ipv4.tcp_mem = 1541646 2055528 3083292 系统无内存压力，启动压力模式阈值，最大值，单位为页的数量 net.ipv4.tcp_moderate_rcvbuf = 1 开启自动调整缓存模式 SWS(Silly Window syndrome)糊涂窗口综合征；场景：Server 当前非常繁忙\n服务器很忙，导致没来得及处理缓冲区中接收的内容。\n服务端的接收窗口会越来越少，整个网络中的效率会越来越低。\n解决方法：等服务器处理完再发 SWS 避免算法\n接收端： David D Clark 算法：窗口边界移动值小于 min(MSS, 缓存/2)时，通知窗口为 0 发送端： Nagle 算法：TCP_NODELAY 用于关闭 Nagle 算法 没有已发送未确认报文段时，立刻发送数据 存在未确认报文段时，直到：没有已发送未确认报文段，或数据长度达到 MSS 时再发送 TCP delayed acknowledgment 延迟确认\n没有携带数据的 ACK 使网络效率也很低\n将 ACK 与要发送的数据包合并，提高效率\n当有响应数据要发送时，ack 会随着响应数据立即发送给对方\n如果没有响应数据，ack 的发送将会有一个延迟，以等待看是否有响应数据可以一起发送\n如果在等待发送 ack 期间，对方的第二个数据段又到达了，这时要立即发送 ack\nNagle 与 delay 合用，会导致更大的延迟\nNagle 算法和 Delay 之间会出现问题，因为我们一开始发送一个小数据包，客户端等不到 ACK 包就不会发 送下一个包，而服务端等不到对方第二个数据段，就会有会延迟产生 如何解决 Nagle 算法下，一定会有一个小报文在网络中发送，后续的报文都在等这个小报文的 ACK，才能 继续发送，而延迟确认又会导致 ACK Delay 一定会发生\n解决方案：\n关闭 delayed ACK: TCP_QUICKACK （接收端）\n关闭 Nagle：TCP_NODELAY`（发送端）\n拥塞控制 拥塞控制是计算机网络中的一种机制，用于防止网络出现拥堵（即网络中出现过多的数据包导致性能下降或数据丢失）。\n当输入的负载到达一定程度吞吐量不会增加，即一部分网络资源会丢失掉，网络的吞吐量维持在其所能控制的最大值，转发节点的缓存不够大这造成分组的丢失是拥塞的征兆。\n慢启动（slow start）、拥塞避免（congestion avoidance）、快速重传（fast retransmit）和快速恢复（fast recovery）\nLinux 下 reno 算法、vegas 算法和 cubic 算法\n慢启动： 1开始，之后接收到确认后拥塞窗口（cwnd）扩大一倍 到达ssthresh时，启动拥塞避免 拥塞避免： 拥塞窗口，慢慢加1 超时重传： ssthresh变为超时拥塞窗口时的一半 重新开始慢启动 快重传： 收到3个重复的确认，就重传相应报文 启动快恢复 快速恢复 快重传后，更新ssthresh为当时拥塞窗口的一半 拥塞窗口也变为一半（也有变一半+3的） 启动拥塞避免 UDP UDP 是一种无连接的、不可靠的、基于报文 的传输层通信协议。\nUDP 适用于对实时性要求较高、对可靠性要求不高的应用，如视频流媒体、实时通信（如 VoIP）和某些在 线游戏等。\nDNS 服务，动态主机配置协议（DHCP）、简单网络管理协议 （SNMP）、物联网（IoT）设备数据传输、网络时间协议（NTP）时间信息传输以及简单文件传输协议 （TFTP）文件传输基于 UDP。\n伪首部的存在仅仅是为了在计算校验和时提供一些额外的信息，以确保数据包在传输中的完整性和正确性。\n伪首部是校验计算会用到，伪首部不会被加入数据包中。\nPDU（协议数据单元，Protocol Data Unit） 源端口（Source Port，2 字节） 表示数据报的发送端端口号。 可选字段。如果发送方不需要接收回应，则可以设置为 0。 目标端口（Destination Port，2 字节） 表示数据报的接收端端口号。 必须包含有效端口号，指定数据报要传输的服务或应用程序。 长度（Length，2 字节） 表示整个 UDP 数据报的长度，包括头部和数据部分。 长度最小值为 8（即没有数据的空 UDP 报文），最大为 65535 字节。 校验和（Checksum，2 字节） 校验和用于确保数据的完整性。它对 UDP 报头、数据以及伪头部信息（IP 源地址、目标地址、协议等）进行校验。 校验和在 UDP 中是可选的。如果校验和为 0，表示不计算校验，但在 IPv6 中必须使用校验和。 网络层协议 IP 将数据包从源地址传送到目标地址。\nPDU 标识：占 16 位，它是一个计数器, 通常，每发送一个报文，该值会加 1， 也用于数据包分片，在同一 个包的若干分片中，该值是相同的； 标志(flag)：占 3 位，目前只有后两位有意义， DF： Don’t Fragment 中间的一位，只有当 DF = 0 时 才允许分片，MF： More Fragment 最后一位，MF = 1 表示后面还有分片，MF = 0 表示最后一个分 片 IP PDU 报头； 生存时间：占 8 位, 记为 TTL (Time To Live) 数据报文在网络中可通过的路由器数的最大值，TTL 字段 是由发送端初始设置一个 8 bit 字段，推荐的初始值由分配数字 RFC 指定, 当前值为 64，发送 ICMP 回显应答时经常把 TTL 设为最大值 255； 协议：占 8 位，指出此数据报携带的数据使用何种协议以便目的主机的 IP 层将数据部分上交给哪个 处理过程，1 表示为 ICMP 协议， 2 表示为 IGMP 协议， 6 表示为 TCP 协议，17 表示为 UDP 协 议； ICMP ping 提供网络的 错误报告 和 状态查询。\n错误报告：ICMP 会在网络传输过程中检测并报告错误（例如，数据包无法送达），并将信息返回给发送方，以便发送方能够及时采取措施。\n状态查询：ICMP 可以向网络设备发送状态查询消息，以检查设备是否在线、路径是否畅通等。\n流量控制：在网络过载时，ICMP 可以通知发送方减慢发送速度，从而帮助优化网络资源。\n诊断和调试：ICMP 可用于执行网络诊断，常见的 ping 和 traceroute 工具都是基于 ICMP 协议的。\nICMP 的安全风险 Ping Flood（Ping 泛洪） 描述：攻击者向目标主机发送大量 ICMP 回显请求（Echo Request），导致目标主机处理不过来，资源耗尽，最终拒绝服务。 防御：限制每秒接收的 ICMP 请求数量，或者在防火墙中对 ICMP 流量做限制。 Ping of Death（死亡之 Ping） 描述：通过发送超大 ICMP 包，导致目标主机缓冲区溢出，引起系统崩溃或重启（已被现代操作系统修复）。 防御：现代操作系统已防范此类攻击，一般无需额外配置。 Smurf 攻击 描述：攻击者向网络广播地址发送伪造源地址的 ICMP 回显请求，导致所有主机同时向目标主机发送响应数据，形成流量放大，造成网络拥堵。 防御：禁止网络中的广播 ICMP 请求，配置防火墙规则屏蔽来自广播地址的请求。 信息收集与侦查 描述：攻击者可以通过 ICMP 进行网络探测，收集网络拓扑、主机状态等信息，为进一步攻击做准备。 防御：在防火墙中限制或禁止 ICMP 流量，尤其是禁止 ICMP 回显请求和重定向消息。 防火墙中的 ICMP 管理 为了提高网络安全性，许多防火墙会对 ICMP 流量进行管理：\n限制 ICMP 类型：可以允许 ping 使用的 ICMP 回显请求，但禁止 ICMP 重定向消息，防止恶意路由重定向。 速率限制：对 ICMP 请求进行速率限制，以避免 Ping Flood 等泛洪攻击。 过滤广播地址的 ICMP 请求：避免 Smurf 攻击。 数据链路层协议 ARP 根据 IP 地址获 取物理地址的一个协议。\nARP 的安全性问题 由于 ARP 不包含认证机制，网络攻击者可能利用 ARP 的漏洞进行攻击。常见的 ARP 攻击包括：\nARP 欺骗（ARP Spoofing）： 攻击者向局域网中的设备发送伪造的 ARP 应答，将自己的 MAC 地址伪装成目标设备的 MAC 地址。 通过 ARP 欺骗，攻击者可以将自己伪装成路由器、网关等设备，从而截获网络流量，实现中间人攻击（MITM）。 ARP 洪泛（ARP Flooding）： 攻击者向局域网广播大量伪造的 ARP 请求或应答，占用网络带宽，并使设备的 ARP 缓存超载。 通过 ARP 洪泛，攻击者可以使网络性能下降或阻塞，造成拒绝服务（DoS）攻击。 ARP 攻击的防御措施 静态 ARP 表：在网络设备上手动配置静态 ARP 表，防止恶意设备伪造 MAC 地址。虽然安全性高，但管理成本大，不适合大型网络。 ARP 绑定：在一些企业级路由器和交换机中，可以将 IP 地址和 MAC 地址进行绑定，防止 ARP 欺骗。 网络隔离和 VLAN：通过 VLAN 将不同类型的设备隔离开，限制 ARP 广播的范围。 ARP 检测：防火墙或入侵检测系统可以实时监控 ARP 流量，识别和阻止异常的 ARP 请求和应答。 加密协议：使用加密的通信协议（如 HTTPS）可以降低中间人攻击的风险，即便遭到 ARP 欺骗也不会泄露敏感数据。 ARP 在网络中的作用与局限 局域网内解析 IP 到 MAC 的桥梁：ARP 是 IP 网络中必不可少的协议，通过 IP 到 MAC 的解析，ARP 支持数据链路层的传输。 仅适用于局域网：ARP 使用广播发送请求，因此仅限于局域网内的解析；跨网段的 IP 到 MAC 转换需要通过路由或代理 ARP 实现。 缺乏安全性：ARP 协议没有认证机制，容易遭受伪造攻击，因此在对安全要求高的网络中需要进行额外的防护。 进程间通信：IPC 系统信号（signal） 用于通知进程某个事件已经发生。\n管道（pipe） 用于具有亲缘关系进程间的数据传递。\n套接字（socket） 同一台计算机上的进程间通信，\n于不同计算机之间的网络通信。\nTCP/UDP\n1 2 3 4 5 6 客户端： 首先创建一个Socket对象，用于与服务器端建立连接。 然后调用connect方法来连接服务器， - 并通过send方法发送数据， - recv方法接收数据。 通信结束后，调用close方法来关闭连接并释放资源。 1 2 3 4 5 6 7 服务器端： 首先创建一个Socket对象，用于监听客户端的连接请求。 然后将Socket对象绑定到一个特定的地址和端口上，以便客户端能够连接到该地址和端口。 接着调用listen方法来开始监听客户端的连接请求。 一旦客户端发起连接请求，服务器端会调用accept方法来接受连接， 并创建一个新的Socket对象用于与该客户端进行通信。 之后，服务器端就可以通过新创建的Socket对象来接收和发送数据了。 文件锁（file lock） 用于进程间对共享文件的同步访问。\n消息队列（message queue） 允许一个或多个进程向它写入或从中读取消息。\n信号灯（semaphore，有的地方也称之为信号量） 用于进程间的同步与互斥。\nIPv4，子网掩码 IPv4 ABCDE 类 A 类：1-126.X.X.X 0 开头，表示未知地址，不能用 127 开头，表示回环地址，不能用 B 类：128-191.X.X.X C 类：192-223.X.X.X D 类：224-239.X.X.X（多播） E 类：略（留给科学家使用） 公共和私有 IP 地址\n私有 IP 地址：不直接用于互联网，通常在局域网中使用 公共 IP 地址：互联网上设备拥有的唯一地址 公共 IP 地址世界唯一，可以通过互联网访问，私有地址不能通过互联网访问 特殊地址\n0.0.0.0 0.0.0.0 不是一个真正意义上的 IP 地址。它表示所有不清楚的主机和目的网络 255.255.255.255 限制广播地址。对本机来说，这个地址指本网段内（同一广播域）的所有主机 224.0.0.0 到 239.255.255.255 组播地址，224.0.0.1 特指所有主机，224.0.0.2 特指所有路由器。224.0.0.5 指 OSPF 路由器，地址多用于一些特殊的程序以及多媒体程序 169.254.x.x 如果 Windows 主机使用了 DHCP 自动分配 IP 地址，而又无法从 DHCP 服务器获取地址，系统会为主机分配这样的地址 保留地址：0，255 IPv4 地址的主机位部分全为 0 时，该地址表示的是整个网络，而不是具体的某台主机。网络地址用于标识子网。\n0.0.0.0 是一个特殊的 IPv4 地址，表示“任何地址”。在路由和绑定时，0.0.0.0 通常表示本地网络上的所有 IP 地址。\n主机位部分全为 1（即 255）时，该地址被用作网络的广播地址。192.168.1.0/24 网络中，192.168.1.255 是广播地址，表示向 192.168.1.0/24 网络的所有主机发送数据包。\n255.255.255.255 是特殊的本地广播地址，表示向当前子网中的所有设备发送消息，不会被路由到其他网络。\n子网掩码 子网掩码通过一系列连续的 1 和 0（以二进制表示）将 IP 地址分成 网络位 和 主机位，从而确定一个 IP 地址所属的网络范围和网络内的主机数量。\n1 2 3 4 5 6 示例： IP地址 172.16.0.0 子网掩码 11111111.11111111.00000000.00000000 子网掩码十进制表示 255.255.0.0 数字表示 16 CIDR方式 172.16.0.0/16 是否同一网段：大小网段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #10.0.0.100/24, 10.0.1.100/16 #上述两个IP是否在同一个网段，要分情况 #10.0.0.100/24 ----\u0026gt; 10.0.1.100/16 时 #10.0.0.100/24 = 10.0.0.100/255.255.255.0 #00001010.00000000.00000000.01100100 IP #11111111.11111111.11111111.00000000 netmask #00001010.00000000.00000000.00000000 网络ID 10.0.0.0 #此处也要和前面的netmask与运算，而不是自己的 #10.0.1.100/24 = 10.0.1.100/255.255.255.0 #00001010.00000000.00000001.01100100 IP #11111111.11111111.11111111.00000000 netmask #00001010.00000000.00000001.00000000 网络ID 10.0.1.0 #结论：10.0.0.0 != 10.0.1.0，所以两者不在同一个网段 #10.0.1.100/16 ----\u0026gt; 10.0.0.100/24 时 #结论，不用算，是同一个网段 #IP A与IP B通信时，都是用IP A的netmask去算IP B的netmask，因为在通信前，IP A不知道IP B的netmask值，只能用自己IP与运算 子网掩码的计算 计算子网数量和主机数量 $$\r子网数量 = 2^{\\text{子网位数}}\r$$ $$\r主机数量 = 2^{\\text{主机位数}} - 2\r$$ （减去 2 是因为每个子网的第一个地址是网络地址，最后一个地址是广播地址）\n计算子网地址范围 要计算一个子网的范围，可以将网络地址和广播地址作为起始和结束。以 192.168.1.0/24 为例：\n网络地址：192.168.1.0 广播地址：192.168.1.255 可用地址范围：192.168.1.1 到 192.168.1.254 ","date":"2024-11-12T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E4%B8%8E%E9%80%9A%E8%AE%AF/","title":"网络协议与通讯"},{"content":" 添加存储 识别存储 存储分区 分区格式化 分区（永久）挂载 磁盘存储 设备号 作用 举例 主设备号 major number 表示设备类型 sda 次设备号 minor number 标识同一类型下的不同设备 sda1，sda2 中的 1，2 设备文件类型：\n块设备（b） 字符设备（c） 磁盘设备命名 添加磁盘不重启识别 1 2 3 4 5 6 7 8 9 echo \u0026#39;- - -\u0026#39; \u0026gt; /sys/class/scsi_host/host0/scan echo \u0026#39;- - -\u0026#39; \u0026gt; /sys/class/scsi_host/host1/scan echo \u0026#39;- - -\u0026#39; \u0026gt; /sys/class/scsi_host/host2/scan # host 默认是32个 for i in $(ls /sys/class/scsi_host/) do echo \u0026#39;- - -\u0026#39; \u0026gt; /sys/class/scsi_host/$i/scan done 硬盘 支持 Nvme 协议硬盘速度是最快的\nSATA：SATA 数据端口与电源端口是分开的，即需要两条线，一条数据线，一条电源线 -\nSAS：SAS 是一整条线，数据端口与电源端口是一体化的，SAS 中是包含供电线的，而 SATA 中不包 含供电线。SATA 标准其实是 SAS 标准的一个子集，SATA 硬盘可以插入 SAS 主板上，反之不行。\n1 2 3 # 磁盘测速 dd | hdparm -t /dev/sda dd | hdparm -t /dev/nvme0n1 LFF：3.5 寸\nSFF：2.5 寸\nCHS：24 bit 扇区：sector\n柱面：cylinder\n分区：Partition\n最大寻址空间：8 GB\n前 10 位表示 cylinder，中间 8 位表示 head，后面 6 位表示 sector\nLBA：48 bit 144 petabytes\nLBA = (((C heads-per-cylinder) + H) sectors-per-track) + S -1\n必看命令 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 # 查看设备信息 lsblk lsblk -f\t# 文件系统 filesystem lsblk -p\t# 设备全路径 path # 查看磁盘分区 fdisk -l # 查看块设备属性 blkid # 查看磁盘容量 Disk Free df -lh df -Th # 查看目录容量 Disk Usage du -sh # 文件复制与转换 dd bs=size\t# 指定块的大小 dd if=/PATH/FROM/SRC of=/PATH/TO/DEST bs=N count=N seek=n\t# 写时，跳过前面的n块 skip=n\t# 读时，跳过前面的n块 # 备份/dev/sdx全盘数据，并利用gzip压缩，保存到指定路径 dd if=/dev/sdx | gzip \u0026gt;/path/to/image.gz 存储分区 磁盘分区的优点：\n数据管理：通过分区，用户可以将不同类型的文件存放在不同的分区中，便于分类管理和查找。\n系统安全：将操作系统和用户数据分别存放在不同的分区中，可以在系统崩溃或需要重装时保护用户数据 不受影响。\n性能优化：合理的分区策略可以减少磁盘碎片，提高磁盘的访问速度和效率。\n多操作系统支持：通过分区，用户可以在同一台计算机上安装并运行多个操作系统，满足不同的应用需 求。\nMBR：Master Boot Record GPT BOIS UEFI 4 个主分区 128 个分区 32 位的 LBA 64 位 LBA 最大可寻址的存储空间只有 2TB 最大可寻址的存储空间只有 9.4ZB MBR：Master Boot Record 硬盘的第一个扇区（0 道 0 头 1 扇区）512bytes。\n446 bytes: boot loader 启动相关\n64 bytes：分区表，其中每 16 bytes 标识一个分区；所以只有四个主分区\n2 bytes: 55AA，标识位\nMBR 分区表最多支持 4 个主分区，或者 3 个主分区和 1 个扩展分区（扩展分区下可以创建多个逻辑分区）。\n主分区：主要是用来启动操作系统的，它主要放的是操作系统的启动或引导程序，/boot 分区最好放在主分区上； 扩展分区是不能使用的，它只是做为逻辑分区的容器存在的，先创建一个扩展分区，在扩展分区之上创建逻辑分区； 我们真正存放数据的是主分区和逻辑分区，大量数据都放在逻辑分区中。 GPT 保护 MBR 区域： 位于磁盘的第一个扇区（LBA0），主要用于兼容性考虑。这个区域存储了一份传统的 MBR 信息，以防止不 支持 GPT 的硬盘管理工具错误识别并破坏硬盘中的数据。 容灾功能：磁盘的 \u0026ldquo;首尾两部分\u0026rdquo; 分别保存一份相同的分区表, 并有 CRC 校验位。 分区实践 1 partprobe\t# 来刷新分区表，使系统立即识别分区的变化，而无需重启。 fdisk：MBR 分区 1 2 3 4 5 6 7 8 9 10 fdisk \u0026lt;disk\u0026gt;\t# 进入分区页面 p\t# 打印分区情况 n\t# 添加分区 d\t# 删除分区 q\t# 退出 w\t# 保存更改 t\t# 更改分区类型 v\t# 检验分区 gdisk：GPT 分区 1 2 3 4 5 6 7 8 9 10 gdisk \u0026lt;disk\u0026gt;\t# 进入分区页面 p\t# 打印分区情况 n\t# 添加分区 d\t# 删除分区 q\t# 退出 w\t# 保存更改 t\t# 更改文件系统类型 v\t# 检验分区 非交互分区 fdisk，gdisk 都可以\n1 2 3 4 5 6 7 8 9 10 11 12 # 1 echo -e \u0026#34;n\\n\\n\\n\\n\\nw\\ny\\n\u0026#34; | gdisk /dev/nvme0n1 # 2 fdisk /dev/sdb \u0026lt;\u0026lt;EOF n +50G w EOF parted 分区 通常用于处理大型磁盘，特别是 在需要更复杂的分区布局时。\n1 parted \u0026lt;disk\u0026gt; 文件系统基础 存储设备上组织文件的方法。存储文件的方法和数据结构。\n1 2 3 4 # 查看当前操作系统支持的文件系统 ls /lib/modules/$(uname -r)/kernel/fs # 查看当前操作系统可用的文件系统；被选择了才是可用的。 cat /proc/filesystems linux 文件系统 ext4 最大 16TB 文件；适合中小型数据存储、个人计算机、一般的服务器环境，或那些包含大量小文件的系统。它的兼容性较高，稳定性和易用性较好，适用于大多数 Linux 用户。 xfs 最大 8EB 文件；适合大型数据库、数据仓库、高并发环境和需要处理大文件的场景，特别适合企业级或数据密集型的服务器应用。XFS 的并发性和快速恢复使其在大规模、高性能环境中表现优异。 swap 虚拟内存 iso9660 光盘 tmpfs 基于内存的文件系统，通常挂载到/tmp win 文件系统 FAT32 4GB 的文件 NTFS 16EB 的文件 网络文件系统 NFS：Network File System，即网络文件系统\nRAW：裸文件系统 没被格式化\n直接对磁盘进行读写\n数据库存储：一些数据库系统（如 Oracle）允许将数据文件直接存储在裸设备上，以提高 I/O 性能和数 据安全性。这是因为裸设备可以绕过操作系统的文件系统层，减少数据读写时的系统开销。 特定应用需求：某些应用程序可能需要直接访问磁盘硬件，以实现特定的功能或性能要求。在这种情况 下，裸设备提供了一个直接访问磁盘的途径。 FAT 文件系统 便携式存储设备（如 U 盘、SD 卡）\n文件系统管理 格式化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 -L\t# 标签 Lable mkfs -t TYPE \u0026lt;device\u0026gt;\t# 默认ext2 mke2fs -t TYPE \u0026lt;device\u0026gt;\t# 默认ext2 # mkfs -t TYPE的简写 mkfs.ext4 mkfs.xfs mkfs.vfat tune2fs\t# 更改ext文件系统参数 dumpe2fs\t# 显示ext文件系统信息 xfs_info\t# 显示xfs文件系统信息 e2label\t# 更改ext文件系统标签 findfs\t# 查找分区 挂载 /etc/fstab：自动挂载文件\n1 2 3 4 5 6 7 8 9 mount mount -a\t# 挂载/etc/fstab中的设备 umount -f\t# 强制 -l\t# 延迟卸载，等分区不忙时 -n\t# 不写入日志 findmnt\t# 查找 持久挂载 打开/etc/fstab 文件 添加挂载信息 保存并关闭文件 验证挂载配置 1 2 3 4 5 6 7 8 9 10 # 应该更改了/etc/fstab，所以使用命令让 systemd 重新加载其缓存的配置 systemctl daemon-reload mount -a #fstab新增条目有效，如果在中间修改了挂载选项，则此命令无效 mount -o remount \u0026lt;device\u0026gt; # 删除|修改 /etc/fstab 条目不生效的场景，上面两条命令不生效，先umount再挂载 umount \u0026lt;device\u0026gt; # 删除fstab条目后，使用umount卸载 1 2 3 4 5 \u0026lt;文件系统设备\u0026gt; \u0026lt;挂载点\u0026gt; \u0026lt;文件系统类型\u0026gt; \u0026lt;挂载选项\u0026gt; \u0026lt;dump\u0026gt; \u0026lt;fsck\u0026gt; UUID=6e9983be-5ce1-4c50-9a8b-2d5f07164fb6 /home ext4 defaults 1 2 # 挂载选项 # dump 是否备份 1：每天；2：隔一天 # fsck 是否进行文件系统检查 0：不检查；1：启动前检查（根文件系统使用）；2：启动后检查 文件系统异常修复 一定不要在挂载状态下执行下面命令修复\n1 2 3 4 5 6 fsck\t# ext -a\t# 自动修复 -r\t# 交互修复 e2fsck xfs_repair swap：交换分区 防止 因内存不足而导致的系统崩溃或性能下降。\n配置过多 swap 空间会造成存储设备处于分配状态但闲置，造成浪费，过多 swap 空间还会掩盖 内存泄露。内存泄露是指程序运行时分配了内存却没有释放，导致系统的内存使用量不断增加。\n为 优化性能，可以将 swap 分布存放， 或 高性能磁盘存放。\nswap 开启与关闭 1 2 3 4 5 6 # 开启swap swapon -a swapon -s\t# 显示已使用交换设备的摘要 swapon -p\t# 定制swap优先级 # 关闭swap swapoff -a /proc/sys/vm/swappiness 的值越高，表示内核越倾向于使用 Swap；值越低，表示内核越倾向于保留物理内存。\n创建 swap 分区/文件 centos 中，swap 通过分区实现\nubuntu 中，swap 通过文件实现\nCentOS 和 Ubuntu 都支持使用 swap 分区和 swap 文件作为交换空间。\nswap 分区 适合需要更高性能和稳定性的服务器和长期使用的系统。\nswap 文件 更灵活，适合需要动态调整内存需求的桌面环境或开发环境。\nswap 分区 1 2 3 4 5 6 7 8 9 10 11 # 创建一个分区给swap使用 gdisk / fdisk # 格式化交换分区 mkswap \u0026lt;device\u0026gt; # 应用 swapon -a # 在fstab添加swap UUID=a93dc00b-f6cc-4475-a665-f793d2eabd96 none swap defaults 0 0 swap 文件 1 2 3 4 5 6 7 8 9 10 11 # 创建一个文件给swap使用 dd if=/dev/zero of=/swap.img bs=1G count=3 # 格式化交换文件 mkswap \u0026lt;file\u0026gt; # 应用 swapon -a # 在fstab添加swap /swap.img none swap sw,pri=-1 0 0 移动介质 挂载点通常 在/media 或/mnt 下 。\n访问前，介质必须被挂载 摘除时，介质必须被卸载 按照默认设置，非根用户只能挂载某些设备（光盘、DVD、软盘、USB 等等） 1 lsusb\t# yum -y install dosfstools usbutils RAID：磁盘阵列 HBA 卡（Host Bus Adapter）主机总线适配器，传输数据；虽然 HBA 卡可以集成 RAID 功能，但与专业的 RAID 卡 相比，这类 HBA RAID 卡的 RAID 性能通常较低，特别是在支持 RAID 5、RAID 6 等需要较高计算需求的情况下。\nRAID 卡，数据保护与优化性能；\nIT 模式（Initiator Target），软件层面：卡不带磁盘阵列系统，需要进入系统使用软件重组。 IR 模式（Integrated RAID），硬件层面：卡自带磁盘阵列系统，进入操作系统，已经组好 RAID。 提高 IO 能力，磁盘并行读写\n提高耐用性，磁盘冗余算法来实现\n硬 RAID 类型 名称 特点 RAID-0 读写并行, 速度是最快 没有冗余功能，也不具备容错能力 RAID-1 镜像（Mirroring)\n它将数据同时写入两个磁盘，实现数据的完全冗余。 RAID-4 奇偶校验码存放在独立的奇偶校验盘上对数据按块访问 RAID-5 分布式奇偶校验综合性能最佳的数据保护解决 RAID-6 与 5 类似容错两个磁盘的故障需要更多的磁盘空 间，成本更高，且写入性能相对较差。 RAID-10 RAID-1+RAID-0 RAID-01 RAID-0+RAID-1A RAID-30|50|60|100 JBOD 大容量将多个独立的磁盘驱动器安装在一个底板上，形成一个逻 辑上的大磁盘组。 RAID7 独立存储计算机价格高昂性能最高 RAID-2 汉明码（Hamming Code）校验 错误修正码对数据按位访问被淘汰 RAID-3 把数据分 n 块，放在 n 个盘上，第 n+1 放校验容错信息对数据按位访问被淘汰 系统盘： Raid1 重要数据：Raid10 +热备盘 + CacheCade 一般数据，不做 raid 软 RAID：mdadm multiple devices admin\n标准的软件 RAID（Redundant Array of Independent Disks，独立磁盘冗余阵列）管理工具。\n1 2 3 4 mdadm能够执行创建、管理、监控RAID设备的任务，它使用Linux中的md驱动。具体来说，mdadm具备 以下基本功能： 创建（create）RAID设备。 构建（build）RAID设备。 组装（assemble）RAID设备。 扩展（grow）RAID设备。 管理（manage）RAID设备。 监控（monitor）RAID设备。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 mdadm \u0026lt;device\u0026gt; -C\t# 创建 -A\t# 装配 -F\t# 监控 -D\t# 信息 -r\t# 移除 -a\t# 添加 -G|--grow\t# 调整参数 -S\t# 停止 -n N\t# 用N个块设备创建 -l N\t# RAID等级 -a {yes|no}\t# 自动创建 -c chunk_size\t# chunk大小 -x N\t# 热备份盘个数 cat /proc/mdstat 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 # 创建 mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sda /dev/sdb /dev/sdc -x 1 /dev/sdd mdadm -C /dev/md0 -a yes -l 5 -n 3 -x 1 /dev/nvme0n{1,2,3,4}p1 [root@loong ~]# lsblk /dev/md0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS md0 9:0 0 4G 0 raid5 mkfs.xfs /dev/md0 nvme0n1 └─nvme0n1p1 linux_raid_member 1.2 loong:0 a5596195-c0ad-5fae-d9fe-c0f4e7b5a0b8 └─md0 xfs 68692b1f-6299-4ab4-abca-3b63c5447989 nvme0n2 └─nvme0n2p1 linux_raid_member 1.2 loong:0 a5596195-c0ad-5fae-d9fe-c0f4e7b5a0b8 └─md0 xfs 68692b1f-6299-4ab4-abca-3b63c5447989 nvme0n3 └─nvme0n3p1 linux_raid_member 1.2 loong:0 a5596195-c0ad-5fae-d9fe-c0f4e7b5a0b8 └─md0 xfs 68692b1f-6299-4ab4-abca-3b63c5447989 nvme0n4 └─nvme0n4p1 linux_raid_member 1.2 loong:0 a5596195-c0ad-5fae-d9fe-c0f4e7b5a0b8 └─md0 xfs 68692b1f-6299-4ab4-abca-3b63c5447989 nvme0n5 └─nvme0n5p1 nvme0n6 └─nvme0n6p1 cat /proc/mdstat\t# mdadm日志 # 查看详细信息 mdadm -D /dev/md0 # 增加一块新磁盘 mdadm -G /dev/md0 -n 4 -a /dev/nvme0n5p1 模拟磁盘故障 将故障盘换成新盘，自动恢复数据\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 标记故障盘 mdadm /dev/md0 -f /dev/nvme0n5p1 #会用空闲盘顶上 # 移除故障标识的磁盘 mdadm /dev/md0 -r /dev/nvme0n5p1 # 增加一块新磁盘 mdadm -G /dev/md0 -n 4 -a /dev/nvme0n6p1 # 生成配置文件 mdadm -D -s \u0026gt;\u0026gt; /etc/mdadm.conf # 停止 mdadm -S /dev/md0 # 基于配置启动 mdadm -A -s /dev/md0 # 强制启动 mdadm -R /dev/md0 热备份：快速恢复数据 在 mdadm 中，-x 选项用于指定热备盘（hot spare）。热备盘是一个备用磁盘，当 RAID 阵列中的某个磁盘发生故障时，热备盘会自动替换故障盘，从而帮助阵列快速恢复正常状态，提高数据的可用性和容错性。\n热备盘仅在 RAID 阵列中存在故障磁盘时才会被激活，平时处于备用状态。\nLVM：逻辑卷管理器 在多个物理设备间重新组织文件系统\n弹性的更改LVM的容量\n实现过程 将设备指定为物理卷 用一个或者多个物理卷来创建一个卷组，物理卷是用固定大小的物理区域（Physical Extent， PE）来定义的 在物理卷上创建的逻辑卷， 是由物理区域（PE）组成 可以在逻辑卷上创建文件系统并挂载 PV（Physical Volume，物理卷）\nVG（Volume Group，卷组）\nLV（Logical Volume，逻辑卷）\nPE（Physical Extent，物理区域）：物理卷中可用于分配的最小存储单元。PE的大小是可配置的，默认为4MB。\nLE（Logical Extent，逻辑区域）：逻辑卷中可用于分配的最小存储单元。一个LE对应一个PE。\nLVM分卷 lvm2\npv格式化 1 2 3 4 5 6 # 查看pv信息 pvs pvdisplay\t# 详细信息 # 创建pv pvcreate /dev/sd{b,c,e,f,g,d}1 创建VG 1 2 3 4 5 6 7 # 查看vg信息 vgs vgdisplay\t# 详细信息 # 创建vg vgcreate -s 16M vgname /dev/sdb1 /dev/sd{c,e,f,g,d}1 # -s size指定PE大小 创建LV 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 查看lv信息 lvs lvdisplay\t# 详细信息 lvscan\t# 查看具体路径 # 创建LV lvcreate -l 100 -n lvname vgname # -L size 指定大小 # -l N 指定LE个数 # -n 名字 lvcreate -l 100 -n lv1 testvg lvcreate -L 5G -n lv2 testvg lvcreate -l 20%free -n lv3 testvg lvcreate -l 10%VG -n lv4 testvg lvscan LVM管理 大小管理 扩展 1 2 3 4 5 6 7 8 9 10 11 12 vgextend lvextend # 扩展卷组 vgextend nvlvm /dev/nvme0n6p1 # 扩展逻辑卷 lvextend -L +2G /dev/nvlvm/lvol0 # 扩容文件系统 resize2fs /dev/nvlvm/lvol0 xfs_growfs MOUNTPOINT 1 2 3 4 5 # 扩展卷组 vgextend nvlvm /dev/nvme0n6p1 # 一步到位（逻辑卷，文件系统） lvresize -r -l +100%FREE /dev/nvlvm/lvol0 缩减 缩减有数据损坏的风险，建议先备份再缩减，不支持在线缩减，要先取消挂载，xfs文件系统不支 持缩减\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 vgreduce lvreduce 1. 取消挂载 umount 2. 文件系统检测 e2fsck -f /dev/VG_NAME/LV_NAME xfs_repair /dev/sdb1 3. 缩减文件系统 resize2fs /dev/nvlvm/lvol0 size\t# 到多少大小 ### XFS 文件系统不支持直接缩减大小需要通过备份数据、删除并重新创建分区或逻辑卷、重新格式化和恢复数据的方式来缩减文件系统。 4. 缩减逻辑卷 lvreduce -L 3G /dev/nvlvm/lvol0 5. 重新挂载 mount # 一步到位（文件系统，逻辑卷） lvreduce -L 1G -r dev/nvlvm/lvol0 # 缩减卷组 vgreduce nvlvm /dev/nvme0n6p1 xfs缩减 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 先备份数据 apt install xfsdump # 挂载点后面不要加/ xfsdump -f data.img /data # 卸载文件系统 umount /data # 缩减逻辑卷 lvreduce -L 10G /dev/vg0/lv0 # 格式化 mkfs.xfs -f /dev/vg0/lv0 # 重新挂载 mount /dev/vg0/lv0 /data # 还原数据 xfsrestore -f data.img /data 删除 1 lvremove /dev/VG_NAME/LV_NAME 数据迁移 1 pvmove /dev/sdb1\t# 将sdb1数据迁移走 跨主机迁移 1 2 3 4 5 6 7 8 9 10 1. 在旧系统中，umount 所有卷组上的逻辑卷 2 禁用卷组 vgchange -a n vg0 lvdisplay 3 导出卷组 vgexport vg0 pvscan vgdisplay 1 2 3 4 5 6 7 8 新主机上操作 4 拆下旧硬盘在目标计算机上，并导入卷组： vgimport vg0 5 启用卷组 vgchange -ay vg0 6 mount 所有卷组上的逻辑卷 卸下一块存储 1 2 3 4 5 6 7 8 9 10 # 迁移要卸下存储中的分卷的所有数据 pvmove /dev/sdb* #从 vg 中删除 vgreduce vg /dev/sdb* # 删除 pv pvremove /dev/sdb* # 卸下存储 lvm快照：一次性使用 对逻辑卷（LV）进行备份或创建数据的时间点副本。\n分配一定的空间给快照。当原逻辑卷中的数 据发生变化时，变化的数据会被复制到快照区域，而未变化的数据则继续由原逻辑卷和快照共享。\n原理：保留旧数据（变动前的数据）\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 1. 创建快照： 使用lvcreate命令并添加-s参数来创建一个快照。同时，可以使用-L参数指定快照的大小，以及-n参数指定快照的名称。 2 挂载快照： 将快照挂载到一个空目录上，以便访问快照中的数据。快照通常以只读方式挂载。 3 备份数据： 在快照挂载后，可以使用常规的备份工具（如rsync、tar等）对快照中的数据进行备份。 4 恢复数据（可选）： 如果需要从快照恢复数据，可以先卸载原始逻辑卷，然后使用lvconvert --merge命令将快照合并到主逻辑卷中。这将把快照时的数据状态应用到主逻辑卷上。 5 删除快照： 完成备份或数据恢复后，可以使用lvremove命令删除快照。 注意事项\n1 2 3 4 5 6 7 8 快照大小： 在创建快照时，需要评估原逻辑卷中可能发生变化的数据量，并据此设置快照的大小。如果快照大小设置过小，可能无法容纳所有变化的数据，导致快照失效。 快照与卷组： 快照和原逻辑卷必须位于同一个卷组（VG）中，因为快照需要共享原逻辑卷的物理存储区域（PE）。 快照状态： 可以通过lvscan命令查看系统中逻辑卷和快照的状态。如果快照处于inactive状态，可能是因为原逻辑卷中的数据变化量超过了快照的大小限制。 快照使用 1 2 3 4 5 6 7 #-s 表示快照 #-L 100M 表示大小，大小取决于你要修改多少文件 #-p r 表示该卷只读 lvcreate -n lv1_snapshot -s -L 100M -p r /dev/testvg/lv1 mount /dev/testvg/lv1_snapshot /mount/lvm_snapshot/ # 快照内容与原内容一样，其实此时快照分区没有内容，看到的内容都来自源分区 还原\n1 2 3 4 5 6 # 先卸载 umount /mount/lvm umount /mount/lvm_snapshot/ lvconvert --merge /dev/testvg/lv1_snapshot # 恢复之后快照就没有了，是一次性的 ","date":"2024-11-05T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E7%A3%81%E7%9B%98%E5%AD%98%E5%82%A8%E4%B8%8E%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/","title":"磁盘存储与文件系统"},{"content":"软件相关概念 ABI ABI（Application Binary Interface，应用程序二进制接口）是一种定义了应用程序与操作系统 或者硬件之间交互方式的接口标准，不同的操作系统，他的 ABI 接口是不一样的。\nwindows 与 linux 中的 ABI 格式是不兼容的\nwindows 中的是 PE (Portable Executable ) 格式 Linux 中的是 ELF ( Executable and Linkable Format ) 格式 API API 即 Application Programming Interface，API 可以在各种不同的操作系统上实现给应用程 序提供完全相同的接口。\nposix posix 规约，程序员们在开发程序的时候不用再关心，同一段程序逻辑功能在进行调用的时候，应该 使用哪个平台的哪条底层命令，而只需要使用 基于这些底层平台抽象封装出来的功能函数文件即可，而这个功 能函数文件的调用方式 无论在 linux 平台 还是 windows 平台，都是一样的。\n程序编译：C 预处理（Pre-Processing） 将所有的#define 删除，并且展开所有的宏定义 处理所有的条件预编译指令，比如 #if，#ifdef，#elif，#else，#endif 等 处理#include 预编译指令，将被包含的文件插入到该预编译指令的位置 删除所有的注释，//，/**/ 添加行号和文件标识，以便编译时产生调试用的行号及编译错误警告行号 保留所有的#pragma 编译指令，因为编译需要使用它们 编译（Compiling） 编译过程就是把预处理完的文件进行一系列的词法分析，语法分析，语义分析及优化后，最后生成的汇编 代码\n汇编（Assembling） 汇编是将汇编代码转变成机器码可以执行的命令，每一个汇编语句几乎都对应一条机器指令。汇编相对于 编译过程比较简单，根据汇编指令和机器指令的对照表一一翻译即可\n链接（Linking） 通过调用链接器 ld 来链接程序运行需要的一大堆目标文件，以及所依赖的其它库文件，最后生成可执行文件\n软件链接 静态链接：在程序编译时，将程序中使用的所有库文件（包括标准库和用户自定义库）中的代码和数据都 \u0026ldquo;复制\u0026rdquo; 到最终的可执行文件中。 动态链接：在程序编译时，不将库文件中的代码和数据复制到可执行文件中，而是在程序运行时 \u0026ldquo;由操作系统动态加 载\u0026rdquo; 所需的库文件。 库文件 内核模块（Kernel Modules）：\n.ko\n.o\n位 于/lib/modules/$(uname -r)/kernel/目录下的子目录中。\n共享库（Shared Libraries）:\n.so\n存储在/lib、/usr/lib 或/usr/local/lib 等目录下。\n查看二进制程序所依赖的库文件: ldd rmp：包管理器 手工包安装 不会自动关联依赖包\n1 2 3 4 5 -q\t# 查询安装的软件包基本信息 -ivh\t# 安装软件 -evh\t# 卸载软件 -Uvh\t# 升级软件，无软件，安装 -Fvh\t# 升级软件，无软件，不安装 不要频繁对内核做升级操作 升级后旧配置文件可能被重命名，以 FILENAME.rpmsnew 格式保留 包卸载时，对应的配置文件不会删除，以 FILENAME.rpmsave 格式保留 包查询 1 2 3 4 5 6 7 rpm -qa\t# 所有 -qi\tname\t# info -ql\t# 查看指定的程序包安装后生成的所有文件 -qf\tfilename\t# 查看指定的文件由哪个包安装生成 -qd\t# 查询程序的文档 -qp packge\t# 查询软件包的信息 包检验 1 rpm -K 在检查包的来源和完整性前，必须导入所需要公钥\n1 rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial 包更新日志 1 rpm -q --changelog packageName dnf/yum 管理 rpm 包文件的工具，具有管理包依赖的功能\nC/S 模式：客户端/服务器模式\n服务器上元数据（包依赖结构的管理文件） bh：repodata 目录下\n添加源 1 2 3 4 5 # 在/etc/yum.repos.d/目录下创建配置文件 # 元数据缓存地址 /var/cache/dnf /var/cache/yum 1 2 3 4 5 yum-config-manager --add-repo=https://mirrors.nju.edu.cn/epel/8/Everything/x86_64/ # yum仓库管理 yum repolist yum repolist -v Repo-name yum 命令 1 --no-resolve\t# 不下载依赖 yum list: 已安装的程序包 安装升级删除程序包 1 2 3 4 5 6 7 yum install yum reinstall yum localinstall\t# 安装本地软件包 --installroot\t#指定安装目录 --downloadonly\t#只下载，不安装 1 2 yum remove package yum erase package\t# 可卸载多个包 1 2 3 yum uodate package\t# 更新；要加包名，否则都更新 yum downgrade package\t# 降级 yum check-update\t# 检查可更新 包组管理 多个软件包，打包成组\n一起安装\n1 2 3 4 yum groupinstall yum groupupdate yum groupremove yum groupinfo 自建 yum 仓库 在 yum server 机上搭建 web 服务，保证其它机器能能过 web 服务访问本机 在 yum server 机上搭建 yum 仓服务 在 client 机上将 yum 的 repos 源指向 yum server 机 测试 复制其他的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # yum仓同步工具 dnf reposync --repoid=REPOID --download-metadata -p /path #安装web服务 yum install -y httpd # 自启动web服务 systemctl enable --now httpd.service #将阿里云的extras 源的相关数据下载到本地，给客户端使用 yum reposync --repoid=nju-extras --download-metadata -p /var/www/html/ #将本地光盘中的内容CP到web目录中，给客户端使用 mkdir /cdrom mount /dev/sr0 /cdrom cp -r /cdrom/BaseOS/* /var/www/html/BaseOS 80 端口开放 1 2 3 4 5 6 7 8 9 10 11 12 13 # firewalld端口开放 # 查看开放的端口 firewall-cmd --list-ports # 开放80端口； --zone #作用域 --add-port=80/tcp #添加端口，格式为：端口/通讯协议 # --permanent 永久生效，没有此参数重启后失效 firewall-cmd --zone=public --add-port=80/tcp --permanent # 重启防火墙 firewall-cmd --reload # iptables 端口开放 vim /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT systemctl restart iptables.service ubuntu 防火墙 1 2 3 4 5 ufw # 列出规则 ufw app list # 允许规则 ufw allow \u0026#39;Apache Full\u0026#39; SElinux 1 2 # 为软链接目录添加适当的 SELinux 上下文标记。httpd_sys_content_t chcon -R -t httpd_sys_content_t /ownYum 自建 根据目录中的 rpm 包生成 repodata 元数据\n1 2 3 4 5 6 7 createrepo [OPTION] \u0026lt;directory_to_index\u0026gt; createrepo 所有包的目录的目录（local） local-Package | -repodata dpkg: Ubuntu 软件管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 dpkg -i\t# 安装软件包 --unpack\t# 解包 -V\t# 检查是否安装 -l\t# 列出已安装的包 -c\t.deb\t# 查看包里文件 --info .deb\t# 查看包的信息 -L\t# 查看安装的软件包里的文件 -p\t# 查看可安装的包 -r\t# 删除包 -P\t# 删除包，包括配置 -s\t# 查看包信息 -C\t# 包校验 -S\t# 反查包 apt: Ubuntu 软件管理 客户/ 服务器架构(c/s)+\napt 是 apt-get, apt-cache, apt-config 的常用指令集合。\n仓库结构 dists：元数据 pool：软件包 1 2 3 4 /var/cache/apt/\t# DEB索引清单缓存位置+ apt-cache stats\t# 缓存信息查看 apt-cache depends name\t# 查看软件包的依赖项 apt-cache rdepends name\t# 查看被那些软件包依赖 命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 -d\t# 只下载包，不安装 -q\t# 静默 -y info update\t# 更新元数据 search search --names-only name show\t# 显示细节 install remove purge\t# 删除软件，包括配置 autoremove\t# 删除不在被依赖的软件包 upgrade\t# 更新软件包，不卸载旧包；安全地更新现有包，而不改变系统包的整体结构或依赖关系。 full-upgrade\t# 更新软件包，会卸载旧包；从一个主要版本升级到下一个版本时使用 --no-upgrade\t# 已存在，不升级 --only-upgrade\t# 只升级不安装 # 异常严重报错，修复 apt --fix-broken install deb 打包 准备程序 1 2 3 4 5 6 7 8 9 10 11 #include \u0026lt;stdio.h\u0026gt; int main(){ printf(\u0026#34;\t^\t\\n\u0026#34;); printf(\u0026#34;\t/ \\\t\\\tn\u0026#34;); printf(\u0026#34;\t| |\t\\\tn\u0026#34;); printf(\u0026#34;\t| |\t\\n\u0026#34;); printf(\u0026#34;\t| |\t\\n\u0026#34;); printf(\u0026#34; \\=====/\t\\n\u0026#34;); printf(\u0026#34;\t[*]\t\\n\u0026#34;); return 0; } 1 2 3 4 5 6 7 gcc exCary.c -o exCary file exCary exCary: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=196519d2cc3f5fe087f6d584b25940d315e7ef5c, for GNU/Linux 3.2.0, not stripped du -sh exCary 16K exCary 打包 deb 结构：\n创建 debian 目录\n1 mkdir debian \u0026amp;\u0026amp; cd debian 在 debian 目录下创建 DEBIAN 目录\n1 mkdir DEBIAN \u0026amp;\u0026amp; cd DEBIAN DEBIAN 下放入包管理工具的元数据\n创建 control 文件\n1 2 3 4 5 6 7 8 9 Package: Excalibur Version: 1.0 Architecture: amd64 Maintainer: Loong Installed-Size: 16K Depends: Homepage: nop Description: This is an image. !!!!!!Excalibur!!!!!!\t# 开头有空格 确定软件安装目录；在 debian 下创建 usr/bin 目录，并将 exCary 这个程序放入。\n1 2 3 cd .. mkdir -p usr/bin mv /root/exCary /root/debian/usr/bin/ DEBIAN 下创建，安装后动作文件 postinst，卸载前动作文件 prerm。\n1 2 3 4 5 vim postinst chmod +x postinst vim prerm chmod +x prerm 添加配置文件。\n1 2 3 4 5 6 7 8 9 # 在debian下创建etc/Excalibur目录 mkdir -p etc/Excalibur \u0026amp;\u0026amp; cd etc/Excalibur # 创建配置文件 vim Excalibur.conf # 在DEBIAN下，创建conffiles文件，在里面写入配置文件路径 vim conffiles # /etc/Excalibur/Excalibur.conf 在 debian 目录外，使用 dpkg-deb 命令打包，生成 debian.deb\n1 dpkg-deb --build debian/ 使用 dpkg-name，使包名符合规范\n1 2 dpkg-name debian.deb dpkg-name: info: moved \u0026#39;debian.deb\u0026#39; to \u0026#39;./Excalibur_1.0_arm64.deb\u0026#39; 验证 1 dpkg -i Excalibur_1.0_arm64.deb snap：新软件包格式 软件包目录：/dev/loop0 挂载点，只读。\n一个只读的文件系统。\n​ 应用自身的执行文件、库、 依赖包都被放在这个只读目录，意味着该目录不能被随意篡改和写入。\n一个可写入的区域。\nsquashFS 文件系统的引入，使得 snap 的安全性要优于传统的 Linux 软件包。\n1 2 3 4 5 install remove list find info 每个己安装的包都有一个挂载点。\n源码包部署 部署 make 编译环境（特殊的编程语言，有专用的编译工具；java：ant|maven） 获取源码代码文件（.tar.gz） 解压软件包 编译安装软件 configure 定制配置（没有 configure，使用 autoconf 生成 configure） make 编译生成配置文件 make install 转移文件到安装目录 将可执行文件路径加入 PATH 环境变量 测试 编译环境准备 1 2 3 4 5 6 7 yum install gcc make gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl devel systemd-devel zlib-devel yum install vim lrzsz tree tmux lsof tcpdump wget net-tools iotop bc bzip2 zip unzip nfs-utils man-pages # yum groupinstall \u0026#34;Development Tools\u0026#34; \u0026#34;System Tools\u0026#34; 包组安装不全 apt install build-essential gcc g++ libc6 libc6-dev libpcre3 libpcre3-dev libssl-dev libsystemd-dev zlib1g-dev apt install vim lrzsz tree tmux lsof tcpdump wget net-tools iotop bc bzip2 zip unzip nfs-common manpages-dev # apt install build-essential 包组安装不全 准备源码包 1 wget https://nginx.org/download/nginx-1.26.2.tar.gz 解压源码包 1 tar -xvf nginx-1.26.2.tar.gz 编译配置 缺少依赖库时，./configure 会有报错。make 无法进行。\n如果中间失败，提示缺少依赖项，通过 yum search 查找软件包名称，然后安装，安装后重新执行 ./configure\n1 2 3 4 5 6 7 ./configure --prefix=/nginx --prefix\t# --user\t# 用户名称 --with-\t# 可选模块 make make install 1 ./nginx -s stop ","date":"2024-11-05T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E8%BD%AF%E4%BB%B6%E7%AE%A1%E7%90%86/","title":"软件管理"},{"content":"shell 基础 首行\n1 2 3 4 5 #!/bin/bash #!/usr/bin/python #!/usr/bin/perl #!/usr/bin/ruby #!/usr/bin/lua 1 2 # 加执行权限 chmod +x test.sh 本地执行远程脚本 1 2 3 4 curl http://10.0.0.157/test.sh -s | bash\t# -s 静默 curl http://10.0.0.157/test.sh 2\u0026gt;/dev/null | bash wget -qO - http://10.0.0.157/test.sh | bash 远程执行本地脚本 1 ssh root@10.0.0.157 /bin/bash \u0026lt; test2.sh 子shell：（），{} 1 2 3 4 临时shell环境 - 启动子shell ( 命令;命令;命令; )，在子shell中执行命令列表，退出子shell后,不影响后续环境操作。 临时shell环境 - 不启动子shell { 命令;命令;命令; }, 在当前shell中运行命令列表,会影响当前shell环境的后续操作。左侧要有空格，右侧要有; CA创建\n1 2 3 4 5 6 7 mkdir /tmp/CA; cd /tmp/CA # 生成私钥 (umask 077;openssl genrsa -out ca.key 2048) # 生成证书 openssl req -new -x509 -key ca.key -out ca.crt -days 3650 # 查看证书信息 openssl x509 -in ca.crt -noout -text 脚本实现\n1 2 3 4 5 6 7 8 9 10 # 定制普通环境变量 CA_DIR=\u0026#34;tls\u0026#34; CA_DOMAIN=\u0026#34;$1\u0026#34; CA_KEY=\u0026#39;tls.key\u0026#39; CA_CRT=\u0026#39;tls.crt\u0026#39; # 创建CA证书 mkdir ${CA_DIR} (umask 077; cd ${CA_DIR}; openssl genrsa -out tls.key 2048) openssl req -new -x509 -key ${CA_DIR}/${CA_KEY} -out ${CA_DIR}/${CA_CRT} -subj \u0026#34;/CN=${CA_DOMAIN}\u0026#34; -days 365 1 /bin/bash ca_create.sh www.example.com 开写 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 lscpu | sed -nr \u0026#39;s/^Model name: +(.*)/\\1/p\u0026#39; cat /proc/meminfo | head -n 1 | tr -s \u0026#34; \u0026#34; | cut -d\u0026#34; \u0026#34; -f2,3 lsblk /dev/sda | grep \u0026#34;^sda\u0026#34; | tr -s \u0026#34; \u0026#34; | cut -d\u0026#34; \u0026#34; -f4 cat /etc/os-release | sed -nr \u0026#34;s/^VERSION=\\\u0026#34;(.*)\\\u0026#34;/\\1/p\u0026#34; cho -e \u0026#34;CPU \\c\u0026#34; lscpu | sed -nr \u0026#39;s/^Model name: +(.*)/\\1/p\u0026#39; echo -e \u0026#34;Mem \\c\u0026#34; cat /proc/meminfo | head -n 1 | tr -s \u0026#34; \u0026#34; | cut -d\u0026#34; \u0026#34; -f2,3 echo -e \u0026#34;DISK \\c\u0026#34; lsblk /dev/sda | grep \u0026#34;^sda\u0026#34; | tr -s \u0026#34; \u0026#34; | cut -d\u0026#34; \u0026#34; -f4 echo -e \u0026#34;OS\t\\c\u0026#34; cat /etc/os-release | sed -nr \u0026#34;s/^VERSION=\\\u0026#34;(.*)\\\u0026#34;/\\1/p\u0026#34; cho -e \u0026#34;========================= sysinfo begin ================\\n\u0026#34; echo -e \u0026#34;CPU \\c\u0026#34; echo -e \u0026#34;\\E[1;32m `lscpu | sed -nr \u0026#39;s/^Model name: +(.*)/\\1/p\u0026#39;` \\E[0m\u0026#34; echo -e \u0026#34;Mem \\c\u0026#34; echo -e \u0026#34;\\E[1;32m `cat /proc/meminfo | head -n 1 | tr -s \u0026#34; \u0026#34; | cut -d\u0026#34; \u0026#34; -f2,3` \\E[0m\u0026#34; echo -e \u0026#34;OS \\c\u0026#34; echo -e \u0026#34;DISK \\c\u0026#34; echo -e \u0026#34;\\E[1;32m `lsblk /dev/sda | grep \u0026#34;^sda\u0026#34; | tr -s \u0026#34; \u0026#34; | cut -d\u0026#34; \u0026#34; -f4` \\E[0m\u0026#34; echo -e \u0026#34;\\E[1;32m `cat /etc/os-release | sed -nr \u0026#39;s/^VERSION=\\\u0026#34;(.*)\\\u0026#34;/\\1/p\u0026#39;` \\E[0m\u0026#34; echo -e \u0026#34;\\n========================= sysinfo end ==================\u0026#34; 1 2 bash -n test.sh # 语法检查 bash -x test.sh # 调试执行 变量 1 2 3 4 5 6 7 8 9 10 11 12 13 PS1，PATH，UID，HOSTNAME，$$，BASHPID，PPID，$?，HISTSIZE PPID # 前进程的父进程 ID。 $$ # 当前 shell 进程的 PID $? # 上一个命令的退出状态码。0 表示成功，非 0 表示失败。 $!\t# 前一个命令的PID，方便杀死 $_\t# 表示上输入的一个参数.当这个命令在开头时, 打印输出文档的绝对路径名. $-\t# 显示当前 shell 的选项标志。 $1,$2,.......\t# 第几个参数 $0\t# 脚本文件名，包括路径 $*\t# 所有参数，一个字符串 $@\t# 所有参数，每个参数独立字符 $#\t# 参数的个数 变量命名：只能使用数字、字母及下划线，且不能以数字开头\n1 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 name=\u0026#39;root\u0026#39; #直接字串 name=\u0026#34;$USER\u0026#34; #变量引用 name=`COMMAND` #命令引用 name=$(COMMAND) #命令引用 \u0026#34;$name\u0026#34; # 弱引用，其中的变量引用会被替换为变量值 \u0026#39;$name\u0026#39; # 强引用，其中的变量引用不会被替换为变量值，而保持原字符串 seq 5 1 2 3 4 5 NUM=`seq 5` echo \u0026#34;$NUM\u0026#34; 1 2 3 4 5 echo $NUM 1 2 3 4 5 # \u0026#34;\u0026#34;会保留原格式 # 使用${}给变量圈定范围 echo ${NAME}_$AGE # 查找全局变量F env | grep SHELL # 变量追加 TITLE=CTO TITLE+=:wang echo $TITLE CTO:wang #set 命令会列出所有已定义的 shell 变量和环境变量，以及它们的当前值。输出内容包括用户定义的变量、系统变量和函数。 set # 删除变量 unset \u0026lt;name\u0026gt; # 环境变量 export name=VALUE # 只读变量，不可删除 readonly name=VALUE # 位置变量 $1,$2,.......\t# 第几个参数 $0\t# 命令本身，包括路径 $*\t# 所有参数，一个字符串 $@\t# 所有参数，每个参数独立字符 $#\t# 参数的个数 # 自定义退出码 exit [n] 变量默认值 1 2 3 4 5 6 7 8 9 10 # ${变量名:-默认值} # 有参就为参，无参就为1 a=\u0026#34;$1\u0026#34; echo ${a:-1} # 强制默认值，无论a是什么，a都为1 ${a+1} ${VAR:?error_message} # 解释：如果 VAR 未定义或为空，则显示 error_message 并中止脚本。 设定变量默认值，无参数传来就为默认 展开命令行 把命令行分成单个命令词 展开别名 展开大括号的声明{} 展开波浪符声明 ~ 命令替换$() 和 `` 再次把命令行分成命令词 展开文件通配符*、?、[abc]等等 准备I/0重导向 \u0026lt;、\u0026gt; 运行命令 $- 1 2 set -x # 启用命令跟踪 set +x # 禁用命令跟踪 字符串 1 2 3 4 5 6 7 8 9 10 11 12 str=abcdefg ${#str}\t# 返回字符串长度 4 # 字符串以0开始 # 字符串截取 ${str:0:5}\t# 从0开始，截取5个 ${str:5:5}\t# 从第六个开始，截取5个 ${str::5}\t# 从0开始，截取5个 ${str:0-6:5}\t# 从倒数第6开始，向后截取5个 ${str: -4}\t# 字符串最后四个 printf 1 printf \u0026#34;%d%s\u0026#34; a b 算术运算:$[],$(()),(()) bash 只支持整数，不支持小数\nlet var=expression\nvar=$[expression]\nvar=$((expression))\n((var=expression))\ndeclare -i var=number\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 i=123;j=456; k=i+j;echo $k i+j let k=i+j;echo $k 579 expr 10+20 10+20 expr 10 + 20 30 expr 10 \\* 20 # *需要转义 200 let num1+=1 ((num1+=1)) expr bc:除法小数实现 1 2 3 4 5 -l\t# 实现小数数学运算 -q\t# 静默 echo \u0026#34;scale=3;20/3\u0026#34;|bc echo \u0026#34;20/3\u0026#34;|bc -l 随机变量 1 $RANDOM #取值范围：0-32767 ^:异或 同为假\n异为真\n$() 字符串操作 默认值相关 expr read 1 2 3 4 5 6 read -p \u0026#34;请输入登录用户名: \u0026#34; user # 限制字符数 read -n 6 -p \u0026#34;sss: \u0026#34; aaa # 时长限制 read -t 5 -p \u0026#34;等待5秒后自动退出! \u0026#34; second -d \u0026#39;q\u0026#39;\t# 结束符设定 |：管道通常会创建子 Shell，因此在管道中定义的变量在当前 Shell 中不可见。\n1 2 3 4 5 6 7 8 9 10 11 read i j \u0026lt; test.txt ; echo $i $j 1 2 echo 1 2 | read x y ; echo $x $y 无输出 echo 1 2 | ( read x y ; echo $x $y ) 1 2 echo 1 2 | { read x y ; echo $x $y; } 1 2 条件测试命令 判断某需求是否满足\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 test xxxx [ xxxxx ] [[ xxxxx ]]\t# 判断字符串是否匹配；==（通配符）；=~(正则) # 状态码 0 为true 1 为false # -a 和 -o 需要使用测试命令进行，[[ ]] 不支持 [ EXPRESSION1 -a EXPRESSION2 ]\t# and [ EXPRESSION1 -o EXPRESSION2 ]\t# or [ ! EXPRESSION1 ]\t# 取反 文件判断 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 -a FILE\t# 判断文件是否存在 -e FILE\t# 判断文件是否存在 -s FILE\t# 判断文件是否存在且不为空 -r FILE\t# 判断文件当前用户是否可读 -w FILE\t# 判断文件当前用户是否可写 -x FILE\t# 判断文件当前用户是否可执行 -O FILE\t# 判断文件当前用户是否为所属人 -G FILE\t# 判断文件当前用户是否为所属组 -k FILE\t# 判断文件是否有sticky位 -u FILE\t# 判断文件是否有SUID位 -b FILE\t# 判断文件是否为块设备 -c FILE\t# 判断文件是否字符设备 -d FILE\t# 判断文件是否为目录 -f FILE\t# 判断文件是否为普通文件 -p FILE\t# 判断文件是否为管道 -S FILE\t# 判断文件是否为套接字 -h FILE\t# 判断文件是否为软链接 -L FILE\t# 判断文件是否为软链接 FILE1 -eq FILE2 # 判断文件1是否为新于文件2的硬链接 -t FD\t# 判断文件描述符是否指向一个终端；判断脚本的输入是否来自于用户的终端 FILE1 -nt FILE2\t# 判断文件1是否新于文件2 FILE1 -ot FILE2\t# 判断文件1是否旧于文件2 字符串判断 1 2 3 4 5 6 7 8 9 10 11 12 13 -z STRING\t# 空为真 -n STRING\t# 非空为真 STRING STRING1 = STRING2 STRING1 != STRING2 == != \u0026lt;= \u0026gt;= \u0026lt; \u0026gt; 数学判断；$(())与(()) $(())用于求值返回结果 (())用于求值返回布尔结果 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 # 用于整数的比较 -eq -ne -lt -le -gt -ge a=5 b=10 # $(())用于求值返回结果 # (())用于求值返回布尔结果 if (( a \u0026gt;= b )); then echo \u0026#34;a 大于等于 b\u0026#34; fi # 可以嵌入在条件判断中 if (( $(($a + $b)) \u0026gt; 10 )); then echo \u0026#34;a + b 大于 10\u0026#34; fi # 小数比较 a=5.5 b=10.2 # 使用 bc -l 比较小数 if (( $(echo \u0026#34;$a \u0026lt; $b\u0026#34; | bc -l) )); then echo \u0026#34;$a 小于 $b\u0026#34; fi 其他 1 -v VAR\t# 是否已赋值 test:IP 1 2 3 4 [[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] IP=$1 [[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] \u0026amp;\u0026amp; echo $IP is valid || echo $IP is invalid \u0026amp;\u0026amp;,|| 与组合使用 \u0026amp;\u0026amp; 和 || 可以组合使用，形成类似“if\u0026hellip;else”的逻辑结构。可以用以下方式来表达“如果命令成功则执行 A，否则执行 B”：\n1 2 3 4 5 command \u0026amp;\u0026amp; echo \u0026#34;Success\u0026#34; || echo \u0026#34;Failure\u0026#34; COMMAND1 \u0026amp;\u0026amp; COMMAND2 # 1成功，2执行； 1失败，2不执行 COMMAND1 || COMMAND2 # 1成功，2不执行； 1失败，2执行 ! COMMAND #非,取反 true，false;没有0，1\nif\u0026hellip;fi 1 2 3 4 5 6 7 8 9 if commands then xxxxxx elif commands then xxxxxx else xxxxxx fi case\u0026hellip;esac 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 case $input in case1) xxxx xxxx ;; case2) xxxx xxxx ;; case3) xxxx ;; *)\t# 都没匹配到；default xxxx ;; esac 1 2 3 4 5 6 7 8 9 10 11 12 read -p \u0026#34;Do you agree(yes/no)? \u0026#34; INPUT case $INPUT in [yY]|[Yy][Ee][Ss]) echo \u0026#34;You input is YES\u0026#34; ;; [Nn]|[Nn][Oo]) echo \u0026#34;You input is NO\u0026#34; ;; *) echo \u0026#34;Input fales,please input yes or no!\u0026#34; ;; esac for\u0026hellip;done；(()) 双小括号方法，即((…))格式，也可以用于算术运算，双小括号方法也可以使bash Shell实现C语言风格的变量操作.\n1 2 3 4 for i in item1 item2 ... itemN do xxxx done 1 2 3 4 5 6 for((i=1;i\u0026lt;=9;i++));do for((j=1;j\u0026lt;=i;j++));do printf \u0026#34;\\E[1;$[RANDOM%7+31]m${i}x${j}=$[i*j]\\E[0m\\t\u0026#34; done printf \u0026#34;\\n\u0026#34; done while\u0026hellip;done 1 2 3 4 while condition do xxxx done : 是 Shell 中的一个内建命令，它也是一个始终返回成功状态的空操作符。\nwhile read 1 2 3 4 while read line do 循环体 done \u0026lt; /PATH/FROM/SOMEFILE unitl 1 2 3 4 until condition do command done continue break shift shift [n] 用于将参量列表 list 左移指定次数，缺省为左移一次。\n参量列表 list 一旦被移动，最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时，常用到 shift\nselect function；自定义函数 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 function func_name(){ } func_name(){ } function func_name{ } # 调用，直接函数名 func_name # 引入函数文件 source func_file . func_file # 返回值 return 0 return xxx # 获取返回值 使用 $? # 参数 func_name 1 2 3 4 用$1, $2, ...调用这些参数；还可以使用$@, $*, $#等特殊变量 # 本地变量 # 默认全是全局 # 使用local为本地变量；变量会被限定在函数作用域内，函数结束后就无法在外部访问它。 my_function() { var1=\u0026#34;Hello from function\u0026#34; } my_function echo \u0026#34;$var1\u0026#34; # 输出: Hello from function #***************************************# my_function() { local var1=\u0026#34;Hello from function\u0026#34; } my_function echo \u0026#34;$var1\u0026#34; # 输出为空，或者会提示未定义 环境函数 使子进程也可使用父进程定义的函数\n1 2 export -f function_name declare -xf function_name ","date":"2024-11-02T00:00:00Z","permalink":"https://www.l00n9.icu/p/shell/","title":"SHELL"},{"content":"文件查找 locate：数据库查找 locate 查询系统上预建的文件索引数据库 /var/lib/mlocate/mlocate.db\n查找速度快 模糊查找 非实时查找 搜索的是文件全路径，不仅仅是文件名 可能只搜索用户具备读取和执行权限的目录 1 2 3 4 5 6 7 8 -n\t# 显示n条 -b\t# 匹配文件，不匹配目录 -c\t# 显示数量 -r\t# 使用正则 -d\t# 指定数据库 -q\t# 显示静默 updatedb\t# 更新数据库 find：实时查找 查找速度略慢 精确查找 实时查找 查找条件丰富 可能只搜索用户具备读取和执行权限的目录 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 -maxdepth N\t# 最大搜索目录深度,指定目录下的文件为第1级 -mindepth N # 最小搜索目录深度 -depth\t# 先查文件 -name\t# 文件名查找 -iname\t# 文件名查找，忽略大小写 -inum num\t# inode查找 -samefile name\t# inode与name相同的文件（查找硬链接） -links n\t# 链接数为n的文件或目录 -regex \u0026#34;pattern\u0026#34;\t# 使用正则 -user USERNAME -group GRPNAME -uid UserID -gid GroupID -nouser -nogroup -type TYPE #type 值 f #普通文件 d #目录文件 l #符号链接文件 s #套接字文件 b #块设备文件 c #字符设备文件 p #管道文件 -empty\t#空文件或空目录 -a\t# 与 -o\t# 或 -!\t# 非 -not\t# 非 条件匹配例子，使用（）做分隔\n1 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 -path name -prune\t# 排除name中的文件 [root@ubuntu2204 ~]# find -name \u0026#34;*.txt\u0026#34; ./dir1/fa.txt ./dir1/fb.txt ./test-a.txt ./test-b.txt ./dir4/f-x.txt ./dir4/f-y.txt #排除 dir1 目录中的 txt 文件，但还是会输出 dir1 [root@ubuntu2204 ~]# find -path \u0026#39;./dir1\u0026#39; -prune -o -name \u0026#34;*.txt\u0026#34; ./dir1 ./test-a.txt ./test-b.txt ./dir4/f-x.txt ./dir4/f-y.txt #action 作用在后一个条件上 [root@ubuntu2204 ~]# find -path \u0026#39;./dir1\u0026#39; -prune -o -name \u0026#34;*.txt\u0026#34; -print ./test-a.txt ./test-b.txt ./dir4/f-x.txt ./dir4/f-y.txt #排除多个目录 [root@ubuntu2204 ~]# find \\( -path \u0026#39;./dir1\u0026#39; -o -path \u0026#39;./dir4\u0026#39; \\) -prune -o name \u0026#34;*.txt\u0026#34; -print ./test-a.txt ./test-b.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -size -size +2k -size -10k # 时间戳 #以天为单位 -atime [+|-]N -mtime [+|-]N -ctime [+|-]N #以分钟为单位 -amin [+|-]N -mmin [+|-]N -cmin [+|-]N -mtime：按文件内容的修改时间（Modification Time）查找。 -atime：按文件的访问时间（Access Time）查找。 -ctime：按文件的状态改变时间（Change Time）查找。 find . -mtime n：查找刚好在 n 天前修改过的文件。 find . -mtime +n：查找大于 n 天前（不包括第 n 天）修改的文件。 find . -mtime -n：查找小于 n 天前（包括今天到第 n 天）修改的文件。 根据权限查找 1 2 3 -perm 444\t# 精确匹配 -perm /444\t# 匹配到一位 -perm -444\t# 至少有权限 动作 1 2 3 4 5 6 7 8 9 10 11 12 13 -print\t# 默认 -print0 -ls -fls file\t# 将结果保存到文件file中 -delete -ok COMMAND {} \\;\t# 执行命令，执行前询问 -exec COMMAND {} \\;\t# 执行命令 {}\t#引用查找到的文件名称 find -name \u0026#34;*log\u0026#34; -exec cp {} {}.bak \\; find -amin +15 -ok rm {} \\; 压缩，解压缩 zip，unzip：.zip 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 zip zipfile FILE unzip zipfile FILE # zip -1\t# 快速压缩 -9\t# 最高压缩比 -r\t# 递归压缩目录，到一个包 -u\t# 如果压缩包内有，则更新，如果没有，则追加进去 -f\t# 更新文件 -d\t# 从压缩包中删除 -m\t# 压缩后删除原文件 -z\t# 给压缩包加注释 -P passwd\t# 设置密码 -i # 仅压缩指定文件 -X\t# 不保留额外文件属性 -y\t# 保存链接符号，非链接指向的文件 # unzip -l # 查看压缩包里内容 -n\t# 解压缩，不覆盖 -o\t# 覆盖 -x\t# 指定不需要解压缩的文件 -d\t# 指定解压到的目录 -t\t# 测试完整 -X\t# 解压时，恢复UID，GID -K\t# 解压时，恢复权限 zcat:不解压查看文件 1 2 -d\t# 解压 -l\t# 压缩包内列表 zcat 命令是专门用来查看 .gz 格式的压缩文件内容\n不常用 compress ， uncompress：.Z 1 2 3 4 5 -r\t# 递归压缩文件，压缩文件，不是整个目录 -d\t# 解压 -c \u0026gt; file\t# 将压缩文件另存为 compress fstab uncompress fstab.Z gzip，gunzip：.gz 1 2 3 -k\t# 保留源文件 -r\t# 递归同上 -l\t# 压缩文件信息 bzip2，bunzip2：.bz2 1 2 3 -d -k -N\t# 指定压缩等级 xz，unxz：.xz 1 2 3 -d -k -T\t#多开线程 打包，解包 对多目录与文件进行归档。\ntar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -A\t# 将归档文件（.tar 文件）合并到现有的归档中 -c\t# 创建新的归档 -d\t# 找出归档与文件系统差异 --delete\t# 从归档中删除 -r\t# 追加文件至归档结尾 -t\t# 列出归档内容 -u\t# 仅追加比归档内容新的文件 -x\t# 从归档中解出文件 -v\t# 显示过程 -f\t# 指定压缩包文件 -p # 保留文件权限信息 -z #相当于gzip压缩工具 -j #相当于bzip2压缩工具 -J #相当于xz压缩工具 -h\t# 软链接指向文件也打包 --hard-dereference\t# 硬链接指向文件也打包 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 #只打包，不压缩 tar -cf etc.tar /etc tar -cf etc.tar /etc # 追加 tar -rf test.tar f3.txt passwd # 删除 tar --delete -f test.tar f1.txt f2.txt # 将 additional.tar 的内容追加到 original.tar tar -A -f original.tar additional.tar # 指定目录解包 tar -xf log.tar -C /tmp # 从文件中读取要打包的文件 [root@ubuntu2204 0510]# cat list.txt f1.txt f2.txt [root@ubuntu2204 0510]# tar -zcvf x.tar.gz -T list.txt f1.txt f2.txt # 排除文件，不归档 tar zcvf /root/a.tgz --exclude=/app/host1 --exclude=/app/host2 /app tar zcvf mybackup.tgz -T /root/includefilelist -X /root/excludefilelist split 1 2 3 4 -b size\t# 指定分割大小 -C\tsize\t# 同上，但尽量维持完整性 -d\t# 分割完后，后缀使用数字 -l\t# 指定行数，多少行切一个文件 ","date":"2024-11-01T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E6%96%87%E4%BB%B6%E6%9F%A5%E6%89%BE%E5%8E%8B%E7%BC%A9%E5%BD%92%E6%A1%A3/","title":"文件查找，压缩，归档"},{"content":"\n推荐vim配置 1 /etc/vim/vimrc 1 2 3 4 5 6 7 8 9 set cul set hlsearch set ai set et set tabstop=4 set shiftwidth=4 syntax on VIM 1 2 3 4 5 -m FILE\t# 只读模式 -b FILE\t# 二进制打开 -d FILE1 FILE2\t# 比较文件\t-e FILE\t# ex模式 +N FILE\t# 进入时，到第几行；定位报错位置 1 2 3 4 5 6 7 8 9 :q :wq :x\t# 小写x == wq :r /etc/passwd\t# 读文件内容，并写在光标处 :w test\t# 另存为test :!echo aa\t# 回到终端，执行命令 :r!echo aa\t# 读命令输出，并写在光标处 :X\t# 大写X，密码加密，zip加密，弱 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 地址定界 # ，是以指定行计算 :5,10\t# 5行-10行 :5,+10\t# 5行-光标后10行 :5,-10\t# 5行-光标前10行 # ；是以光标所在行计算 :5;+10\t# 5行-往前10行 :5;-10\t# 5行-往后10行 :.\t# 当前行 :$ :.,$-1 :% :/parttern/ 1 2 3 4 5 6 7 8 9 10 # 命令模式，扩展命令模式 p\t# 粘贴 d\t# 删除 行号，行号d y\t# 复制 行号，行号y # 扩展命令模式 行号，行号t行号\t# 将内容，粘贴到‘行号’后 行号，行号m行号\t# 将内容，移动到‘行号’后 查找并替换 1 2 3 4 5 6 7 s/原/替换/\t# 当前行第一个 s/原/替换/g\t# 当前行所有 %s/原/替换/\t# 所有行第一个 %s/原/替换/g\t# 所有行所有 %s/原/替换/gi\t# 所有行所有，忽略大小写 配置，可在.vimrc 更改，或是扩展命令行更改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 set number\t# 显示行号 set nonumber\t# 不显示行号 set ignorecase\t# 忽略大小写 set ic set autoindent\t# 自动缩进 set ai set paste\t# 复制保留格式\tset list\t# 显示系统字符 set hlsearch\t# 搜索高亮 syntax on\t# 语法高亮 光标跳转 1 2 3 4 5 6 7 8 9 10 11 12 13 w\t# 下个词首 e\t# 下个词尾 b\t# 前个词首 H\t# 页首 M\t# 页之间 L\t# 页底 G\t# 最后一行 gg\t# 第一行 Ctrl+d\t# 后翻半页 Ctrl+u\t# 前翻半页 1 2 3 4 yy\t# 复制整行 dd\t# 删除一行 cc\t# 删除一行后，进入插入模式 # 这些内容都在缓冲区，可以用p键粘贴出来 查找 1 2 /pattern\t# 向前 ?pattern\t# 向后 撤销 1 u 1 2 v\t# 选取，按字符 V\t# 整行选取 多窗口 1 2 3 4 5 6 7 vim -O /var/log/boot.log-20241026 /var/log/boot.log-20241028 /var/log/boot.log-20241024 -o\t# 上下模式 -O\t# 左右模式 :wqall\t# 退出 Ctrl+w,Arrow\t# 窗口切换 单文件窗口分割 1 2 3 4 5 Ctrl+w,s\t# 上下分 Ctrl+w,v\t# 左右分 Ctrl+w,q\t# 取消相邻窗口 Ctrl+w,o\t# 取消所有窗口 Ctrl+w,Arrow\t# 窗口切换 ","date":"2024-10-30T00:00:00Z","permalink":"https://www.l00n9.icu/p/vim/","title":"VIM"},{"content":"文本处理工具 cat 1 -A\t# 显示所有系统符号 hexdump 1 2 3 hexdump -C -n 512 /dev/sda\t# -C 显示ASCII码 # -n 数字 字节长度 more 只能向下翻页，使用空格键或 Enter 键逐步向下滚动。\n一次性加载整个文件内容，因此在查看大文件时可能会遇到卡顿。\nless：比 more 更好用 持双向滚动。可以使用方向键或 Page Up / Page Down 键向上和向下翻页，允许更方便的文件浏览。\n采用逐页加载机制，尤其适合查看大文件，性能更佳，不会一次性加载全部内容。\nhead 1 head -n 10 FILE\t# 前10行输出 tail 1 tail -n 10 FILE\t# 后10行输出 tr -d ：删除所有出现在 SET1 中的字符。\n-s ：将连续重复出现的字符（由 SET1 和 SET2 指定或其他条件）压缩为单一出现。常和字符替换同时使用，以减少重复字符。\n-c ：对 SET1 集合进行补集操作，也就是说对不在 SET1 中的字符进行操作。（例如，tr -dc '0-9' 会删除所有不在0到9之间的字符。）\n-t ：截断 SET1 或 SET2，使得两者长度相同进行处理。该选项在部分系统中可能为默认行为。\n常见用法示例\n大小写转换\n将标准输入中的小写字母全部转换为大写字母：\n1 cat file.txt | tr \u0026#39;[:lower:]\u0026#39; \u0026#39;[:upper:]\u0026#39; 或者：\n1 tr \u0026#39;a-z\u0026#39; \u0026#39;A-Z\u0026#39; \u0026lt; file.txt 删除特定字符\n删除文本中的所有数字字符：\n1 tr -d \u0026#39;0-9\u0026#39; \u0026lt; file.txt 删除所有换行符（将文本行连接成一行）：\n1 tr -d \u0026#39;\\n\u0026#39; \u0026lt; file.txt 压缩重复字符\n将连续的空格压缩为单个空格：\n1 tr -s \u0026#39; \u0026#39; \u0026lt; file.txt 将连续出现的换行符压缩为一个：\n1 tr -s \u0026#39;\\n\u0026#39; \u0026lt; file.txt 删除非数字字符\n保留数字，删除其他所有字符：\n1 tr -cd \u0026#39;0-9\u0026#39; \u0026lt; file.txt 这里 -c 是对字符集取反，-d 是删除该集合字符，因此 -cd '0-9' 即保留数字并删除非数字。\n替换制表符为空格\n有时文件中含有制表符（\\t），想将其转换为单个空格：\n1 tr \u0026#39;\\t\u0026#39; \u0026#39; \u0026#39; \u0026lt; file.txt 多种字符间的映射\n将 abc 转换为 123：\n1 tr \u0026#39;abc\u0026#39; \u0026#39;123\u0026#39; \u0026lt; file.txt 当 SET1 长于 SET2 时，多出来的字符会映射为 SET2 的最后一个字符。例如：\n1 tr \u0026#39;abcd\u0026#39; \u0026#39;12\u0026#39; \u0026lt; file.txt a 映射到 1，b 映射到 2，c 和 d 都映射到 2。\ncut：按列抽取文本 1 2 3 4 5 6 -d\t# 指定分隔符 -f\t# 要显示列 --output-delimiter=\u0026#34;+\u0026#34;\t# 输出是用+替代分隔符 head -n 2 \u0026lt;\u0026lt;\u0026lt; $(ifconfig) | tail -n 1| cut -d \u0026#39; \u0026#39; -f 10 10.0.0.14 paste：合并文件，行行合并 1 2 3 4 5 6 7 8 9 10 11 12 13 14 seq 1 10 \u0026gt; 1.txt printf \u0026#34;%s\\n\u0026#34; {a..g} \u0026gt; 2.txt paste 1.txt 2.txt 1 a 2 b 3 c 4 d 5 e 6 f 7 g 8 9 10 1 2 -d\t# 设定分割符 -s\t# 一列合成一行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 paste -d : 1.txt 2.txt 1:a 2:b 3:c 4:d 5:e 6:f 7:g 8: 9: 10: paste -d : -s 1.txt 2.txt 1:2:3:4:5:6:7:8:9:10 a:b:c:d:e:f:g xargs xargs 可以将管道或标准输入（stdin）数据转换成命令行参数，也能够从文件的输出中读取数据。\nxargs 一般是和管道一起使用。\n1 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 -d\t# 指定分隔符 -E\t# 指定结束符 -l N\t# 一次性读取 N 行 -n\t# 一次执行用多少参数 -p\t# 执行前确认 -r\t# 输入为空，不执行 -t\t# 显示过程 -i\t# 使用{}占位符 -P n\t# 并发 n 执行 -0|--null\t# 用 assic 中的 0 或 null 作分隔符 echo user{1..5} |xargs -t -n 1 useradd seq 60 | xargs -i -P3 you-get https://www.bilibili.com/video/BV1KX4y1S7dT?p ={} ls \u0026#39;a b\u0026#39; f-1.txt f-2.txt f-3.txt # \u0026#39;a b\u0026#39;，被拆分为 find -type f | xargs ls ls: cannot access \u0026#39;./a\u0026#39;: No such file or directory ls: cannot access \u0026#39;b\u0026#39;: No such file or directory ./f-1.txt ./f-2.txt ./f-3.txt find -type f -print0 |xargs -0 ls \u0026#39;./a b\u0026#39; ./f-1.txt ./f-2.txt ./f-3.txt ls 1 2 3 4 5 ls * | xargs -n 1 -i {} rename \u0026#39;{}\u0026#39; \u0026#39;{}.txt\u0026#39; {} ls 1.txt 2.txt 3.txt 4.txt 5.txt 文本分析工具 wc：文本数据统计 1 2 3 4 5 -l\t# 只统计行数 wc story.txt 39 237 1901 story.txt 行数\t单词数 字节数 sort：文本排序 1 2 3 4 -u\t# 去重 -k 数字\t# 指定排序列 -r\t# 倒序 -n\t# 以数字大小排序 uniq：去重 1 2 3 -c\t# 显示重复数 -d\t# 仅显示重复的行 -u\t# 仅显示不重复的行 diff：比较文件 1 diff -u f1.txt f2.txt \u0026gt; f.patch patch：应用差异文件，用于版本更新 1 2 3 4 5 6 7 -b\t# 备份 # 到处差异文件 diff -u 100 102 \u0026gt; 100_102.patch # 将 100 更新为 102 patch -b 100 100_102.patch cmp：对比二进制文件 grep：正则全局搜索并打印行 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 -E\t# 使用 ERG 正则 -F\t# 不正则 -G -P -v\t# 取反，显示没有匹配到的行 -e pattern0 -e pattern1\t# 匹配 0 或 1 -f FILE\t# 从文件中读取匹配规则 -i\t# 忽略大小写 -w\t# 只匹配完整的单词；\u0026#34;root\u0026#34;（不匹配部分字符串，如 rootuser） -B N\t# 显示匹配到的前 N 行；before -A N\t# 显示匹配到的后 N 行；after -C N\t# 显示匹配到的前后 N 行 -n\t# 显示匹配到的行号 -H\t# 显示匹配到的文件名 -o\t# 仅显示匹配到的内容 -d\t# 查找目录 -D\t# 查找设备文件 -r\t# 递归目录，不处理软链接 -R\t# 递归目录，处理软链接 -L|--files-without-match\t# 显示没有匹配上的文件名，只显示文件名 -l|--files-with-matches\t# 显示匹配上的文件名，只显示文件名 -c|--count # 统计匹配到的行数 grep -nir 关键字 /路径 # 大范围文件中，快速检索内容，修改配置 1 2 3 4 5 6 7 8 9 grep -v nologin /etc/passwd grep -v \u0026#34;#\u0026#34; /etc/fstab\t# 不看注释 grep -n bash /etc/passwd\tgrep -C 2 root /etc/passwd\t# -A；-B grep root /etc/passwd | grep bash\t# 且匹配 1 2 3 4 5 6 7 8 9 df | grep \u0026#39;^/dev/sd\u0026#39;\t# ^表示行首匹配 df | grep \u0026#39;^/dev/sd\u0026#39; | grep -oE \u0026#39;\\\u0026lt; [0-9]{1,3}%\u0026#39; | grep -Eo \u0026#39;[0-9]+\u0026#39; # -o 只输出匹配到的 # -E 启动正则 # \\\u0026lt; 匹配开头 # [0-9]{1,3} 1-3 个 0-9 的数字 # % 有百分比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [root@loong ~]# ifconfig | grep -E \u0026#39;[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}\u0026#39; -o 10.0.0.14 255.255.255.0 10.0.0.255 00:50:56:36 **** 7417145\t**** 35391370 **** 127.0.0.1 255.0.0.0 192.168.122.1 255.255.255.0 192.168.122.255 52:54:00:5 **** [root@loong ~]# ifconfig | grep -E \u0026#39;[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\u0026#39; -o 10.0.0.14 255.255.255.0 10.0.0.255 127.0.0.1 255.0.0.0 192.168.122.1 255.255.255.0 192.168.122.255 1 2 3 4 5 6 7 8 9 10 11 12 13 14 \\\u0026lt; \\\u0026gt;\t# 单词边界符 # \\\u0026lt; root 匹配 “root” 出现在单词开头的情况。 # root \\\u0026gt; 匹配 \u0026#34;root\u0026#34; 出现在单词结尾的情况。 # \\\u0026lt; root \\\u0026gt; 表示“完整匹配单词 root”，避免包含其他字符的词被误匹配。 grep -E \u0026#34;^(.*)\\\u0026gt;.* \\\u0026lt;\\1$\u0026#34; /etc/passwd # 去看正则位置锚定 # ^ # (.*) # \\1 # $ sed Sed是从文件或管道中读取一行，处理一行，输出一行；再读取一行，再处理一行，再输出一行，直到 最后一行。\n一次处理一行的设计模式使得sed性能很高，sed在读取大文件时不会出现卡顿的现象。\n1 2 3 4 5 6 7 8 9 10 11 sed option \u0026#39;\u0026lt;匹配条件\u0026gt; [动作]; [动作]\u0026#39; pathOfFile -n\t# 静默模式 -i\t# 直接修改文件；-i.bak，以 bak 文件备份原文件 -i.bak -r\t# 扩展正则 # 带时间戳备份 sed -i.\u0026#34;$(date +%Y%m%d%H%M%S).bak \u0026#34; \u0026#39;s/old_text/new_text/g\u0026#39; filename.txt -ni\t#危险组合，会清空文件 匹配条件\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 数字行数 空\t# 表示所有行 n\t# 表示第 n 行 n, m\t# n 到 m n,+m\t# n 到 n+m $\t# 尾行 ~\t# 表示步进 1~2\t# 奇数行 2~2\t# 偶数行 # 关键字匹配 \u0026#39;/关键字/\u0026#39; # /可用@，#,! 替换 /关键字 1/,/关键字 2/\t# 匹配到 1 的行，到匹配到 2 的行 n,/关键字 1/ 动作\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 p\t# print Ip\t# 忽略大小写，print d\t# 删除 a[\\]text\t# append i[\\]text\t# insert c[\\]text\t# 替换匹配到的整行 s###\t# 替换匹配的内容 w file\t# 保存至 file r file\t# 读取 file =\t# 显示行号 q\t# 结束 sed # 上面的动作应该在参数为-i 的时候使用，不然的话不会有效果 1 2 3 nihao sed1 sed2 sed3 nihao sed4 sed5 sed6 nihao sed7 sed8 sed9 打印 1 2 3 4 5 6 7 sed \u0026#39;2p\u0026#39; sed.txt -n nihao sed4 sed5 sed6 sed -n \u0026#39;/^root/p\u0026#39; /etc/passwd sed -n \u0026#39;/bash$/p\u0026#39; /etc/passwd sed -n -e \u0026#39;1p\u0026#39; -e \u0026#39;3p\u0026#39; sed.txt 替换 1 2 3 4 5 6 7 8 9 sed -i \u0026#39;行号 s/原内容/替换后内容/列号\u0026#39; file # 无行号，代表所有行 # 无列号代表第一个 sed -i \u0026#39;行号 s/原内容/替换后内容/g\u0026#39; file # g，替换所有 sed -i \u0026#39;行号 s#原内容#\u0026amp;新增信息#列号\u0026#39; [文件名] # \u0026amp;代表原内容 1 2 3 4 5 6 sed -i \u0026#39;s#sed#SED#\u0026#39; sed.txt sed -i \u0026#39;2s#SED#sed#\u0026#39; sed.txt sed -i \u0026#39;s#SED#sed#2\u0026#39; sed.txt\t# 第二个匹配到的改变 ip a show ens33 | sed -n \u0026#39;3p\u0026#39; | sed -r \u0026#39;s#.*inet (.*) brd.*#\\1#\u0026#39; 10.0.0.14/24 追加与插入；\\，注意是反斜杠 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 sed -i \u0026#39;行号 a\\增加的内容\u0026#39; 文件名\t# sed -i \u0026#39;行号 a\\增加的内容\u0026#39; 文件名 sed -i \u0026#39;1,3a\\增加内容\u0026#39; 文件名\t# 范围追加 sed -i \u0026#39;行号 i\\增加的内容\u0026#39; 文件名\t# 将内容插入到指定的行 sed -i \u0026#39;1,3i\\增加内容\u0026#39; 文件名\t# 范围插入 # \\ 的作用 [root@ubuntu2204 ~]# sed \u0026#39;2a *******\u0026#39; test.txt aaa bbb ******* ccc bbb [root@ubuntu2204 ~]# sed \u0026#39;2a\\ *******\u0026#39; test.txt aaa bbb ******* ccc bbb 删除 1 2 sed -i \u0026#39;行号 d\u0026#39; 文件名 sed -i \u0026#39;1,3d\u0026#39; 文件名 替换整行 1 2 3 4 5 6 7 sed -i \u0026#39;行号 c\\内容\u0026#39; 文件名 sed -i \u0026#39;1,3c\\内容\u0026#39; 文件名\t# 将 1-3 行替换为‘内容’一行；不是每行都替换 [root@rocky9 ~]# head -n 1 /etc/passwd | sed -n \u0026#39;s/root/\u0026amp;user/1p\u0026#39; rootuser:x:0:0:root:/root:/bin/bash [root@rocky9 ~]# head -n 1 /etc/passwd | sed -n \u0026#39;s/root/\u0026amp;user/gp\u0026#39; rootuser:x:0:0:rootuser:/rootuser:/bin/bash 加载保存 1 2 3 4 sed -i \u0026#39;行号 r 文件名 1\u0026#39; 文件名 sed -i \u0026#39;1,3r 文件名 1\u0026#39; 文件名\t#每行后都加载 sed -i \u0026#39;行号 w 文件名\u0026#39; 文件名 题 1 2 3 4 5 ls | grep -Ev \u0026#39;f-(1|3|5|7)\\.txt\u0026#39; | sed -n \u0026#39;s/.*/rm \u0026amp;/p\u0026#39; | bash [root@ubuntu2204 ~]# ls f-1.txt f-3.txt f-5.txt f-7.txt ls | grep -Ev \u0026#39;f-(1|3|5|7)\\.txt\u0026#39; | sed -En \u0026#39;s/(.*)/rm \\1/p\u0026#39; | bash 1 2 3 4 5 6 7 8 9 10 11 sed -n \u0026#39;/^$/! p\u0026#39; nginx.conf\t# 空行不打印 sed -rn \u0026#39;/^(#|$)/! p\u0026#39; nginx.conf\t# 过滤掉空行和注释行 # 将非#开头的行加# sed -rn ‘s/^[^#]/#\u0026amp;/p’ fstab sed -rn \u0026#39;/^#/! s@^@#@p\u0026#39; fstab sed -rn \u0026#39;s/^[^#](.*)/#\\1/p\u0026#39; fstab # 添加了 net.ifnames = 0 sed -Ei.bak \u0026#39;s/^(GRUB_CMDLINE_LINUX =.*)\u0026#34;$/\\1 net.ifnames = 0 \u0026#34;/\u0026#39; /etc/default/grub sed -Ei \u0026#39;/^GRUB_CMDLINE_LINUX/s#\u0026#34;$# net.ifnames = 0 \u0026#34;#\u0026#39; /etc/default/grub ^(#|$)：匹配以 # 开头的注释行或空行。\n^：匹配行的开头。 #：表示注释行。 $：匹配空行。 ( ... )：分组，# 或 $，即匹配注释或空行。 1 2 3 4 5 echo \u0026#34;/etc/sysconfig/network\u0026#34; |sed -r \u0026#39;s#(^/.*/)([^/]+/?)#\\1#\u0026#39; /etc/sysconfig/ echo \u0026#34;/etc/sysconfig/network\u0026#34; |sed -r \u0026#39;s#(^/.*/)([^/]+/?)#\\2#\u0026#39; network s#(^/.\\*/)([^/]+/?)#\\1#：替换命令，用正则表达式匹配并替换。\n(^/.\\*/)：匹配以 / 开头的路径，直到最后一个斜杠 / 之前。这里用括号将其分组为 \\1，表示路径的父目录。 ([^/]+/?)：匹配最后一个文件或目录的名称，[^/]+ 表示一个或多个非斜杠字符。 \\1：替换内容，仅保留第一个分组（即父目录路径部分），去除最后一个文件或目录的名称。 [^/]+：\n[^/]：匹配除斜杠 / 之外的任何字符。方括号内的 ^ 表示“非”或“排除”。 +：表示前面的模式（即 [^/]）匹配一次或多次。因此，[^/]+ 匹配连续的、非斜杠的字符序列，代表路径中的最后一个文件或目录名称。 /?：\n/：匹配路径中的斜杠。 ?：表示前面的 / 是可选的，即可以匹配零次或一次。 所以 /? 表示最后的文件或目录名后面可以带有一个斜杠，也可以没有。 1 2 3 sed \u0026#39;/^#/d;/^$/d\u0026#39; nginx.conf sed -r -e \u0026#34; s/listen.*;/listen\\t $port;/\u0026#34; -e \u0026#39;/server_name/c\\\\tserver_name\u0026#39;$(hostname):$port\u0026#39;;\u0026#39; nginx.conf awk 过滤、提取、运算为一体\n每一行是一条记录\n每一列是一个字段\n字段与字段的分隔符默认是一个或多个空格或tab制表符.\n工作方式是逐行\n1 2 3 awk [参数] \u0026#39;BEGIN 段 [动作] END 段\u0026#39; [文件名] -F\t# 指定分隔符 -v\t# 设置内置变量 内置变量 1 2 3 4 5 6 7 8 9 10 11 12 13 FILENAME\t# 当前文件名 FS\t# 输入，字段分隔符\tField Separator OFS\t# 输出，字段分隔符\tOutput Field Separator RS\t# 输入，行分隔符\tRecord Separator ORS\t# 输出，行分隔符\tOutput Record Separator NF\t# 每行对应的字段数\tNumber of Fields NR\t# 行号\tNumber of Records FNR\t# 各个文件的行号\tFile Number of Records ARGC\t# 命令参数个数 ARGV [n]\t# 命令参数内容 print 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $0\t# 整行，不分割 $1\t# 第一列 $n\t# 第 n 列 $NF\t# 最后一个列 NR\t# 行号 awk -v OFS =\u0026#39;:\u0026#39; \u0026#39;{print $0}\u0026#39; awk nihao awk1 awk2 awk3 nihao awk4 awk5 awk6 nihao awk7 awk8 awk9 awk -v OFS =\u0026#39;:\u0026#39; \u0026#39;{print $1,$ 2}\u0026#39; awk nihao: awk1 nihao: awk4 nihao: awk7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 awk \u0026#39;{print $1\u0026#34;\\t\u0026#34;$ 3}\u0026#39; awk.txt # 动作执行的次数与文件行数一致 awk \u0026#39;{print \u0026#34;hello awk\u0026#34;}\u0026#39; awk # 指定输出行数 awk \u0026#39;NR \u0026gt;= 2 \u0026amp;\u0026amp; NR \u0026lt;= 4 {print NR, \u0026#34;hello awk\u0026#34;}\u0026#39; awk awk -F \u0026#39;[:/.]+\u0026#39; \u0026#39;{for (i = 1; i \u0026lt;= 3; i++) printf \u0026#34;%s \u0026#34;, $i; print \u0026#34;\u0026#34;}\u0026#39; domain awk \u0026#39;{printf \u0026#34;%d--%s--%s\\n\u0026#34;, NR, $1,$ NR}\u0026#39; awk awk \u0026#39;BEGIN{print 2*3}\u0026#39; 6 awk \u0026#39;{print NR, $1\u0026#34;\\t\u0026#34;$ 3}{print NR,$2}\u0026#39; awk 1 nihao awk2 1 awk1 2 nihao awk5 2 awk4 3 nihao awk8 3 awk7 4 awk11 4 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 80 81 82 83 84 85 86 87 awk -F \u0026#34;:\u0026#34; \u0026#39; BEGIN { printf \u0026#34;--------------------------\\n%-17s|%19s|\\n---------------------------\\n\u0026#34;, \u0026#34;用户名\u0026#34;, \u0026#34;shell 类型\u0026#34; } { printf \u0026#34;%-20s|%21s|\\n---------------------------\\n\u0026#34;, $1, $ 7 } END { printf \u0026#34;用户总数: %2d\\n\u0026#34;, NR }\u0026#39; /etc/passwd # %s # %20s 20 个字符宽度，中文占 2 字符宽度 # %-20s\t左对齐，默认右对齐 -------------------------- 用户名 | shell 类型| --------------------------- root | /bin/bash| --------------------------- bin | /usr/sbin/nologin| --------------------------- daemon | /usr/sbin/nologin| --------------------------- adm | /usr/sbin/nologin| --------------------------- lp | /usr/sbin/nologin| --------------------------- sync | /bin/sync| --------------------------- shutdown | /sbin/shutdown| --------------------------- halt | /sbin/halt| --------------------------- mail | /usr/sbin/nologin| --------------------------- operator | /usr/sbin/nologin| --------------------------- games | /usr/sbin/nologin| --------------------------- ftp | /usr/sbin/nologin| --------------------------- nobody | /usr/sbin/nologin| --------------------------- systemd-coredump | /sbin/nologin| --------------------------- saslauth | /sbin/nologin| --------------------------- libstoragemgmt | /sbin/nologin| --------------------------- rpc | /sbin/nologin| --------------------------- tss | /sbin/nologin| --------------------------- dhcpd | /sbin/nologin| --------------------------- dnsmasq | /usr/sbin/nologin| --------------------------- sshd | /sbin/nologin| --------------------------- dbus | /sbin/nologin| --------------------------- polkitd | /sbin/nologin| --------------------------- unbound | /sbin/nologin| --------------------------- qemu | /sbin/nologin| --------------------------- rpcuser | /sbin/nologin| --------------------------- cockpit-ws | /sbin/nologin| --------------------------- cockpit-wsinstance | /sbin/nologin| --------------------------- chrony | /sbin/nologin| --------------------------- tcpdump | /sbin/nologin| --------------------------- nginx | /sbin/nologin| --------------------------- ntp | /sbin/nologin| --------------------------- noob | /bin/bash| --------------------------- loong | /bin/bash| --------------------------- 用户总数: 34 1 2 3 4 5 6 7 [root@loong vim]# awk \u0026#39;BEGIN{FIELDWIDTHS = \u0026#34;5 2 8\u0026#34;}NR == 1{print $1,$ 2,$3}\u0026#39; /etc/passwd root: x: 0:0:Supe [root@loong vim]# cat /etc/passwd root:x:0:0:Super User:/root:/bin/bash # FIELDWIDTHS = \u0026#34;5 2 8\u0026#34; # 5 个字符为 $1；2=$ 2；8 =$3 自定义变量 1 2 3 4 5 awk -v var1 = abc \u0026#39;BEGIN{print var1}\u0026#39; awk -v var1 = abc -v VAR1 = 123 \u0026#39;BEGIN{print var1, VAR1}\u0026#39; awk \u0026#39;BEGIN{name = \u0026#34;shuji\u0026#34;; print name}\u0026#39; awk -v var1 = abc \u0026#39;BEGIN{print var1; var1 = \u0026#34;def\u0026#34;; print var1}{print var1}\u0026#39; /etc/os-release 匹配运算 1 2 3 4 5 ~ !~ awk -F \u0026#39;:\u0026#39; \u0026#39;$1 ~ \u0026#34;^[a-d].*\u0026#34; {print $ 0}\u0026#39; /etc/passwd awk -F \u0026#39;:\u0026#39; \u0026#39;$1 !~ \u0026#34;^[a-d].*\u0026#34; {print $ 0}\u0026#39; /etc/passwd x?x:x ture前\nfalse后\n1 awk -F: \u0026#39;{$3\u0026gt;=1000?utype=\u0026#34;Common\u0026#34;:utype=\u0026#34;Sys\u0026#34;; printf \u0026#34;%-20s:%12s\\n\u0026#34;,$ 1, utype}\u0026#39; /etc/passwd 条件判断 if-else 1 awk -F: \u0026#39;{if($3\u0026lt;=100){print \u0026#34;\u0026lt;=100\u0026#34;,$ 3}else if ($3\u0026lt;=1000){print \u0026#34;\u0026lt;=1000\u0026#34;,$ 3} else{print \u0026#34;\u0026gt; 1000\u0026#34;,$3}}\u0026#39; /etc/passwd swich-case 1 awk -F: \u0026#39;{switch($3){case 0:print \u0026#34;root\u0026#34;,$ 3; break; case /^[1-9][0-9]{0,2}$|1000/:print \u0026#34;sys user\u0026#34;,$ 3; break; default: print \u0026#34;common user\u0026#34;,$3; break;}}\u0026#39; /etc/passwd while 1 2 3 awk -v i = 1 -v sum = 0 \u0026#39;BEGIN{while(i \u0026lt;= 100){sum+= i; i++}; print sum}\u0026#39; awk \u0026#39;BEGIN{ total = 0; i = 1; do{total+= i; i++;}while(i \u0026lt;= 100); print total}\u0026#39; for 1 2 3 4 5 6 7 8 9 10 echo \u0026#39;dsFUs34tg*fs5a8ar%$#@\u0026#39; | awk -F \u0026#34;\u0026#34; \u0026#39; { str = \u0026#34;\u0026#34; # 初始化 str 为空字符串 for (i = 1; i \u0026lt;= NF; i++) { if ($i ~ /[0-9]/) { # 如果 $ i 是数字字符 str = (str $i) # 拼接数字字符到 str } } print str # 输出拼接后的数字字符串 }\u0026#39; continue 和 break next 下一行处理（awk自身循环）\n数组 判断索引存不存在\n1 2 awk \u0026#39;BEGIN{array [\u0026#34;i\u0026#34;] = \u0026#34;x\u0026#34;; array [\u0026#34;j\u0026#34;] = \u0026#34;y\u0026#34; ; print \u0026#34;i\u0026#34; in array, \u0026#34;y\u0026#34; in array }\u0026#39; 0 1 遍历数组\n1 2 3 4 5 6 7 8 awk \u0026#39;BEGIN { a [\u0026#34;x\u0026#34;] = \u0026#34;welcome\u0026#34; a [\u0026#34;y\u0026#34;] = \u0026#34;to\u0026#34; a [\u0026#34;z\u0026#34;] = \u0026#34;Magedu\u0026#34; for (i in a) { print i, a [i] } }\u0026#39; 1 2 3 4 5 6 7 8 9 awk \u0026#39;{ ip[$1]++ } END { for (i in ip) { if (ip [i] \u0026gt;= 1000) { system(\u0026#34;iptables -A INPUT -s \\\u0026#34;\u0026#34; i \u0026#34;\\\u0026#34; -j REJECT\u0026#34;) } } }\u0026#39; nginx.access.log-20200428 内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 int()\t# 转为 int sqrt()\t# 平方根 srand()\t# 设置 rand 种子 rand()\t# 随机数 # 字符串类 length() strtonum()\t# 0 开头，8 进制；0x 开头，16 进制 tolower() toupper() index(str, substr)\t# 在 str 中查找 substr，有，返回索引；无，返回 0 split(str, arr, 分隔符) match() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 awk \u0026#39;BEGIN{a = sprintf(\u0026#34;%s-%d-%s\u0026#34;, \u0026#34;abc\u0026#34;,23, \u0026#34;ert\u0026#34;); print a}\u0026#39; awk \u0026#39;BEGIN{v = \u0026#34;nsfadsafdsaf\u0026#34;; print length(v)}\u0026#39; awk \u0026#39;BEGIN{str = \u0026#34;nsfad\u0026#34;; print index(str, \u0026#34;ns\u0026#34;)}\u0026#39; 1 awk \u0026#39;BEGIN{v = \u0026#34;abcdefgh\u0026#34;; print substr(v,3,3)}\u0026#39; cde awk \u0026#39;BEGIN{split(\u0026#34;abc-def-gho-pq\u0026#34;, arr, \u0026#34;-\u0026#34;, seps); print length(arr), arr [3], seps [1]}\u0026#39; 4 gho - awk \u0026#39;BEGIN{str = \u0026#34;safdsajfkdsajlfjdsl\u0026#34;; print match(str,\u0026#34; j.*s \u0026#34;)}\u0026#39; 7 awk \u0026#39;BEGIN{str = \u0026#34;safdsajfkdsajlfjdsl\u0026#34;; match(str,\u0026#34; j.*s \u0026#34;, arry); print arry [0]}\u0026#39; jfkdsajlfjds 1 2 3 4 5 6 7 8 systime() awk \u0026#39;BEGIN{print strftime()}\u0026#39; # 系统命令 system(cmd) awk \u0026#39;BEGIN{system(\u0026#34;hostname\u0026#34;)}\u0026#39; isarray() 1 2 3 4 [root@loong vim]# awk \u0026#39;BEGIN{v =(\u0026#34;aa\u0026#34; \u0026#34;bb\u0026#34; 11); print isarray(v)}\u0026#39; 0 [root@loong vim]# awk \u0026#39;BEGIN{v [1] =(\u0026#34;aa\u0026#34; \u0026#34;bb\u0026#34; 11); print isarray(v)}\u0026#39; 1 自定义函数 1 2 3 4 5 function name ( parameter, parameter, ... ) { statements return expression } awk \u0026#39;function test(){print \u0026#34;hello test func\u0026#34;}BEGIN{test()}\u0026#39; ","date":"2024-10-30T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86%E5%B7%A5%E5%85%B7/","title":"文本处理工具"},{"content":"\nPerl正则；-P 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 # 单字符 .\t# 任意字符（\\n除外） \\d\t# 数字 \\w\t# 数字，字符，下划线 \\s\t# 空格 []\t# 多选一 [0-9] [a-z] [^]\t# 取反 #量词 *\t# 0到多 +\t# 1到多 ?\t# 0或1 {N}\t# N个 {M,N}\t# M到N个 # 断言 ^\t# 开头 $\t# 结尾 \\b\t# 单词断开 同\\\u0026lt;,\\\u0026gt; # 分组引用 ((for)(ward)) \\2 = for \\1 = forward \\3 = ward \\0 == \u0026amp; 正则 基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 .\t# 匹配单个任意字符（除\\n） []\t# 匹配指定范围的单个字符 [^]\t# 匹配指定范围外的单个字符 [:alnum:]\t# 匹配字母数字 [:alpha:]\t# 匹配字母 [:lower:]\t# 匹配小写字母 [:upper:]\t# 匹配大写字母 [:blank:]\t# 匹配空格与制表符 [:space:]\t# 匹配各种空白符 [:cntrl:]\t# 匹配不可打印字符 [:digit:]\t# 匹配数字 [:xdigit:]\t# 匹配十六进制数字 [:graph:]\t# 匹配可打印的非空白符 [:print:]\t# 匹配可打印字符 [:punct:]\t# 匹配标点 \\s\t# 匹配任何空白符\t[\\f\\r\\t\\v] \\S\t# 匹配任何非空白符\t[^\\f\\r\\t\\v] \\w\t# 匹配任何字符 \\W\t# 匹配任何非字符 范围匹配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ls /etc/ | grep \u0026#39;rc[.0-6].\u0026#39; rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rc.d rc.local ls /etc/ | grep \u0026#39;rc[.0-6]\\.\u0026#39;\t# \\.匹配一个实际的点号 rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d 匹配次数 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 *\t# 任意长度 .*\t# 任意字符任意长度 \\?\t# 长度\u0026gt;=0 \\+\t# \u0026gt;=1 \\{n\\}\t# =n \\{m,n\\}\t# \u0026gt;=m,\u0026lt;=n \\{,n\\}\t# \u0026lt;=n \\{m,\\}\t# \u0026gt;=m [root@loong ~]# echo \u0026#34;1 222 3\u0026#34; | grep \u0026#34;1\\{1\\}\u0026#34; 1 222 3 [root@loong ~]# echo \u0026#34;1 222 3\u0026#34; | grep \u0026#34;1\\{2\\}\u0026#34; [root@loong ~]# [root@loong ~]# echo \u0026#34;1 222 3\u0026#34; | grep \u0026#34;1\\{,2\\}\u0026#34; 1 222 3 [root@loong ~]# echo \u0026#34; 222 3\u0026#34; | grep \u0026#34;1\\{,2\\}\u0026#34; 222 3 [root@loong ~]# [root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E \u0026#39;-?[0-9]+\u0026#39; grep: invalid option -- \u0026#39;?\u0026#39; Usage: grep [OPTION]... PATTERNS [FILE]... Try \u0026#39;grep --help\u0026#39; for more information. [root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E \u0026#39;\\-?[0-9]+\u0026#39; -1 -2 123 -123 234 [root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E -- \u0026#39;-?[0-9]+\u0026#39; -1 -2 123 -123 234 [root@ubuntu2204 ~]# echo -1 -2 123 -123 234 |grep -E \u0026#39;(-)?[0-9]+\u0026#39; -1 -2 123 -123 234 # -被识别成选项开头的- # 使用--结束表示选项的结束 位置锚定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ^\t# 开头 $\t# 结尾 ^pattern$\t# 一行是pattern ^$\t# 空行 ^#\t# 开头注释 \\\u0026lt;\t# 词首 \\\u0026gt;\t# 词尾 \\\u0026lt;pattern\\\u0026gt;\t# 匹配整个词 #所有非空行 grep -v \u0026#34;^$\u0026#34; /etc/profile #所有非注释行 grep \u0026#34;^[^#]\u0026#34; /etc/profile #排除所有空行和注释行 grep -v \u0026#34;^$\u0026#34; /etc/profile | grep -v \u0026#34;^#\u0026#34; /etc/profile grep -v \u0026#39;^$\\|^#\u0026#39; /etc/profile 分组 （）：将多个字符捆绑在一起，作为一个整体\n引用分组：\\1,\\2,\\3\n\\0表示匹配到的所有字符\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@loong ~]# echo \u0026#34;hello 123\u0026#34; | sed -E \u0026#39;s/([0-9]+)/\\1abc/\u0026#39; hello 123abc [root@loong ~]# echo \u0026#34;hello 123\u0026#34; | sed -E \u0026#39;s/[0-9]+/\\0abc/\u0026#39; hello 123abc [root@loong ~]# echo \u0026#34;hello 123\u0026#34; | sed -E \u0026#39;s/[0-9]+/abc/\u0026#39; hello abc [root@loong ~]# echo \u0026#34;hello 123\u0026#34; | sed -E \u0026#39;s/[a-z]+/\\0abc/\u0026#39; helloabc 123 echo abcabcabc | grep \u0026#34;\\(abc\\)\\{3\\}\u0026#34; # 前三有.； ifconfig ens33 | grep -o \u0026#34;\\([0-9]\\{1,3\\}\\.\\)\\{3\\}[0-9]\\{1,3\\}\u0026#34; | head -n 1 |：或 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 注意|的范围 #a或b a\\|b #12a 或 b 12a\\|b #12a 或 12b 12a\\|12b 12\\(a\\|b\\) 12[ab] # 排除空行和#开头的行的四种写法 ^# |(管道) ^$ ^#\\|^$ ^\\(#\\|$\\) ^[^#]\t# 匹配开头字符非#的行；空行没有字符，不符合开头字符的前提条件，所有不被匹配到； []里的^表示非，^在[]外表示开头 ","date":"2024-10-30T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E6%AD%A3%E5%88%99/","title":"正则"},{"content":"linux安全模型 Authentication：认证，验证身份 Authorization：授权，不同权限 Accounting：审计 用户 管理员：uid 0 普通用户 系统用户：uid 1-999，给后台程序使用如mysql，nginx 登录用户：uid 1000+ 用户组 一个用户可以是一个或多个组 用户组可以为空 primary group（主组）：私有组，必须有且只有一个，创建时会创建同名的主组 附加组：用户可以加入除主组外的其他组 安全上下文 用户，程序，进程，能访问的资源在权限上保持一致。\n用户与组的配置相关文件 /etc/passwd： 用户及其属性uid，gid /etc/shadow：用户密码及属性 /etc/group：组及其属性 /etc/gpasswd：组密码及其属性 getent：用于查询系统数据库 get entries\ngetent basename key\nchsh：修改用户sh -s shell路径\nchsh -s /bin/sh root\nshadow 禁用用户时可在密码字段前加上！\nusermod -L jose\nusermod -U jose # 解锁\nvipw \u0026amp; vigr 安全编辑passwd，group文件\npwck \u0026amp; grpck 检查passwd，group文件\n管理用户与组 用户管理：\nuseradd usermod userdel 组管理：\ngroupadd groupmod groupdel groupmod：组修改 -n 组改名\n例 1 2 3 4 5 6 7 8 9 10 11 12 # 先创建用户组，这样创建用户时可指定 groupadd -g 111 -r loong\t# -g 指定gid，-r系统组 useradd -u 111 -g loong -s /bin/bash -d /home/loong -M -r loong # -u，指定uid；-g，指定组；-s，指定shell；-d指定家目录；-M，不创建家目录；-r，系统用户 # 创建用户 useradd looong adduser -D #查看默认的参数 # /etc/skel/，是家目录模板 批量创建用户 1 2 3 4 5 cat user.txt u1:123456:1024:1024::/home/u1:/bin/bash u2:123456:1025:1025::/home/u2:/bin/bash newusers user.txt 批量改口令 1 2 3 4 5 6 7 8 9 10 cat pwd.txt u1:1234567 u2:1234567 chpasswd \u0026lt; pwd.txt chpasswd \u0026lt;\u0026lt;EOF \u0026gt; u1:1234567 \u0026gt; u2:1234567 \u0026gt; EOF SHA512加密 openssl passwd -6 123456\n-6 指定SHA512\nsu 1 2 3 su username su - username\t# 会读取配置文件 su -s /bin/bash mail\t# nologin账户，可以指定shell，达到登录目的 不切换用户，使用它的权限执行 1 su - loong -c \u0026#34;touch jose-2.txt\u0026#34; passwd：修改，设置密码 passwd -e jose\nexpired 到期\njose在下次登录后，会让它修改密码\ngpasswd：更改组成员与密码 1 2 3 4 5 gpasswd -a loong group1\t# 向组添加成员 gpasswd group1\t# 设置组密码 gpasswd -d loong group1\t# 移除组成员 groupmems：更改，查看组成员 1 groupmems -l group1\t# 列出组成员 groups：列出自己的组列表 newgrp：临时切换组 1 newprp group2 # 切换之后创建的文件属组就是group2 文件权限管理 文件所属人所属组操作 root 的权限不受文件的权限位\nchown：设置所属人，所属组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 也可使用uid，gid修改 chown jose: a2.txt\t# 人与组都修改了 chown :jose a2.txt\t# 只改了组 chown jose:jose a2.txt # 都修改 chown --reference=f1.txt f2.txt\t# 根据文件1修改文件2 chown -R jose.tom dir1/\t# 修改文件夹下所有 chown mage --dereference a.link\t# 修改连接指向的文件 chown mage --no-dereference a.link # 修改链接文件本身 chgrp 同上\n文件权限 r和w权限对root 用户无效，对没有读写权限的文件，root用户也可读可写\n只要所有者，所属组或other三者之一有x权限，root就可以执行\n创建文件，初始权限是644\n创建目录，初始权限是755\nLinux中的目录和文件的权限区别？分别说明读，写和执行权限的区别 r 4\n文件：读其中内容 目录：查看目录下内容，但不能看文件里内容 w 2\n文件：修改文件\n目录：在目录下创建删除重命名；\n写权限与执行权限的关系：要在目录中创建、删除、重命名文件，不仅需要写权限，还需要执行权限.\nx 1\n文件：执行文件 目录：允许进入目录 chmod：修改文件权限 \u0026ndash;reference=FILE\n-R|\u0026ndash;recursive\n1 2 3 4 5 chmod u=r,g=w,o=x f2 chmod u+w,g-x,o-r f3 chmod a=rwx f4 chmod 644 a1 删除权限的特殊性：在 Linux 中，删除文件或目录的权限取决于该文件所在目录的写权限，而不取决于文件本身的权限。这意味着即使文件只读，如果用户对目录有写权限，仍然可以删除文件。 1 2 3 4 5 [loong@loong t]$ chmod u-rwx 1.log [loong@loong t]$ cat 1.log cat: 1.log: Permission denied [loong@loong t]$ rm -f 1.log [loong@loong t]$ ls\t# 删除成功 umask：权限掩码 掩码是用默认权限减去掩码\n文件的默认权限是644\n目录的默认权限是755，因为目录需要执行权限来允许进入目录、查看和操作目录内容。\n默认umask-022\n1 2 3 4 5 6 7 8 9 umask -p umask 0022 # 第一位 0：特殊权限位，不常用，一般设为 0。 # 第二位 0：影响文件所有者的权限（不做任何限制）。 # 第三位 2：影响组的权限，禁止写权限。 # 第四位 2：影响其他用户的权限，禁止写权限。 umask -S u=rwx,g=rx,o=rx 特殊权限 SUID： 设置SUID位的主要作用是使普通用户在执行这个文件时，临时获得文件所有者（通常是root）的权限。\n二进制文件：二进制文件执行后，进程属于文件的所属人，而不是执行的人（无SUID，进程属于执行人） 目录：无意义 1 2 3 4 # 只有文件的所有者或者root用户可以更改文件的SUID（Set User ID）权限位。 chmod u+s FILE chmod 4xxx FILE chmod u-s FILE SGID： 二进制文件：执行该文件的用户将以文件所属组的权限来运行它，而不是以用户本身的组权限来运行。 目录：使目录下创建的文件的所属组为目录的所属组（而不是创建者的默认组）。 大写的S 表示SGID位已设置，但组用户没有执行权限。这种设置会使SGID没有实际效果，因为没有执行权限。\n小写的s 才是设置成功。\n1 2 3 chmod g+s FILE chmod 2xxx FILE chmod g-s FILE STICKY： 具有目录写权限的通常用户可以删除该目录中的任何文件，无论该文件的权限或拥有权。\n删除文件不仅需要目录的写权限，还需要执行权限，因为删除操作需要“进入”目录并修改其内容。\n文件：无意义 目录：使只有目录下的文件的所属人，目录所有者和root才能删除文件。 1 2 3 chmod o+t DIR chmod 1xxx DIR chmod o-t DIR 目录所有者仍然拥有删除任何文件的权限，就算设置了STICKY，即便文件由其他用户创建。\nchatrr：设置文件的特殊属性 Change Attributes\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +attribute -attribute =attribute a\t# 文件只能追加内容，无法修改或删除已有内容。对于日志文件，这个属性非常有用。可复制，可查看 A\t# 禁止访问时间更新。访问文件时不更新访问时间。 # 适合减少频繁访问时间更新的文件的I/O负载。 i\t# 文件无法被修改、删除、重命名，甚至无法创建硬链接。可复制，可查看 # 即使是root用户也不能更改此文件，适合保护关键系统文件。 s\t# 安全删除属性。当文件被删除时，其数据会被覆盖，防止恢复。 # 这个属性对数据敏感性高的文件较为适用。 u\t# 可恢复删除属性。删除文件时，系统保留其数据，方便恢复。 lsattr\t# 显示文件的特殊属性 ACL：访问控制列表 ACL生效顺序：\n​\t所有者，自定义用户，所属组，自定义组，其他人\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 setfacl FILE|DIR\t# 可设置ACL权限 getfacl FILE|DIR\t# 可查看设置的ACL权限 -rw-r--r--+ 1 root root 10 Jun 26 20:19 f1\t#有+号 setfacl -m u:noob:- f1.log\t# noob权限全无 setfacl -m u:noob:rw f1.log\t# noob：rw setfacl -m u:noob:r f1.log\t# noob：r setfacl -m g:noob:- f1.log\t# noob组权限全无 setacl f1.log f2.log\t# f1的acl给f2 getfacl f1 | setfacl --set-file=- f2\t# 通过管道 setfacl -x u:noob f1\t# 移除某用户acl setfacl -b f1\t# 移除所有acl，恢复为标准的Linux权限 setfacl -k f1\t# 清除默认ACL -rw-r--r--. 1 root root 10 Jun 26 20:19 f1\t#无+号 setfacl --set u::rw,u:jerry:-,g::-,o::- f2\t# 用新规则替换原有 mask mask 权限，指的是用户或群组能拥有的最大 ACL 权限，也就是说，给用户或群组设定的 ACL 权限不能超过 mask 规定的权限范围，超出部分做无效处理。\n脚本程序，要有读权限，才能执行。\n顺序是\n读脚本文件 bash执行，读取代码 编译过后二进制文件，没有读权限，也能执行。\n","date":"2024-10-27T00:00:00Z","permalink":"https://www.l00n9.icu/p/linux%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86%E4%B8%8E%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/","title":"Linux用户管理与文件权限管理"},{"content":"文件管理 文件目录结构 以 . 开头的文件为隐藏文件\n蓝色：目录\n绿色：可执行文件\n红色：压缩文件\n浅蓝色：链接文件\n灰色：其他文件\n目录功能 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 /boot\t# 引导文件：内核文件（vmlinuz），引导加载器（boot loader，grub） /bin\t# 所有用户使用的基本命令 /sbin\t# 管理类的基本命令 /lib\t# 启动时，程序依赖的共享库文件和内核模块文件（/lib/modules） /lib64\t# x86_64系统上的辅助共享库文件 /etc\t# 配置文件 /home/USERNAME\t# 普通用户家目录 /root\t# 管理员家目录 /media\t# 便携式移动设备挂载点 /mnt\t# 临时文件系统挂载点 /dev\t# 设备文件及特殊文件存储位置， b：块设备；c：字符设备 /opt\t# 第三方应用安装位置 /srv\t# 系统上运行的服务使用的数据 /tmp\t# 临时文件存储 /proc\t# 输出内核与进程相关信息的虚拟文件系统 /sys\t# 系统硬件设备相关信息的虚拟文件系统 /selinux\t# 存储security enhance linux相关安全策略等信息 /usr\t# Unix System Resource /usr/bin\t# 保证系统拥有完整功能而提供的应用程序 /usr/sbin\t# 保证系统拥有完整功能而提供的应用程序 /usr/lib /usr/lib64 /usr/include\t# C程序头文件 /usr/share\t# 结构化独立的数据，如doc，man等 /var\t# variable data files,可变数据目录 /var/cache\t# 应用程序的缓存数据目录 /var/lib\t# 应用程序的状态信息数据 /var/loacl\t# 给/usr/local下的应用程序存储可变数据 /var/lock\t# 锁文件 /var/log\t# 日志目录及文件 /var/opt\t# 给/opt下应用程序存储可变数据 /var/run\t# 运行中的进行相关的数据，通常用于存储进程pid的文件 /var/spool\t# 应用程序数据池 /var/tmp\t# 临时数据 文件类型 文件类型 标识符 普通文件 - 目录文件 d directory 链接文件 l link 块设备 b block 字符设备 c character 管道文件 p pipe 套接字文件 s socket 管道文件 用于进程间通信\n单向通讯 俩类：匿名，命名(mkfifo # first in first out) 套接字文件 用于进程间的通信（网络）\n双向通讯 文件基础命令 1 2 pwd # print working directory pwd -P #真实路径；可打印软链接的真实路径 基名\u0026amp;目录名 1 2 3 4 5 6 7 8 9 10 11 12 # basename /etc/apt/apt.conf.d/01autoremove 01autoremove # dirname /etc/apt/apt.conf.d/01autoremove /etc/apt/apt.conf.d # basename http://nginx.org/download/nginx-1.18.0.tar.gz nginx-1.18.0.tar.gz # dirname http://nginx.org/download/nginx-1.18.0.tar.gz http://nginx.org/download [root@loong etc]# basename -s .conf.d ld.so.conf.d/ # 去除尾部的后缀 ld.so 目录相关 1 2 3 4 5 6 cd -P /bin # 到真实目录 /usr/bin # 相关环境变量 $PWD #当前目录 $OLDPWD #上一次目录 ls 1 2 3 4 5 ls -a\t# 显示所有，包含隐藏 ls -l\t# 显示额外信息 ls -R\t# 递归显示 ls -ld\t# 目录的信息 # ll 是 ls的别名 file：文件信息显示 1 2 [root@loong /]# file bin bin: symbolic link to usr/bin dos2unix 将win文件格式化为Linux可运行的文件\nstat：文件状态 1 2 3 4 5 6 7 8 9 10 [root@loong ~]# stat anaconda-ks.cfg File: anaconda-ks.cfg Size: 822 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 201918974 Links: 1 Access: (0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root) Context: system_u:object_r:admin_home_t:s0 Access: 2024-10-24 04:56:32.266122542 -0400 Modify: 2024-10-24 04:56:32.266122542 -0400 # 内容最后被修改的时间 Change: 2024-10-24 04:56:32.266122542 -0400 # 元数据被改变的时间，如权限，所有权 Birth: 2024-10-21 08:00:43.008980116 -0400 文件通配符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 *\t# 匹配任意长度，任意字符，不包括隐藏文件 ?\t# 匹配单字符 ~\t# 当前用户家目录 .\t# 当前工作目录 ~+\t# 当前工作目录 -\t# 前一个工作目录 ~用户名\t# 用户家目录 # []多用于过滤操作 [0-9]\t[a-z] [A-Z] [loasd]\t# 匹配中一个 [^loasd]\t# 非 {1..5}\t# 用于批量操作 {a..z}\t[:lower:] [:upper:] ... # 使用时在外再加[] touch：创建空文件和刷新时间 1 2 touch `date +%F_%T`.log touch $(date -d \u0026#34;1 year\u0026#34; +%F_%T).log cp：复制文件与目录 -b：备份\n1 2 3 4 5 6 7 8 9 10 11 12 cp -i\t# 如果文件已存在，则提示是否覆盖 cp -n\t# 如果文件存在，则跳过 cp -p\t# 保留所属人，所属组，时间戳 cp -b\t# 先备份在覆盖 cp -a\t# 保留软链接，递归复制，保留文件属性 # copy整个目录 cp -r\t#使用-r，否则报错 # -b 建议使用 cp --backup=numbered filea.txt fileb.txt x.log y.log y.log.~1~ y.log.~2~ mv：移动；rename重命名文件 -b：备份\n1 2 3 4 mv -b\t# 移动前先备份 mv -i\t# 提示覆盖 mv -n\t# 文件存在，跳过 mv -u\t# 只有源文件比目标文件新时，才执行 rename 1 2 3 4 5 6 7 rename -s\t# 如果目标是链接文件，则重命名其指向 rename -o\t# 不覆盖已存在的文件 rename 更改前内容 更改后内容 指定文件 # 批量更改 rename txt log *.txt ubuntu的rename，使用方法不一样。\n1 2 rename \u0026#39;s/txt/html/g\u0026#39; f*\t# 后缀更改 rename \u0026#39;s/$/.bak/\u0026#39; *\t# 后缀添加 rm 删除文件 1 2 3 4 5 6 7 8 9 rm -i\t# 删除前确认 rm -f\t# 不确认，直接删除 rm -r\t# 递归删除，不递归删除不了文件夹与它下面的文件 rm -d\t# 删除空目录 # 删除一些带特殊符号的文件，如 -f，\u0026#39;~\u0026#39; rm -f ./-f rm -f ./\u0026#39;~\u0026#39; # 指定目录 定义别名避免误删，将文件移动到/tmp中\n1 alias rm =\u0026#39;mv -t /tmp\u0026#39; tree 树形展示结构 1 2 3 4 5 6 7 8 9 10 11 12 13 -a\t# 所有 -d\t# 只目录 -f\t# 完整路径 -F\t# 区分文件类型 -u\t# 显示所属人 -g\t# 显示所属组 -p\t# 显示权限 -s\t# size -t\t# time, 时间排序 -o file\t# 输入到文件中 -L n\t# 显示多少层 -D\t# 显示修改时间 -C\t# 显示颜色 mkdir 创建目录 1 2 mkdir -m=777\t# 设置权限 mkdir -p\t# 无父目录时，一起创建 rmdir 删除目录 1 rmdir -p\t# 连父目录一起删除 文件元数据与节点表结构 inode表结构 元数据与内容数据分开存放。\n每个文件都有一个inode和n个block数据块；inode存元数据，数据库存内容数据。\ninode number 文件类型 所属人所属组 链接数：多少文件名指向这个inode 文件大小 各种时间戳 指向数据块的指针 其他数据 目录\n是特殊的文件\n存储目录下文件名与其inode的映射\n1 2 3 4 5 6 7 8 9 10 11 12 13 df -Th\t# T：type；h：human [root@loong ~]# df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/mapper/openeuler-root 4587520 60955 4526565 2% / devtmpfs 427014 416 426598 1% /dev tmpfs 431725 1 431724 1% /dev/shm tmpfs 1024 18 1006 2% /sys/fs/cgroup tmpfs 819200 811 818389 1% /run tmpfs 1048576 11 1048565 1% /tmp /dev/sda2 65536 384 65152 1% /boot /dev/mapper/openeuler-home 8200192 11 8200181 1% /home # Inodes是此文件系统inode总量 硬链接 一个inode，有多个文件指向该inode\ninode链接数递增 不能跨驱动器或分区 不支持对目录创建硬链接 1 ln filename linkname 软链接 符号链接，快捷方式\n可对目录软链接 可跨分区 软链接文件的数据块是链接的路径名 1 ln -s filename linkname 全使用绝对路径\n删除软链接\n1 2 3 rm -rf a.link\t#删除链接文件 rm -rf a.linl/\t# 删除链接文件指向目录下文件 inode编号耗尽，磁盘打满 大量空文件会把inode编号占满\n大文件会把磁盘占满，inode编号仍有剩余\n删除大文件操作 将/dev/null覆盖大文件\n1 cat /dev/null \u0026gt; /var/log/huge.log /dev/null会丢弃写入的一切东西，输出一个EOF。（黑洞）\n提示空间满 No space left on device，但 df 可以看 到空间很多，为什么？ df为磁盘空间，可能是inode分配完了，使用df -i查看inode数量 被分配的磁盘创建满，被管理员限制，quota 剩下可能为必要的运行空间 提示空间快满，使用 rm 删除了很大的无用文件后，df 仍然看到空间不足，为什么？如何解决？ 文件名被删除，但文件资源仍然被某些进程持有，导致磁盘空间无法释放 lsof （list open file）\n查看进程打开的文件信息 终止进程\n清空文件的内容，而不是文件\n重启服务或系统\nIO 重定向 覆盖式重定向 1 2 \u0026gt;\t# 左 重定向到 右 \u0026lt;\t# 右 重定向到 左；多行文件处理 追加式重定向 1 2 \u0026gt;\u0026gt;\t# 追加到文件末尾 \u0026lt;\u0026lt;\t# 多行文件处理 管道 1 2 |\t# 管道符，命令间传递消息；左到右 ps aux | grep a 后台执行 1 2 \u0026amp; sleep 5 \u0026amp; 信息符号 1 2 3 4 5 6 7 8 9 标准输入 0 标准输出 1 标准错误 2 bash a.sh 2\u0026gt; err.log\t# 2与\u0026gt;间无空格 2\u0026gt;\u0026amp;1\t# 标准错误重定向至标准输出 1\u0026gt;\u0026amp;2\t# 标准输出重定向至标准错误 \u0026gt;\u0026amp;\t# 标准输入与标准错误都重定向 临时shell 1 2 (命令; 命令)\t# 临时子shell，操作完后无残留 { 命令; 命令 }\t# 临时shell，保留操作结果,前后要有空格 标准输入重定向 使用文件来代替键盘输入\n1 cat \u0026lt; a.txt \u0026gt; b.txt\t# 将a.txt输入给cat，再将cat输出的内容输入给b.txt \u0026lt;\u0026lt;EOP: 标准输入多行重定向 \u0026lt;\u0026lt;-EOP用于脚本中，忽略EOP前的制表符\n可进行多行标准输入\nEOP标志结束\n1 cat \u0026gt; c.txt \u0026lt;\u0026lt;EOP tee 将标准输入复制到每个指定文件夹，并显示到标准输出\n搭配\u0026lt;\u0026lt;EOP使用，EOP会成为结束标志\n-a 追加\ntee filename\n之后会让你输入，边输入边回显\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@loong ~]# tee tee.log \u0026lt;\u0026lt;EOP \u0026gt; sdqw \u0026gt; sadq \u0026gt; cawrqw \u0026gt; \u0026gt; \u0026gt; safwqw \u0026gt; EOP sdqw sadq cawrqw safwqw cat \u0026lt;\u0026lt;EOF | sudo tee /etc/modules-load.d/k8s.conf 在当前用户解析输入内容\n之后再由root去写入文件\n系统文件通常有root用户写入，避免权限问题 read，让用户输入，对脚本内参数赋值 -s 不显示用户输入\n-n 限制字符数量\n-t 输入时长\n-p “输入passwd” 输入提示\n\u0026lt;\u0026lt;\u0026lt; 高级重定向 \u0026lt;：是文件输入重定向，后面的会被解析成文件文件\n\u0026lt;\u0026lt;\u0026lt;：是字符串重定向\n","date":"2024-10-25T00:00:00Z","permalink":"https://www.l00n9.icu/p/%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86%E4%B8%8Eio%E9%87%8D%E5%AE%9A%E5%90%91/","title":"文件管理与IO重定向"},{"content":"Linux 目录结构 文件系统的目录结构\nbin：给普通用户使用的工具(二进制可执行文件) boot：开启启动的文件，包含 linux 内核 linux 内核：vmlinuz-5.14.0-284.11.1.el9_2.x86_64 grub, 开机引导加载程序 dev：硬件设备，比如：硬盘 etc：类似于注册表，核心！各种配置文件 home：用户的数据，各个用户在家目录 root：root 用户的家目录 run：运行过程中生成的临时文件 sbin：给管理员使用的工具（二进制可执行文件） tmp：临时文件 usr：操作系统下自带的文件，大多在 usr var：网页文件，日志等不断会变化的文件 lib/lib64: 库文件，很多应用程序共同依赖的库文件 mnt/media：实现外围设备的挂载用的 proc/sys：内存中的数据，虚拟文件系统，内存映射到硬盘的数据 opt/srv：外部下载的一些程序软件，如果不下载的话，一般为空 opt：外部下载的一些程序软件，如果不下载的话，一般为空 srv：系统上运行的服务用到的数据 命令\n1 2 $PATH\t#调用的变量 $(COMMAND)\t#括号内的时命令 主机名修改 1 2 hostname #临时修改主机名 hostnamectl #永久修改主机名 CPU lscpu cat /proc/cpuinfo\n内存 lsmem\ncat /proc/meminfo\n1 2 free -h #显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer。 free -h -s 1 -c 5\t#每1秒更新, 更新5次 磁盘 磁盘分区\n1 lsblk 磁盘和目录关系信息\n1 blkid 内核版本 1 uname -r 发行版本 1 cat /etc/os-release 关机与重启 关机 1 2 3 4 halt poweroff init 0 shutdown -h now 重启 1 2 3 reboot init 6 shutdown -r now halt 立即中断所有任务\npoweroff 关闭系统并切断电源。\nshutdown 安全的关闭，会通知所有登陆的用户并阻塞登录。\nshell 中的命令 内部命令 shell 自带\n外部命令 有对应的可执行程序，执行命令时才加载到内存中，执行完毕后删除。\n既有内部又有外部命令 外部命令作为备份，防止内部命令执行失败\nHash 缓存表 执行外部命令时会先在 hash 表中查找。提高命令调用率\n临时数据\n命令执行优先级 别名 \u0026mdash;\u0026ndash;\u0026gt; 内部命令 \u0026mdash;\u0026mdash;\u0026gt; hash\u0026mdash;\u0026gt; 外部命令\n会话管理 打开窗口，会话开始；关闭窗口，会话结束，会话内部的进程也会随之终止，不管有没有运行完。\n1 2 pstree -p # 带pid ps aux # 所有进程 会话解绑 screen，tmux\n远程登陆方式 Telnet 旧的远程登录协议，不加密。\nSSH 加密会话\n终端与控制台的区别 控制台直接在系统级别上与操作系统交互。\n例如 VMware 上的虚拟机，虚拟机界面就是控制台。\n终端可以是本地或是远程的，提供用户级别的命令行界面。\n例如 ssh 链接的就是终端不是控制台。\n","date":"2024-10-23T00:00:00Z","permalink":"https://www.l00n9.icu/p/linux-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/","title":"Linux 基础知识"}]