0%

方式一

通过udev规则监听设备事件,编写/etc/udev/rules.d/99-udev-mount.rules规则实现U盘插入捕获U盘插入事件

1
2
3
4
5
# 插入U盘自动挂载
ACTION=="add", KERNEL=="sd[a-z]*", RUN+="/bin/mkdir -p /media/udev-%k", RUN+="/bin/mount /dev/%k /media/udev-%k"

# 移除U盘自动卸载
ACTION=="remove", KERNEL=="sd[a-z]*", RUN+="/bin/umount /media/udev-%k"

规则编辑完成后执行以下命令使规则生效

1
sudo udevadm control --reload

1. 准备环境

  • 准备开发包:包含头文件(.h)、库文件(.dll或.so)及对接文档
  • 安装依赖:确保Python环境已安装ctypes库或第三方库例如Cython(用于复杂场景)
  • 配置路径:将SDK的库路径添加到环境变量或直接在代码中指定路径(推荐方式,不会因为换电脑导致无法编译,例如sdk/windows/sdk.dll)

2. 封装接口

加载SDK

1
2
3
4
5
6
7
8
9
10
import sys
from ctypes import *
from ctypes import wintypes

# 区分Windows和Linux环境,加载不同SDK
if sys.platform.startwith("win"):
sdk = WinDLL("sdk/windows/sdk.dll")
elif sys.platform.startwith("linux"):
sdk = CDLL("sdk/linux/sdk.so")

定义结构体

1
2
3
4
5
6
7
# 定义结构体,需要与SDK头文件一致
class DEMO
_fields_ = [
("fieldname-1", c_int), # int 类型
("fieldname-2", c_int_p), # int 指针
# 其他字段参考SDK文档
]

![[Python对接C库/IMG-20250327180040644.png]]
定义函数原型,需严格对齐SDK中的数据类型和函数参数顺序

1
2
3
4
sdk.Init.restype = c_bool # 映射返回值,Init为C/C++中的函数名
sdk.Init.argtypes = [ # 映射参数列表
c_int, c_int_p, c_char_p
]

3. 接口调用

函数调用

1
sdk.Init(c_int(0), c_int_p(0), c_char_p(b"this is a test"))

带有回调函数的函数调用
回调函数例如

1
int (*Callback) (int, char*);

Python中定义回调函数类型

1
CallbackType = CFUNCTYPE(c_int, c_int, c_char_p) # 返回类型在前,参数在后

若C函数使用__stdcall(常见于Windows API),需要WINFUNCTYPE替代CFUNCTYPE,若为__cdecl(默认),则使用CFUNCTYPE
Python实现回调函数(参数和返回值需与C定义严格一致)

1
2
3
def py_callback(num, text) -> int:
print(f"Received: {num}, {text.decode("utf-8")}")
return 0 # 返回值需与C定义匹配

处理指针参数

若回调参数包含指针,例如void*,需要使用c_void_p类型,并通过cast解析

1
2
3
def py_callback(data_ptr): 
data = cast(data_ptr, POINTER(c_int)).contents.value
return data

注册回调函数

1
2
3
4
c_callback = CallbackType(py_callback) # 使用定义的回调类型包装Python函数
global_keep_alive = c_callback # 关键! 将回调对象保存为全局变量或类属性,防止被回收
sdk.register_callback.argtypes = [c_int, CallbackType]
sdk.register_callback.restype = None

4. 资源释放

退出时需要调用SDK中的清理函数释放资源

1
sdk.Cleanup()

5. 注意事项

  • 结构体指针和缓冲区需要手动分配/释放,避免内存泄漏
  • 不同版本SDK接口可能有差异,建议统一开发与部署环境
  • 映射Windows中特有的类型例如WORD,DWORDwintypes包中
  • C调用Python回调时,若Python函数抛出异常可能导致程序崩溃。需要在回调内部处理异常。
  • 若C函数在子线程中调用回调,需确保Python的GIL(全局解释锁)已获取
    1
    2
    3
    4
    5
    6
    7
    from ctypes import py_object, pythonapi 
    PyGILState_Ensure = pythonapi.PyGILState_Ensure
    PyGILState_Release = pythonapi.PyGILState_Release
    def thread_safe_callback():
    state = PyGILState_Ensure()
    # 执行Python操作
    PyGILState_Release(state)

使用os.stat()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import (
"fmt"
"os"
)

func main() {
dir := "new"
if _, err := os.Stat(dir); os.IsNotExist(err) {
fmt.Println(dir, "does not exist")
} else {
fmt.Println("The provided directory named", dir, "exists")
}
}

使用os.open()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import (
"fmt"
"os"
)

func main() {
dir := "go"
if _, err := os.Open(dir); os.IsNotExist(err) {
fmt.Println("The directory named", dir, "does not exist")
} else {
fmt.Println("The directory namend", dir, "exists")
}
}

使用mkdir()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import (
"fmt"
"os"
)

func main() {
dir := "new"
if err := os.Mkdir(dir, 0755); os.IsExist(err) {
fmt.Println("The directory named", dir, "exists")
} else {
fmt.Println("The directory named", dir, "does not exist")
}
}

ECB模式,PKCS5填充

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
package sm4

import (
"bytes"
"encoding/hex"
"github.com/tjfoc/gmsm/sm4"
)

func SM4EcbEncrypt(key, plaintext []byte) (string, error) {
block, err := sm4.NewCipher(key)
if err != nil {
return "", err
}

plaintext = PKCS5Padding(plaintext, block.BlockSize())
ciphertext := make([]byte, len(plaintext))

for start := 0; start < len(plaintext); start += block.BlockSize() {
block.Encrypt(ciphertext[start:start+block.BlockSize()], plaintext[start:start+block.BlockSize()])
}

return hex.EncodeToString(ciphertext), nil
}

func SM4EcbDecrypt(key []byte, data string) ([]byte, error) {
plaintext, _ := hex.DecodeString(data)
block, err := sm4.NewCipher(key)
if err != nil {
return nil, err
}

ciphertext := make([]byte, len(plaintext))

for start := 0; start < len(plaintext); start += block.BlockSize() {
block.Decrypt(ciphertext[start:start+block.BlockSize()], plaintext[start:start+block.BlockSize()])
}
ciphertext = PKCS5Unpadding(ciphertext)
return ciphertext, nil
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}

func PKCS5Unpadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}

使用sys模块

1
2
3
4
5
6
7
8
9
10
import sys

if sys.platform.startwith("win"):
print("当前系统是Windows")
elif sys.platform.startwith("linux"):
print("当前系统是Linux")
elif sys.platform.startwith("darwin"):
print("当前系统是MAC OS")
else:
print("当前系统是其他操作系统")

使用platform模块

1
2
3
4
5
6
7
8
9
10
11
import platform

system=platform.system()
if system=="Windows":
print("当前系统是Windows")
elif system=="Linux":
print("当前系统是Linux")
elif system=="Darwin":
print("当前系统是MAC OS")
else:
print("当前系统是其他操作系统")

使用os模块

1
2
3
4
5
6
7
8
9
import os

system = os.name
if system == "nt":
print("当前系统是Windows")
elif system == "posix":
print("当前系统是Linux或Mac OS")
else
print("当前系统是其他操作系统")

临时修改

方法一

1
2
3
4
sudo apt update & sudo apt install net-tools    # 安装 net-tools
sudo ifconfig eth0 down # 停用网卡
sudo ifconfig eth0 hw ether AA:BB:CC:DD:EE:FF # 设置 MAC 地址
sudo ifconfig eth0 up # 启用网卡

方法二

1
2
3
sudo ip link set dev eth0 down                      # 停用网卡 
sudo ip link set dev eth0 address AA:BB:CC:DD:EE:FF # 设置 MAC 地址
sudo ip link set dev eth0 up # 启用网卡

永久修改

注意: 永久修改需要停止NetworkManager服务,此服务可能导致修改不生效

1
2
sudo systemctl stop NetworkManager.service
sudo systemctl disable NetworkManager.service

方法一

编辑`/etc/init.d/rc.local``文件,在此配置文件最后追加临时修改网卡MAC命令

1
2
3
4
# 修改 ech0 网卡的 MAC 地址
sudo ifconfig eth0 down # 网卡名称可使用 ifconfig 或 ip addr 查看
sudo ifconfig eth0 hw ether AA:BB:CC:DD:EE:FF
sudo ifconfig eth0 up

方法二

编辑/etc/network/interfaces文件,在此文件后追加

1
2
3
4
5
6
7
8
auto eth0                         # 网卡自动启动
iface eth0 inet static # 静态 IP
address 192.168.1.2 # IP 地址
netmask 255.255.255.0 # 掩码
gateway 192.168.1.1 # 网关
hwaddress ether AA:BB:CC:DD:EE:FF # MAC 地址
dns-nameservers 223.5.5.5 # DNS 多个用空格隔开
dns-search .com # 限制 .com 的查询走上边设置的DNS服务器

修改完成需要重启网络服务使配置生效

1
2
3
4
sudo systemctl restart networking.service 

# 不同系统服务名可能有不太一样,如果找不到就重启系统
sudo reboot

安装Anaconda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wget https://repo.anaconda.com/archive/Anaconda3-2024.10-1-Linux-x86_64.sh

sudo chmod +x Anaconda3-2024.10-1-Linux-x86_64.sh # 文件添加执行权限

sudo sh Anaconda3-2024.10-1-Linux-x86_64.sh # 执行安装

# Please, press ENTER to continue -> 回车继续
# 阅读协议,同意按回车(跳过ctrl+c)
# Do you accept the license terms? [yes|no] -> 同意协议输入yes回车
# Anaconda3 will now be installed into this location -> 选择安装路径(本文安装/usr/local/anaconda3),等待安装
# by running conda init? [yes|no] -> 是否添加系统环境,输入yes回车
# 待安装结束

# 刷新当前用户环境(激活环境)
source /usr/local/anaconda3/bin

如果是否添加环境变量选择no的话,安装完成需要手动添加环境变量

1
2
export ANACONDA3_ROOT=/usr/local/anaconda3
export PATH=$ANACONDA3_ROOT/bin:$ANACONDA3_ROOT/condabin:$PATH

如果安装时选择了no但安装完成还想初始化可以执行

1
2
source /usr/local/anaconda3/bin/activate
conda init

![[Anaconda环境配置/IMG-20250326093704426.png]]

安装完成后查看.bashrc 中变更内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/usr/local/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/usr/local/anaconda3/etc/profile.d/conda.sh" ]; then
. "/usr/local/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/usr/local/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<

解决打开终端Anaconda自启动问题

1
2
3
4
```
#### 镜像源

北京外国语大学

channels:

Anaconda添加删除虚拟环境

1
2
3
4
5
# 新建虚拟环境 -n 为新建虚拟环境命名
conda create -n python310 python=3.10

# 删除虚拟环境
conda remove -n python310 --all

Anaconda切换虚拟环境

1
2
3
4
5
6
7
8
# 查看所有虚拟环境
conda env list

# 激活虚拟环境
conda activate python310

# 退出虚拟环境
conda deactivate python310

Docker 19.03以上版本可以使用 docker buildx build命令使用BuildKit构建镜像。该命令支持--platform参数可以同时构建多种系统架构的Docker镜像。

新建builder实例

Docker for Linux不支持构建arm架构镜像,可以运行一个新的容器让其支持该特性,Docker Desktop版本无需进行此项设置。

1
docker run --rm --privileged tonistiigi/binfmt:latest --install all 

由于Docker默认的build实例不支持同时指定多个 --platform,必须首先创建一个新的builder实例。

1
2
3
4
5
6
7
8
9
# 适用于国内环境
$ docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master

# 适用于腾讯云环境(腾讯云主机、coding.net 持续集成)
$ docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master-tencent

# $ docker buildx create --name mybuilder --driver docker-container

$ docker buildx use mybuilder

构建镜像

1
2
3
4
5
FROM --platform=$TARGETPLATFORM alpine

RUN uname -a > os.txt

CMD ["cat", "os.txt"]
1
2
3
4
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t {镜像名称} . --push

# 查看镜像信息
docker buildx imagetools inspect {镜像名称}

--push 参数表示将构建好的镜像推送到Docker仓库

架构相关变量

TARGETPLATFORM
构建镜像的目标平台,例如 linux/amd64linux/arm/v7windows/amd64

TARGETOS
构建镜像的OS类型,例如 linuxwindows

TARGETARCH
构建镜像的架构类型,例如 amd64arm

BUILDPLATFORM
构建镜像主机平台,例如 linux/amd64

BUILDOS
构建镜像主机的OS类型,例如 linux

BUILDARCH
构建镜像主机的架构类型,例如 amd64

BUILDVARIANT
BUILDPLATFORM的变种,该变量可能为空,例如 v7

使用举例
例如要构建 linux/arm/v7linux/amd64两种架构的镜像

1
2
3
4
5
6
7
8
9
10
11
FROM docker.io/library/python:3.10-alpine

# 使用变量必须申明
ARG TARGETOS
ARG TARGETARCH

WORKDIR /app

COPY main.py /app

# ENTRYPOINT [/app]

方法1

最简单的一种方法,将当前用户添加到root组。这样做之后该用户将拥有所有root权限,从而使用户在使用sudo时不再需要输入密码。

1
sudo adduser {当前用户名} root 

注意: 将用户添加到root组后,该用户将拥有最高权限,因此在执行系统级操作时要特别小心,以避免可能的系统破坏。

方法2(推荐)

通过编辑/etc/sudoers文件来配置特定用户或组的sudo行为。这种方法允许更灵活的控制哪些命令可以绕过密码提示。
![[Linux配置sudo无密码/IMG-20250319160639846.png]]

单用户配置

1
{用户名} ALL=(ALL:ALL) NOPASSWD:ALL #在 root 后新添加一行

用户组配置

1
%{用户组} ALL=(ALL:ALL) NOPASSWD:ALL # 在 %sudo 后添加

使用此方式需将用户添加进组

1
sudo usermod -a -G {用户组} {用户名}

安装Golang

Windows版本下载安装程序安装即可,Ubuntu下有两种安装方式
第一种方式

1
2
sudo apt update
sudo apt install golang

此种方式安装的版本并不是最新版,或者下载 [官方包]执行

1
2
sudo tar -zxvf go1.24.2.linux-amd64.tar.gz -C  /usr/local # 解压缩到/usr/local
sudo chmod 755 -R /usr/local/go # 修改权限,一般解压后就有权限,此步可以省略

配置环境变量

Windows

打开 系统设置->关于->高级系统设置->环境变量,注意如果只给当前用户使用添加到用户的环境变量即可,全部用户可用需配置系统环境变量。

GOROOT

![[Golang环境配置/IMG-20250319151338172.png]]

GOPATH
![[Golang环境配置/IMG-20250319151450977.png]]

GOPROXY

![[Golang环境配置/IMG-20250319151516015.png]]

Ubuntu

如果只给当前用户使用编辑用户目录下.bashrc文件,全部用户可用需配置/etc/profile

1
2
3
export GOROOT=/usr/local/go # Golang根目录
export GOPATH=/home/go-project # 项目根目录
export PATH=$GOROOT/bin:$GOPATH/bin:$PATH

进阶配置

GOPROXY可在环境变量中配置也可使用go env -w命令配置

1
2
3
go env -w GOPROXY=https://goproxy.cn # 七牛
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/ # 阿里
go env -w GOPROXY=https://goproxy.io # 官方

GO111MODULE
从go 1.11版本开始,推荐使用Go Modules进行包管理。

1
go env -w GO111MODULE=on

在项目目录下初始化模块

1
go mod init