CANopen for Python

news2024/11/15 10:03:45

系列文章目录


前言

        该软件包支持与 CANopen 节点网络交互。

        注意 这里的大部分文档都是从 CANopen 维基百科页面上直接盗用的。
        本文档正在编写中。欢迎反馈和修改!

        CANopen 是用于自动化领域嵌入式系统的通信协议和设备配置文件规范。根据 OSI 模型,CANopen 实现了网络层以上(包括网络层)的各层。CANopen 标准包括一个寻址方案、几个小型通信协议和一个由设备配置文件定义的应用层。通信协议支持网络管理、设备监控和节点之间的通信,包括一个用于报文分段/解分段的简单传输层。

        最简单的安装方法是使用 pip:

pip install canopen
  • 网络和节点
  • 对象字典
  • 网络管理 (NMT)
  • 服务数据对象 (SDO)
  • 进程数据对象 (PDO)
  • 同步对象 (SYNC)
  • 紧急对象 (EMCY)
  • 时间戳对象(TIME)
  • 层设置服务 (LSS)
  • 与现有代码集成
  • 设备配置文件 

 


一、网络和节点

        canopen.Network 表示连接到同一条 CAN 总线的节点集合。它处理报文的发送和接收,并将报文发送到它所知道的节点。

        每个节点都使用 canopen.RemoteNode 或 canopen.LocalNode 类来表示。它通常与一个对象字典相关联,每个服务都有自己的属性,由该节点所有。

1.1 示例

        为每条 CAN 总线创建一个网络:

import canopen

network = canopen.Network()

        默认情况下,该库使用 python-can 进行实际通信。有关如何配置特定接口的详细信息,请参阅其文档。

        调用 connect() 方法启动通信,可选择提供传递给 can.BusABC 构造函数的参数:

network.connect(channel='can0', bustype='socketcan')
# network.connect(bustype='kvaser', channel=0, bitrate=250000)
# network.connect(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
# network.connect(bustype='ixxat', channel=0, bitrate=250000)
# network.connect(bustype='nican', channel='CAN0', bitrate=250000)

        使用 add_node() 方法向网络中添加节点:

node = network.add_node(6, '/path/to/object_dictionary.eds')

local_node = canopen.LocalNode(1, '/path/to/master_dictionary.eds')
network.add_node(local_node)

        节点也可以使用作为 Python 字典的网络对象来访问:

for node_id in network:
    print(network[node_id])

        要自动检测网络上存在哪些节点,可以使用扫描仪属性:

# This will attempt to read an SDO from nodes 1 - 127
network.scanner.search()
# We may need to wait a short while here to allow all nodes to respond
time.sleep(0.05)
for node_id in network.scanner.nodes:
    print(f"Found node {node_id}!")

        最后,确保完成后断开连接:

network.disconnect()

二、对象字典

        CANopen 设备必须有一个对象字典,用于配置和与设备通信。对象字典中的条目定义如下

  • 索引,对象在字典中的 16 位地址
  • 对象类型,如数组、记录或简单变量
  • 名称,描述条目的字符串
  • 类型,给出变量的数据类型(或数组中所有变量的数据类型)
  • 属性,提供该条目访问权限的信息,可以是读/写(rw)、只读(ro)或只写(wo)。

        标准中定义了布尔值、整数和浮点数等对象字典值的基本数据类型,以及字符串、数组和记录等复合数据类型。复合数据类型可使用 8 位索引进行子索引;数组或记录的子索引 0 中的值表示数据结构中的元素个数,其类型为 UNSIGNED8。

2.1 支持的格式

        目前支持用于指定节点对象字典的文件格式有

  • EDS (类似 INI 文件的标准化格式)
  • DCF(与 EDS 格式相同,但指定了比特率和节点 ID)
  • EPF(Inmotion Technologies 使用的专有 XML 格式)

2.2 示例

        对象字典文件通常在创建节点时提供。下面是一个打印出整个对象字典的示例:

node = network.add_node(6, 'od.eds')
for obj in node.object_dictionary.values():
    print(f'0x{obj.index:X}: {obj.name}')
    if isinstance(obj, canopen.objectdictionary.ODRecord):
        for subobj in obj.values():
            print(f'  {subobj.subindex}: {subobj.name}')

        您可以使用索引/子索引或名称访问对象:

device_name_obj = node.object_dictionary['ManufacturerDeviceName']
vendor_id_obj = node.object_dictionary[0x1018][1]
actual_speed = node.object_dictionary['ApplicationStatus.ActualSpeed']
command_all = node.object_dictionary['ApplicationCommands.CommandAll']

三、网络管理 (NMT)

        NMT 协议用于发出状态机更改命令(如启动和停止设备)、检测远程设备启动和错误状况。

        模块控制协议用于 NMT 主站改变设备状态。该协议的 CAN 帧 COB-ID 始终为 0,即功能代码为 0,节点 ID 为 0,这意味着网络中的每个节点都将处理该报文。命令的实际节点 ID 在报文的数据部分(第二个字节)给出。节点 ID 也可以是 0,这意味着总线上的所有设备都应进入指定状态。

        心跳协议用于监控网络中的节点并验证它们是否存活。心跳生成器(通常是从属设备)会定期发送带有二进制功能代码 1110 及其节点 ID(COB-ID = 0x700 + 节点 ID)的报文。帧的数据部分包含一个表示节点状态的字节。心跳用户会读取这些报文。

        CANopen 设备需要在启动过程中自动从 "初始化 "状态过渡到 "预运行 "状态。转换完成后,会向总线发送一条心跳报文。这就是启动协议。

3.1 示例

        使用 canopen.Node.nmt 属性访问 NMT 功能。可使用 state 属性改变状态:

node.nmt.state = 'OPERATIONAL'
# Same as sending NMT start
node.nmt.send_command(0x1)

        您还可以通过广播信息同时改变所有节点的状态:

network.nmt.state = 'OPERATIONAL'

        如果节点发送心跳信息,状态属性就会自动更新为当前状态:

# Send NMT start to all nodes
network.send_message(0x0, [0x1, 0])
node.nmt.wait_for_heartbeat()
assert node.nmt.state == 'OPERATIONAL'

四、服务数据对象 (SDO)

        SDO 协议用于设置和读取远程设备对象字典中的值。访问对象字典的设备是 SDO 服务器,访问远程设备的设备是 SDO 客户端。通信始终由 SDO 客户端发起。在 CANopen 术语中,通信是从 SDO 服务器开始的,因此从对象字典中读取数据是 SDO 上传,而写入字典条目则是 SDO 下载。

        由于对象字典值可能大于 CAN 帧的 8 字节限制,因此 SDO 协议实现了对较长报文的分割和解分割。实际上,有两个这样的协议: SDO 下载/上传和 SDO 块下载/上传。SDO 数据块传输是新增加的标准,可以传输大量数据,协议开销略低。

        客户机到服务器和服务器到客户机的各自 SDO 传输信息的 COB-ID 可在对象字典中设置。最多可在对象字典中设置 128 个 SDO 服务器,地址为 0x1200 - 0x127F。同样,设备的 SDO 客户端连接也可通过 0x1280 - 0x12FF 的变量进行配置。不过,预定义的连接集定义了一个 SDO 通道,即使在启动后(预运行状态)也可使用该通道配置设备。该通道的 COB-ID 为 0x600 + 节点 ID(用于接收)和 0x580 + 节点 ID(用于发送)。

4.1 示例

        可以使用 .sdo 成员访问 SDO 对象,其工作方式类似于 Python 字典。索引可以用名称或编号来标识。有两种方法来标识子索引,一种是使用索引和子索引作为单独的参数,另一种是使用点来组合语法。下面的代码只创建对象,还没有发送或接收信息:

# Complex records
command_all = node.sdo['ApplicationCommands']['CommandAll']
command_all = node.sdo['ApplicationCommands.CommandAll']
actual_speed = node.sdo['ApplicationStatus']['ActualSpeed']
control_mode = node.sdo['ApplicationSetupParameters']['RequestedControlMode']

# Simple variables
device_type = node.sdo[0x1000]

# Arrays
error_log = node.sdo[0x1003]

        要实际读取或写入变量,请使用 .raw、.phys、.desc 或 .bits 属性:

print(f"The device type is 0x{device_type.raw:X}")

# Using value descriptions instead of integers (if supported by OD)
control_mode.desc = 'Speed Mode'

# Set individual bit
command_all.bits[3] = 1

# Read and write physical values scaled by a factor (if supported by OD)
print(f"The actual speed is {actual_speed.phys} rpm")

# Iterate over arrays or records
for error in error_log.values():
    print(f"Error 0x{error.raw:X} was found in the log")

        也可以读写不在对象字典中的变量,但只能使用原始字节:

device_type_data = node.sdo.upload(0x1000, 0)
node.sdo.download(0x1017, 0, b'\x00\x00')

        变量可以作为可读或可写文件对象打开,这在处理大量数据时非常有用:

# Open the Store EDS variable as a file like object
with node.sdo[0x1021].open('r', encoding='ascii') as infile,
        open('out.eds', 'w', encoding='ascii') as outfile:

   # Iteratively read lines from node and write to file
   outfile.writelines(infile)

        大多数接受文件对象的应用程序接口应该也能接受这一点。

        如果服务器支持数据块传输,它就能有效地传输大量数据。这可以通过文件对象接口实现:

FIRMWARE_PATH = '/path/to/firmware.bin'
FILESIZE = os.path.getsize(FIRMWARE_PATH)

with open(FIRMWARE_PATH, 'rb') as infile,
        node.sdo['Firmware'].open('wb', size=FILESIZE, block_transfer=True) as outfile:

    # Iteratively transfer data without having to read all into memory
    while True:
        data = infile.read(1024)
        if not data:
            break
        outfile.write(data)

警告 区块转移仍处于试验阶段!

 

五、过程数据对象 (PDO)

        过程数据对象协议用于处理各节点之间的实时数据。每个 PDO 最多可从设备或向设备传输 8 字节(64 位)数据。一个 PDO 可包含多个对象字典条目,一个 PDO 中的对象可通过映射和参数对象字典条目进行配置。

        PDO 有两种:发送 PDO 和接收 PDO(TPDO 和 RPDO)。前者用于接收来自设备的数据,后者用于接收前往设备的数据;也就是说,使用 RPDO 可以向设备发送数据,使用 TPDO 可以从设备读取数据。在预定义的连接集中,有四(4)个 TPDO 和四(4)个 RPDO 的标识符。可配置 512 个 PDO。

        PDO 可以同步或非同步发送。同步 PDO 在 SYNC 信息后发送,而异步信息则在内部或外部触发后发送。例如,您可以通过发送带有 RTR 标志的空 TPDO(如果设备配置为接受 TPDO 请求),请求设备发送包含所需数据的 TPDO。

        例如,通过 RPDO,您可以同时启动两个设备。您只需将同一个 RPDO 映射到两个或多个不同的设备中,并确保这些 RPDO 映射的 COB-ID 相同。

5.1 示例

        一个 canopen.RemoteNode 具有 canopen.RemoteNode.rpdo 和 canopen.RemoteNode.tpdo 属性,可用于使用 PDO 与节点交互。这些属性可以用子索引来指定使用哪个映射(第一个映射从 1 开始,而不是 0):

# Read current PDO configuration
node.tpdo.read()
node.rpdo.read()

# Do some changes to TPDO4 and RPDO4
node.tpdo[4].clear()
node.tpdo[4].add_variable('Application Status', 'Status All')
node.tpdo[4].add_variable('Application Status', 'Actual Speed')
node.tpdo[4].trans_type = 254
node.tpdo[4].event_timer = 10
node.tpdo[4].enabled = True

node.rpdo[4].clear()
node.rpdo[4].add_variable('Application Commands', 'Command All')
node.rpdo[4].add_variable('Application Commands', 'Command Speed')
node.rpdo[4].enabled = True

# Save new configuration (node must be in pre-operational)
node.nmt.state = 'PRE-OPERATIONAL'
node.tpdo.save()
node.rpdo.save()

# Start RPDO4 with an interval of 100 ms
node.rpdo[4]['Application Commands.Command Speed'].phys = 1000
node.rpdo[4].start(0.1)
node.nmt.state = 'OPERATIONAL'

# Read 50 values of speed and save to a file
with open('output.txt', 'w') as f:
    for i in range(50):
        node.tpdo[4].wait_for_reception()
        speed = node.tpdo['Application Status.Actual Speed'].phys
        f.write(f'{speed}\n')

# Using a callback to asynchronously receive values
# Do not do any blocking operations here!
def print_speed(message):
    print(f'{message.name} received')
    for var in message:
        print(f'{var.name} = {var.raw}')

node.tpdo[4].add_callback(print_speed)
time.sleep(5)

# Stop transmission of RxPDO
node.rpdo[4].stop()

六、同步对象 (SYNC)

        同步生产者(Sync-Producer)为同步消费者(Sync-Consumer)提供同步信号。同步消费者收到信号后,就开始执行同步任务。

        一般来说,同步 PDO 信息传输时间的固定和同步对象传输的周期性保证了传感器设备可以安排对过程变量进行采样,执行器设备可以以协调的方式执行动作。

        同步对象的标识符位于索引 1005h。

6.1 示例

        使用 canopen.Network.sync 属性启动和停止 SYNC 消息:

# Transmit every 10 ms
network.sync.start(0.01)

network.sync.stop()

七、紧急对象 (EMCY)

        紧急信息由设备内部发生致命错误时触发,以高优先级从相关应用设备传输到其他设备。因此,它们适用于中断类型的错误警报。每个 "错误事件 "只能发送一次紧急报文,即紧急报文不得重复发送。只要设备没有发生新的错误,就不能再发送紧急报文。通过 CANopen 通信配置文件定义的紧急错误代码、错误寄存器和设备配置文件中指定的设备特定附加信息。

7.1 示例

        要列出某个节点当前激活的紧急事件,可以使用 .active 属性,该属性是         canopen.emcy.EmcyError 对象的列表:

active_codes = [emcy.code for emcy in node.emcy.active]
all_codes = [emcy.code for emcy in node.emcy.log]

        canopen.emcy.EmcyError 对象实际上是异常,因此如果您需要,可以很容易地引发异常:

if node.emcy.active:
    raise node.emcy.active[-1]

八、时间戳对象(TIME)

        通常,时间戳对象表示午夜后以毫秒为单位的绝对时间和自 1984 年 1 月 1 日以来的天数。这是一个长度为 48(6 字节)的位序列。

九、层设置服务 (LSS)

        LSS 协议用于更改 CANOpen 目标设备(从站)的节点 ID 和波特率。要更改这些值,主站应首先设置配置状态。然后修改节点 ID 和波特率。从等待状态切换到配置状态有两种选择。一种是一次性切换所有从属设备,另一种是只切换一个从属设备。前者可用于设置所有从属设备的波特率。后者可用于逐个更改节点 ID。

        完成设置后,应将数值保存到非易失性存储器中。最后,可以切换到 LSS 等待状态。

        注意 某些方法和常量名称有所更改:

send_switch_mode_global() ==> send_switch_state_global()
network.lss.CONFIGURATION_MODE ==> network.lss.CONFIGURATION_STATE
network.lss.NORMAL_MODE ==> network.lss.WAITING_STATE

        您仍可使用旧名称,但请使用新名称。

        注意 从 v0.8.0 开始支持 Fastscan。未实施 LSS 识别从属服务。


9.1 示例

        将所有从属设备切换到 CONFIGURATION(配置)状态。信息无响应。

network.lss.send_switch_state_global(network.lss.CONFIGURATION_STATE)

        如果只想切换一个从属设备,也可以使用 4 个 ID 调用此方法:

vendorId = 0x00000022
productCode = 0x12345678
revisionNumber = 0x0000555
serialNumber = 0x00abcdef
ret_bool = network.lss.send_switch_state_selective(vendorId, productCode,
                                    revisionNumber, serialNumber)

        或者,可以运行 fastscan 程序

ret_bool, lss_id_list = network.lss.fast_scan()

        一旦其中一个传感器进入 "配置 "状态,就可以读取 LSS 从站的当前节点 ID:

node_id = network.lss.inquire_node_id()

        更改节点 ID 和波特率:

network.lss.configure_node_id(node_id+1)
network.lss.configure_bit_timing(2)

        这是将比特定时的参数索引转换为波特率的表格。

idx

Baud rate

0

1 MBit/sec

1

800 kBit/sec

2

500 kBit/sec

3

250 kBit/sec

4

125 kBit/sec

5

100 kBit/sec

6

50 kBit/sec

7

20 kBit/sec

8

10 kBit/sec

         保存配置:

network.lss.store_configuration()

        最后,可以将从属设备的状态从 "配置 "状态切换到 "等待 "状态:

network.lss.send_switch_state_global(network.lss.WAITING_STATE)

十、与现有代码集成

        有时,您需要将该库与某些现有代码库结合使用,或者您有 Python-can 不支持的 CAN 驱动程序。本章将介绍一些使用案例。

10.1 重新使用总线

        如果您需要与本库之外的 CAN 总线进行交互,并希望使用相同的 python-can 总线实例,您需要告诉网络使用哪条总线,并将 canopen.network.MessageListener 添加到现有的 can.Notifier 中。

        下面是一个简短的示例:

import canopen
import can

# A Bus instance created outside
bus = can.interface.Bus()

network = canopen.Network()
# Associate the bus with the network
network.bus = bus

# Add your list of can.Listener with the network's
listeners = [can.Printer()] + network.listeners
# Start the notifier
notifier = can.Notifier(bus, listeners, 0.5)

10.2 使用自定义后端

        如果 python-can 软件包不支持您的 CAN 接口,您就需要创建 canopen.Network 的子类,并提供自己的消息发送方式。您还需要在后台线程中向 canopen.Network.notify() 发送接收到的消息。

        下面是一个示例:

import canopen

class CustomNetwork(canopen.Network):

    def connect(self, *args, **kwargs):
        # Optionally use this to start communication with CAN
        pass

    def disconnect(self):
        # Optionally use this to stop communincation
        pass

    def send_message(self, can_id, data, remote=False):
        # Send the message with the 11-bit can_id and data which might be
        # a bytearray or list of integers.
        # if remote is True then it should be sent as an RTR.
        pass


network = CustomNetwork()

# Should be done in a thread but here we notify the network for
# demonstration purposes only
network.notify(0x701, bytearray([0x05]), time.time())

十一、设备配置文件

        在包括 DS301 应用层在内的标准 CANopen 功能基础上,还可以为某些应用提供专门的附加配置文件。

11.1 用于运动控制器和驱动器的 CiA 402 CANopen 设备配置文件

        该设备配置文件具有用于控制驱动器行为的控制状态机。因此,需要使用 BaseNode402 类实例化一个节点

        使用 BaseNode402 创建一个节点:

import canopen
from canopen.profiles.p402 import BaseNode402

some_node = BaseNode402(3, 'someprofile.eds')
network = canopen.Network()
network.add_node(some_node)

11.2 电源状态机

        PowerStateMachine 类提供了控制该状态机状态的方法。静态方法 on_PDO1_callback() 被添加到 TPDO1 回调中。

        通过向寄存器 0x6040 写入特定值(称为 "控制字"),可以控制状态变化。当前状态可通过读取寄存器 0x6041(称为 "Statusword")来读取。只有在 NmtMaster 的 "运行 "状态下才能更改状态。

        需要正确设置映射了控制字和状态字的 PDO,这是大多数 DS402 兼容驱动器的默认配置。要使状态机实现可以访问它们,请运行 BaseNode402.setup_402_state_machine() 方法。请注意,该设置例程默认会读取当前的 PDO 配置,从而导致一些 SDO 流量。这仅在 NmtMaster 的 "OPERATIONAL(运行)"或 "PRE-OPERATIONAL(预运行)"状态下有效:

# run the setup routine for TPDO1 and it's callback
some_node.setup_402_state_machine()

        写入 Controlword 并读取 Statusword:

# command to go to 'READY TO SWITCH ON' from 'NOT READY TO SWITCH ON' or 'SWITCHED ON'
some_node.sdo[0x6040].raw = 0x06

# Read the state of the Statusword
some_node.sdo[0x6041].raw

        在运行过程中,状态可能会变为控制字无法命令的状态,例如 "故障 "状态。因此,BaseNode402 类(与 NmtMaster 类似)会自动监控由 TPDO 发送的状态字的状态变化。然后,TPDO 上的可用回调将提取信息并在 BaseNode402.state 属性中反映状态变化。

        与 NmtMaster 类类似,BaseNode402 类状态属性的状态可以通过字符串读取和设置(命令):

# command a state (an SDO message will be called)
some_node.state = 'SWITCHED ON'
# read the current state
some_node.state

 

        可用状态:

  • 未准备好开启
  • 已禁用
  • 准备开启
  • 已开启
  • 已启用操作
  • 故障
  • 故障反应激活
  • 快速停止激活

        可用命令

  • 禁用开关
  • 禁用电压
  • 准备开启
  • 已开启
  • 启用操作
  • 快速停止激活

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【背包-BM70 兑换零钱(一)】

题目 BM70 兑换零钱(一) 描述 给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。 如果无解,…

Promed Bioscience—高纯度胶原蛋白

Promed Bioscience——高纯度胶原蛋白供应商 专于研发,忠于质量,创新驱动 AXXORA 作为Enzo life sciences公司的子公司,是欧美最大的生命科学研究信息、服务、销售电子一站式服务平台之一,AXXORA精选欧洲四十多家优秀的生命科学研…

[Algorithm][动态规划][01背包问题][模板 背包][分割等和子集]详细讲解 +何为背包问题?

目录 0.何为背包问题?1.模板 背包1.题目链接2.算法原理详解3.代码实现 2.分割等和子集1.题目链接2.算法原理详解3.代码实现 0.何为背包问题? 背包问题:有限制条件下的"组合问题" 你有一个背包,地上有一堆物品&#xff…

基于zyyo主页与無名の主页合并二改,一款适合新手的个人主页

pengzi主页🙋 项目地址 简洁的布局:主页应该有清晰的布局,包括一个简洁的导航菜单和易于浏览的内容区域。避免使用过多的花哨效果,保持页面简洁明了。 个人资料介绍:在主页上展示一段简短的个人介绍,包括…

pikachu靶场(File Inclusion(文件包含)通关教程)

1.File Inclusion(local)本地文件包含 1.1打开网站,发现有个下拉框,随便选择一个,然后点击提交 1.2发现图中有个参数变了,其他的也会变,猜测这里可能有其他隐藏的文件 1.3直接进行抓包 ,右键发送到爆破模…

PXE、无人值守实验

PXE部署 [roottest2 ~]# systemctl stop firewalld [roottest2 ~]# setenforce 0一、部署tftp服务 [roottest2 ~]# yum -y install tftp-server.x86_64 xinetd.x86_64 [roottest2 ~]# systemctl start tftp [roottest2 ~]# systemctl enable tftp [roottest2 ~]# systemctl …

《深入浅出LLM 》(一):大模型概念综述

《深入浅出LLM 》(一):大模型概念综述 一、大模型概念 大规模语言模型(LargeLanguageModels,LLM),也称大规模语言模型或大型语言模型,是一种由包含数百亿以上参数的深度神经网络构建…

Python | Leetcode Python题解之第138题随机链表的复制

题目: 题解: class Solution:def copyRandomList(self, head: Optional[Node]) -> Optional[Node]:allNode[] # 用一个数组存储所有结点cur1headwhile cur1:allNode.append(cur1)cur1cur1.nextnlen(allNode)allRandom[-1]*n # 用一个数组存储所有节点…

Node.js后端构建指南:MongoDB与Express的集成

安装express 安装 Express 并将其保存到依赖列表中: $ cnpm install express --save 以上命令会将 Express 框架安装在当前目录的 node_modules 目录中, node_modules 目录下会自动创建 express 目录。以下几个重要的模块是需要与 express 框架一起安…

开源WebGIS全流程常用技术栈

1 数据生产 1.1 uDig uDig(http://udig.refractions.net/)是一个基于Java开源的桌面应用框架,它构建在Eclipse RCP和GeoTools(一个开源的Java GIS包)上。可以进行shp格式地图文件的编辑和查看;是一个开源空间数据查看…

前端最新面试题(基础模块HTML/CSS/JS篇)

目录 一、HTML、HTTP、WEB综合问题 1 前端需要注意哪些SEO 2 img的title和alt有什么区别 3 HTTP的几种请求方法用途 4 从浏览器地址栏输入url到显示页面的步骤 5 如何进行网站性能优化 6 HTTP状态码及其含义 7 语义化的理解 8 介绍一下你对浏览器内核的理解&#xff1…

阿里云服务器发送邮件失败 Could not connect to SMTP host: smtp.xxx.com, port: 465;

最近做了一个发送邮件的功能, 在本地调试完成后,部署到阿里云服务器就一直报错, Could not connect to SMTP host: smtp.qiye.aliyun.com, port: 465; 网上也搜索了很多的资料,最后花了好几个小时才解决, 报错日志如下…

全新抖音快手小红书视频解析去水印系统网站源码

这个系统支持几十种平台,包括抖音、快手小红书以及其他热门社交媒体平台。它可以帮助轻松地下载这些平台上的任何视频,并去除其中的水印,让你可以自由地保存和分享这些视频。 使用方法: 上传压缩包解压,网站信息在inc…

数据脱敏技术方案选择(word)

1 概述 1.1 数据脱敏定义 1.2 数据脱敏原则 1.2.1基本原则 1.2.2技术原则 1.2.3管理原则 1.3 数据脱敏常用方法 3.1.1泛化技术 3.1.2抑制技术 3.1.3扰乱技术 3.1.4有损技术 1.4 数据脱敏全生命周期 2 制定数据脱敏规程 3 发现敏感数据 4 定义脱敏规则 5 执…

读取文件

自学python如何成为大佬(目录):自学python如何成为大佬(目录)_利用python语言智能手机的默认语言实战一-CSDN博客 在Python中打开文件后,除了可以向其写入或追加内容,还可以读取文件中的内容。读取文件内容主要分为以下几种情况: 1 读取指…

python爬虫入门教程(二):requests库的高级用法

requests库除了基本的GET和POST请求外,requests库还提供了许多高级功能,本文将介绍其中一些常用的用法。包括: 会话保持(Session)SSL证书验证文件上传代理设置自定义HTTP适配器超时设置 请求参数 文章最开始&#x…

github将默认分支main改为master

github将默认分支main改为master 1.进入github,点击setting 2.在setting中,选择Respositories,更新默认分支为master 3.选择要更新的项目,在项目中选择setting->general->切换默认分支

Elastic Search(ES)Java 入门实操(3)数据同步

基本概念和数据查询代码: Elastic Search (ES)Java 入门实操(1)下载安装、概念-CSDN博客 Elastic Search(ES)Java 入门实操(2)搜索代码-CSDN博客 想要使用 ES 来查询数…

MAVEN:自定义模板Archetype的创建

目录 一、简介 二、具体步骤 三、 vscode通过模板创建项目 四、通过IDEA创建 一、简介 有时候MAVEN自带的模板库并不能满足我们创建项目的需求,为了能够快速创建项目,免去每次复杂的配置,所以我们需要自定义模板库,本次操作基于…

控制台输入javac命令输出的结果中的中文乱码解决方式

默认字符编码UTF-8无法解析中文。设置环境变量中 “JAVA_TOOL_OPTIONS” 的值为"UTF-8" 即可。 具体配置步骤: 桌面右键"我的电脑" --> 属性 高级系统设置 环境变量 用户变量中添加 JAVA_TOOL_OPTIONS 然后确定,保存即可。