服务器自动巡检(Server automatic inspection)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

服务器自动巡检
技能目标: - 熟悉项目开发流程
- 熟悉服务器硬件资源采集方法

9.1 案例分析

9.1.1 案例概述

随着业务量增加,服务器也会越来越多,如何高效管理上百台服务器是一个重要的问题。
大公司在管理服务器过程中经常有这么一个需求,统计这些服务器基本信息,例如 CPU
几核的,内存多少 G、磁盘多大的等等,然后参考统计的结果做好资源规划。小李入职到新
公司后,经理发来几个电子文档,要求他确认并维护公司所有服务器信息。小周打开文件后
发现竟有百十来台服务器的信息。如果一台台服务器登录,查看获取信息,显然效率很低。
现在,根据这样的需求编写一个服务器自动巡检工具,帮助小李完成这个任务。

9.1.2 案例前置知识点

1. 服务器自动巡检

服务器自动巡检是通过技术手段自动获取目标服务器指定信息,并对结果处理,以表格、
图表形式展示,这种方式极大提高了工作效率。

2. 什么是标准库

Python 发行版中包含一系列非常有用的模块,这些模块也称为标准库;Python 模块
是一个 Python 文件,以.py 结尾,包含了 Python 对象定义和语句。模块让编程者能够有逻
辑地组织代码,使编写出来的代码更易懂、可复用。

3. 标准库如何使用

标准库的模块可以立刻使用,无需额外安装。以内建 sys 模块为例。
[root@localhost ~]# python3
Python 3.6.5 (default, Jun 9 2020, 11:14:59)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> help(sys)
>>> dir(sys)
进入 Python 解释器,直接 import sys 即可导入。可以使用 help()方法查看模板帮助文
档,dir()方法查看模块方法、属性信息了解该模块信息。
Python 的标准库应用非常广泛,提供了一系列功能帮助解决日常编程,非常有必要学习下,为以后打好基础。

4. os 模块

Python os 模块提供一种操作系统接口,主要用于管理目录或者文件。
os 模块方法非常多,表 9-1 是常用的方法。
9-1 os 模块中常用的方法
方法描述示例
os.environ以字典形式返回系统变量
>>> os.environ
>>> os.environ['HOSTNAME']
os.listdir(path)
以列表形式返回目录下所有目录
和文件名
>>> os.listdir("/tmp")
os.getcwd()获取当前路径
>>> os.getcwd()
'/root'
os.chdir(path)改变当前工作目录到指定目录
>>> os.chdir('/tmp)
>>> os.getcwd()
'/tmp'
os.mkdir(path,
mode=0777])
创建目录>>> os.mkdir('/tmp/abc')
os.makedirs(path,
mode=0777])
递归创建目录>>> os.makedirs('/tmp/cde/123')
os.rmdir(path)移除空目录>>> os.rmdir ('/tmp/cde/123'
os.remove(path)移除文件>>> os.remove("/tmp/a.txt")
os.rename(old, new)重命名文件或目录
>>>
os.rename("/tmp/old.txt","/tmp/new.txt")
方法
描述
示例
>>> os.stat("/tmp")
获取文件或目录属性
>>> os.stat("/tmp")
os.chown(path, uid, gid)
改变文件或目录所有者
改变文件或目录所有者
os.chmod(path, mode)
改变文件访问权限
>>> os.chmod("/tmp/abc",777)
os.symlink(src, dst)
创建软链接
>>> os.symlink("/tmp/abc","/tmp/abc2")
os.unlink(path)
移除软链接
>>> os.unlink('/tmp/abc2')
os.urandom(n)
返回随机字节,适合加密使用
>>> os.urandom(2)
'%\xec
os.getuid()
返回当前进程 UID
>>> os.getuid()
0
os.getlogin()
返回登录用户名
>>> os.getlogin()
'root'
os.getpid()
返回当前进程 ID
>>> os.getpid()
3079

5. paramiko 模块

paramiko 是用 Python 语言写的一个模块,遵循 SSH2 协议,支持以加密和认证的方
式,进行远程服务器的连接。
由于使用的是 Python 这样的能够跨平台运行的语言,所以所有 Python 支持的平台,
Linux, Solaris, BSD, MacOS X, Windows 等,paramiko 都可以支持,因此,如果需要使
SSH 从一个平台连接到另外一个平台,进行一系列的操作时,paramiko 是最佳工具之一。

9.1.3 案例环境

本案例环境如表 9-2 所示。
9-2 服务器配置
主机操作系统主机名/IP 地址主要软件及版本
自动巡检工具CentOS 7.3Center /192.168.0.10Python 3
被检服务器
CentOS 7.3
localhost /192.168.0.11/
被检服务器 CentOS 7.3localhost /192.168.0.12/

案例拓扑如图 9.1 所示。

9.1 自动巡检服务拓扑图

1. 案例需求

收集服务器指标如下:
运行时间(当前时间、最后启动时间)
主机名
系统版本/内核版本
CPU
内存
硬盘
监听端口
是否允许 root 远程登录

2. 实现思路

使用 paramiko 模块将收集程序上传到目标主机并执行,处理返回的数据写到 csv 文件
中。

9.2 案例实施

9.2.1 功能模块规划

根据本案例的需求,设计 Python 工程目录结构中所包含的模块信息,如表 9-3 所示。
9-3 Python 工程目录结构中所包含的模块信息
模块描述
run.py主程序
collect.py收集主机信息程序
host.info存放主机信息文件
存放主机信息文件处理结果

9.2.2 服务器指标收集

Linux 文件系统的/proc 目录是一个虚拟目录,在 Linux 系统启动后生成的,数据存储在
内存中,存放内核运行时的参数、网络信息、进程状态、资源利用率等等。
服务器指标收集就是从这个目录下的文件获取各项数据,如表 9-4 所示。
9-4 服务器指标收集文件
文件路径描述

/etc/issue

/etc/redhat-release

操作系统版本信息
/proc/cpuinfoCPU 信息
/proc/stat
CPU 使用情况
/proc/meminfo
内存信息
/etc/mtab
硬盘分区
/dev
Linux 系统使用的所有外部设备
/sys/class/net
网络设备连接符号
/proc/net/dev
网卡统计信息
/proc/net/tcp
/proc/net/udp
网络连接信息

9.2.3 功能实现

运行本案例的 Python 脚本需使用 paramiko 模块,而 paramiko 模块内部依赖 pycrypto
所以需先下载安装 pycrypto
[root@center ~]# pip3 install pycrypto
[root@center ~]# pip3 install paramiko

1. 主程序

[root@center ~]# vim run.py
#!/usr/bin/python3
import os,sys
import paramiko
base_dir = os.path.dirname(os.path.abspath(__file__))
host_file = "%s/host.info" %base_dir
collect_file = "%s/collect.py" %base_dirimport csv, codecs
# 字段名称
with codecs.open('result.csv', 'w', 'gbk') as f1:
csv_file = csv.writer(f1)
csv_file.writerow(['IP 地址', '主机名', '操作系统', '内存', 'CPU', '硬盘', '网络连接状态统计', \
'监听端口', '网卡流量'])
with open(host_file) as f:
# 遍历主机列表
while f:
line = f.readline()
if not line: break
line = line.split()
hostname = line[0]
port = int(line[1])
username = line[2]
password = line[3]
if not os.path.isfile(collect_file):
print(collect_file + " 文件不存在!")
sys.exit(1)
try:
s = paramiko.Transport((hostname, port))
s.connect(username=username, password=password)
except Exception as e:
print(e)
continue
# 上传收集程序到目标主机
remote_file = "/tmp/collect.py"
sftp = paramiko.SFTPClient.from_transport(s)
sftp.put(collect_file, remote_file)
try:
sftp.file(remote_file)
# 在目标主机执行收集程序
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname, port, username, password)
stdin, stdout, stderr = client.exec_command('python %s' %remote_file)
stdout = stdout.read()
error = stderr.read()
if not error:
# 处理从主机收集的数据
result = eval(stdout.decode('utf-8'))
ip = result["ip"]
os_info = result["os"]
memory = result["memory"]
cpu = result["cpu"]
disk = result["disk"]
network = result["network"]
# 系统信息
host_name = os_info["host_name"]
os_version = "os_version: %s" % os_info["os_version"] + "\n" \
+ "kernel: %s" %os_info["kernel"] + "\n" \
+ "start_time: %s" %os_info["start_time"] + "\n" \
+ "current_time: %s" %os_info["current_time"]
# 内存
m = ''
for k, v in memory.items():
m +="%s: %sM" %(k, v) + "\n"
# CPU
c = ''
for k, v in cpu.items():
c +="%s: %s" %(k, v) + "\n"
# 硬盘
d = ''
for k, v in disk.items():
fs = k
mount = v["mount"]
total = v["total"]
avail = v["free"]
used = v["used"]
d += "%s -> %s,total: %s, avail: %s, used: %s" %(fs, mount, total, avail, \
used) + "\n"
# 连接状态统计
status_count = ''
for k, v in network["tcp_status_count"].items():
status_count +="%s: %s" %(k, v) + "\n"
status_count + "\n" + "%s: udp_status_count" %(network["udp_status_count"])
# 监听端口
listen = ''
for k, v in network["listen"].items():
v = list(set(v))
listen +="%s: %s" %(k, v) + "\n"
# 网卡流量
traffic = ''
for k, v in network["traffic"].items():
traffic +="%s: %sKB" %(k, v) + "\n"
# 写入 csv
with codecs.open('result.csv', 'a', 'gbk') as f2:
csv_file = csv.writer(f2)
data = [
(ip, host_name, os_version, m, c, d, status_count, listen, traffic)
]
csv_file.writerows(data)
else:
print(error)
# 删除上传到目标主机的收集程序
#client.exec_command('rm -f %s' %remote_file)
#client.close()
except Exception as e:
print(e)
continue
finally:
s.close()

2. 收集主机信息程序

[root@center ~]# vim collect.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Only support OS CentOS or Ubuntu
from datetime import datetime, date
import os, sys, time, re, math, socket
import subprocess
################# 获取本地外网 IP #################
def extranet_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('10.255.255.255', 0))
ip = s.getsockname()[0]
return ip
################# 操作系统版本/主机名/内核版本 #################
def os_info():
with open("/etc/issue") as f:
f = f.read()
if "\S" in f or "CentOS" in f:
with open("/etc/redhat-release") as f:
os_version = f.read().replace('\n', '')
else:
os_version = f.split("\n")[0]
host_name, kernel = os.uname()[1:3]
os_info = {'os_version': os_version, 'host_name': host_name, 'kernel': kernel}
return os_info
################# 运行时间 #################
# 最后系统启动时间
def start_time():
p = subprocess.Popen("date -d \"$(awk -F. '{print $1}' /proc/uptime) second ago\" +'%F %T'", \
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
outs, errs = p.communicate()
# bytes to str
outs = outs.decode('utf-8').replace('\n','')
# 当前时间
date_time = date.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
time = {'start_time': outs, 'current_time': date_time}
return time
################# CPU 核心数量/CPU 占用时间百分比 #################
#from multiprocessing import cpu_count
#print(cpu_count())
def cpu_count():
cpu_count = {}
with open("/proc/cpuinfo") as f:
for i in f.readlines():
if "processor" in i:
cpu_count["cpu_count"] = cpu_count.get("cpu_count", 0) + 1
return cpu_count
# user nice system idle iowait irq softirq steal guest (从系统启动开始累计到当前)
def cpu_use_time_percent():
with open('/proc/stat') as f:
cpu = [int(n) for n in f.readline().split()[1:]]
total_old = sum(cpu)
user_old = cpu[0] + cpu[1]
system_old = cpu[2]
idle_old = cpu[3]
iowait_old = cpu[4]
time.sleep(2)
with open('/proc/stat') as f:
cpu = [int(n) for n in f.readline().split()[1:]]
total_new = sum(cpu)
user_new = cpu[0] + cpu[1]
system_new = cpu[2]
idle_new = cpu[3]
iowait_new = cpu[4]
cpu_total = float(total_new - total_old)
cpu_user = float(user_new - user_old)
cpu_system = float(system_new - system_old)
cpu_idle = float(idle_new - idle_old)
cpu_iowait = float(iowait_new - iowait_old)
# used = float("%.1f" %((1-cpu_idle / cpu_total) * 100))
user = round(cpu_user / cpu_total * 100, 1)
system = round(cpu_system / cpu_total * 100, 1)
iowait = round(cpu_iowait / cpu_total * 100, 1)
cpu_time = {'user': user, 'system': system, 'iowait': iowait}
return cpu_time
################# 内存利用率 #################
def memory():
memory = {}
with open("/proc/meminfo") as f:
for n in range(5):
mem = f.readline().split()
memory[mem[0]] = int(mem[1])
total = memory["MemTotal:"] // 1024
free = (memory['MemFree:'] + memory['Buffers:'] + memory['Cached:']) // 1024
used = total - free
memory = {'total': total, 'used': used, 'free': free}
return memory
################# 硬盘分区利用率 #################
def disk_partitions():
part = {}
with open("/etc/mtab") as f:
for p in f.readlines():
if p.startswith("/dev"):
p = p.split()
fs = p[0]
mount = p[1]
fs_info = os.statvfs(mount)
# 如果数除不尽则为 0,所以要用 float 取结果浮点数,单位 G
# total = "%.1f" %(float(fs_info.f_bsize * fs_info.f_blocks / 1024 / 1024) \
/ float(1024))
# bsize * block = bytes
total = round(float(fs_info.f_bsize * fs_info.f_blocks / 1024 / 1024) / float(1024), 1)
# bfree: 可用块数量
used = round(float(fs_info.f_bsize * fs_info.f_bfree / 1024 / 1024) / float(1024), 1)
used = round(total - used, 1)
# bavail: 非超级用户可用块
free = round(float(fs_info.f_bsize * fs_info.f_bavail / 1024 / 1024) / float(1024), 1)
# 如果键存在就返回对应的值,否则新增(以读取的第一个文件系统为准)
part[fs] = part.get(fs, {'mount':mount, 'total': total, 'used': used, 'free': free})
return part
################# 网卡流量 #################
# 通过 IP 获取网卡名
ip = extranet_ip()
def nic_traffic():
p = subprocess.Popen("ifconfig |awk -F'[: ]' '/^em|^eth|^br|^p3p1|^en/{nic=$1}/%s/{ \
print nic}'" %ip, stdout=subprocess.PIPE, shell=True)
outs, errs = p.communicate()
nic = outs.decode("utf-8").replace("\n","")
with open("/proc/net/dev") as f:
for s in f.readlines():
if s.strip().startswith(nic):
s = s.replace(":"," ")
in_old = s.split()[1]
out_old = s.split()[9]
time.sleep(1)
with open("/proc/net/dev") as f:
for s in f.readlines():
if s.strip().startswith(nic):
s = s.replace(":"," ")
in_new = s.split()[1]
out_new = s.split()[9]
# // 整除去尾
traffic_in = (int(in_new) - int(in_old)) // 1024
traffic_out = (int(out_new) - int(out_old)) // 1024
traffic = {'traffic': {'in': traffic_in, 'out': traffic_out}}
return traffic
################# 网络连接 #################
def network_status():
tcp_status = {
'01':'ESTABLISHED',
'02':'SYN_SENT',
'03':'SYN_RECV',
'04':'FIN_WAIT1',
'05':'FIN_WAIT2',
'06':'TIME_WAIT',
'07':'CLOSE',
'08':'CLOSE_WAIT',
'09':'LAST_ACK',
'0A':'LISTEN',
'0B':'CLOSING'
}
tcp_status_count = {}
udp_status_count = 0
listen = {"tcp":[], "tcp6":[], "udp":[], "udp6":[]}
for t in listen.keys():
if os.path.exists('/proc/net/%s' %t):
with open('/proc/net/%s' %t) as f:
while f:
line = f.readline()
if not line: break
status_line = line.split()
status = status_line[3]
if status == "st": continue
# 统计监听端口
# TCP
if status == "0A" and t.startswith("tcp"):
# 16 to 10
listen_port = int(status_line[1].split(':')[1], 16)
listen[t] = listen.get(t, []) + [listen_port]
# UDP
elif status == "07" and t.startswith("udp"):
listen_port = int(status_line[1].split(':')[1], 16)
listen[t] = listen.get(t, []) + [listen_port]
# 统计 TCP 连接状态
status_name = tcp_status[status]
if t.startswith("tcp"):
tcp_status_count[status_name]=tcp_status_count.get(status_name,0)+1
else:
udp_status_count += 1
network_status = {'listen': listen, 'tcp_status_count': tcp_status_count, \
'udp_status_count': udp_status_count}
return network_status
if __name__ == '__main__':
result = {}
os_info = os_info()
os_info.update(start_time())
cpu_count = cpu_count()
cpu_count.update(cpu_use_time_percent())
network_status = network_status()
network_status.update(nic_traffic())
result["ip"] = extranet_ip()
result["os"] = os_info
result["memory"] = memory()
result["cpu"] = cpu_count
result["disk"] = disk_partitions()
result["network"] = network_status
print(result)

3. 存放主机信息文件

[root@center ~]# vim host.info
192.168.0.11 22 root 123456
192.168.0.12 22 root 123456
在所需巡检的主机信息文件中输入主机 IP 地址、SSH 端口、用户名、密码,需要巡检
多少台主机,就添加多少台的主机信息。本例巡检两台 192.168.0.11 192.168.0.12
9.2.4 测试
在已安装 Python 3.6 以上版本的目标主机上,将以上三个文件 run.pycollect.py
host.info 保存到信息采集的计算机上,然后运行主程序:
[root@center ~]# python3 run.py
所有主机逐一处理完成后,可以使用 cat 命令直接查看巡检记录,生成的 result.csv
件的内容如下:
[root@center ~]# cat result.csv
192.168.0.11,localhost.localdomain,"os_version:CentOS
Linux
release
7.3.1611
(
Core)
kernel: 3.10.0-514.el7.x86_64
start_time: 2020-07-20 08:56:47
current_time: 2020-07-20 10:09:27","total: 976M
free: 594M
used: 382M
","iowait: 0.0
cpu_count: 1
user: 0.0
system: 0.0
","/dev/mapper/cl-root -> /,total: 17.0, avail: 14.3, used: 2.7
/dev/sda1 -> /boot,total: 1.0, avail: 0.9, used: 0.1
","ESTABLISHED: 2
LISTEN: 5
","udp6: [63217, 323]
udp: [323, 68, 36501]
tcp6: [25, 3306, 22]
tcp: [25, 22]
","out: 0KB
in: 1KB
"
192.168.0.12,localhost.localdomain,"os_version:
CentOS
Linux
release
7.3.1611
(
Core)
kernel: 3.10.0-514.el7.x86_64
start_time: 2020-07-20 08:56:50
current_time: 2020-07-20 10:09:31","total: 976M
free: 597M
used: 379M
","iowait: 0.0
cpu_count: 1
user: 0.5system: 0.5
","/dev/mapper/cl-root -> /,total: 17.0, avail: 14.3, used: 2.7
/dev/sda1 -> /boot,total: 1.0, avail: 0.9, used: 0.1
","ESTABLISHED: 2
LISTEN: 5
","udp6: [63217, 323]
udp: [323, 68, 36501]
tcp6: [25, 3306, 22]
tcp: [25, 22]
","out: 0KB
in: 0KB
"
如果将 result.csv 文件传送到 Windows 服务器以 Excel 表格打开,就会以更加直观的
图表形式展示,如图 9.2 所示。
9.2 图标展示服务器巡检信息
通过本案例编写的服务器自动巡检工具 Python 脚本,可以很轻易收集所需管理的服务
器信息,提高工作效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/427702.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Microsoft Edge 五个神级插件

🐣个人主页 可惜已不在 🐤这篇在这个专栏 插件_可惜已不在的博客-CSDN博客 🐥有用的话就留下一个三连吧😼 目录 Microsoft Edge 一.安装游览器 ​编辑 二.找到插件商店 1.打开游览器后,点击右上角的设置&#x…

BLE 协议之链路层

目录 一、前言二、状态和角色三、Air Interface Packets1、Preamble 字段2、Access Address 字段2.1 静态地址2.2 私有地址 3、PDU 字段3.1 Advertising Channel PDU3.1.1 Header 字段3.1.2 Payload 字段 3.2 Data Channel PDU3.2.1 Header 字段3.2.2 Payload 字段 4、CRC 字段…

STM32上实现FFT算法精准测量正弦波信号的幅值、频率和相位差(标准库)

在研究声音、电力或任何形式的波形时,我们常常需要穿过表面看本质。FFT(快速傅里叶变换)就是这样一种强大的工具,它能够揭示隐藏在复杂信号背后的频率成分。本文将带你走进FFT的世界,了解它是如何将时域信号转化为频域…

【微信小程序】搭建项目步骤 + 引入Tdesign UI

目录 创建1个空文件夹,选择下图基础模板 开启/支持sass 创建公共style文件并引入 引入Tdesign UI: 1. 初始化: 2. 安装后,开发工具进行构建: 3. 修改 app.json 4. 使用 5. 自定义主题色 创建1个空文件夹,选择下…

初始c++:入门基础(完结)

打字不易,留个赞再走吧~~~ 目录 一函数重载二引用1 引⽤的概念和定义2引⽤的特性3引⽤的使⽤三inline四nullptr 一函数重载 C⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同。这样C函数调⽤…

FPGA随记-二进制转格雷码

反射二进制码(RBC),也称为反射二进制(RB)或格雷码(Gray code),得名于Frank Gray,是二进制数制的一种排列方式,使得连续两个值之间仅有一个比特(二…

【Python进阶】requests库有哪些常用的参数和方法?一篇文章带你详细了解!!!附带源码

常用的requests库参数和方法 常用方法 requests库中定义了多个常用的请求方法,其中requests.get()和requests.post()是最常用的方法。这些方法对应于HTTP协议中的GET和POST方法。 requests.get(url, paramsNone, **kwargs): 用于发送GET请求。requests.post(url…

【高阶数据结构】二叉搜索树的插入、删除和查找(精美图解+完整代码)

🤡博客主页:醉竺 🥰本文专栏:《高阶数据结构》 😻欢迎关注:感谢大家的点赞评论关注,祝您学有所成! ✨✨💜💛想要学习更多《高阶数据结构》点击专栏链接查看&a…

Mysql梳理6——order by排序

目录 6 order by排序 6.1 排序数据 6.2 单列排序 6.3 多行排列 6 order by排序 6.1 排序数据 使用ORDER BY字句排序 ASC(ascend):升序DESC(descend):降序 ORDER BY子句在SELECT语句的结尾 6.2 单列排序 如果没有使用排序操作,默认…

一、桥式整流电路

桥式整流电路 1、二极管的单向导电性: 伏安特性曲线: 理想开关模型和恒压降模型 2、桥式整流电流流向过程 输入输出波形: 3、计算:Vo,lo,二极管反向电压。 学习心得

十三,Spring Boot 中注入 Servlet,Filter,Listener

十三,Spring Boot 中注入 Servlet,Filter,Listener 文章目录 十三,Spring Boot 中注入 Servlet,Filter,Listener1. 基本介绍2. 第一种方式:使用注解方式注入:Servlet,Fil…

【C++】——多态详解

目录 1、什么是多态? 2、多态的定义及实现 2.1多态的构成条件 ​2.2多态语法细节处理 2.3协变 2.4析构函数的重写 2.5C11 override 和 final关键字 2.6重载—重写—隐藏的对比分析 3、纯虚函数和抽象类 4、多态的原理分析 4.1多态是如何实现的 4.2虚函数…

OpenCV 2

目录 图像平滑处理 高斯与中值滤波 图像阈值 ​编辑 Canny边缘检测 非极大值抑制 边缘检测效果 轮廓检测方法 ​编辑 ​编辑​编辑 轮廓检测结果 轮廓特征与近似 图像平滑处理 以上两种出来的图片效果 以上的效果,因为填的是normalize False,越界…

零基础到项目实战:Node.js版Selenium WebDriver教程

在当今数字化时代,Web应用程序的质量和性能至关重要。为了确保这些应用的可靠性,自动化测试成为一种不可或缺的工具。Selenium,作为自动化测试领域的瑰宝,为我们提供了无限可能。本教程将深入介绍Selenium,以及如何结合…

硬盘数据恢复必备:4 款强大硬盘数据恢复软件推荐!

在数字化的时代,我们的生活和工作越来越离不开电脑,而硬盘作为重要的数据存储设备,一旦出现数据丢失的情况,往往会给我们带来极大的困扰。别担心,今天就为大家推荐四款强大的硬盘数据恢复软件,帮助你轻松找…

优化算法(三)—模拟退火算法(附MATLAB程序)

模拟退火算法(Simulated Annealing, SA)是一种基于概率的优化算法,旨在寻找全局最优解。该算法模拟金属退火过程中的物质冷却过程,逐渐降低系统的“温度”以达到全局优化的效果。它特别适用于解决复杂的组合优化问题。 一、模拟退…

[羊城杯 2020]Blackcat1

知识点:数组加密绕过 进入页面熟悉的web三部曲(url地址,web源代码,web目录扫描) url地址没有什么东西去看看源代码. 这有一个mp3文件点一下看看. 在最后面发现了 PHP源码. if(empty($_POST[Black-Cat-Sheriff]) || em…

Android Studio报错: Could not find pub.devrel:easypermissions:0.3.0, 改用linux编译

在Android studio中去编译开源的仓库,大概率就是各种编译不过,一堆错误,一顿改错,基本上会耗费非常多时间,比如: 这个就是改gradle版本,改成7.2 ,修改完成之后,还有其他报…

翻页时钟 2.0-自动置顶显示,点击小时切换显示标题栏不显示标题栏-供大家学习研究参考

更新内容 自动置顶显示点击小时切换显示标题栏,(显示标题栏后可移动时钟位置,鼠标拖动边框调整时钟大小)不显示标题栏时,透明部分光标可穿透修正一个显示bu 下载地址: https://download.csdn.net/download…