0%

  1. 安装依赖环境

    1
    2
    3
    4
    5
    6
    7
    8
    # 启用虚拟化平台
    dism /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

    # 启用linux子系统
    dism /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all

    wsl --install
    wsl --update
  2. 安装Podman

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 安装DockerCLI,用于兼容Docker命令
    winget install --id Docker.DockerCLI

    # 安装Podman
    winget install --id RedHat.Podman

    # 安装Podman Desktop (可选)
    winget install --id RedHat.Podman-Desktop

    # 初始化Podman
    podman machine init

    # 配置端口转发
    wsl sudo sysctl net.ipv4.ip_forward=1
  3. 配置wsl虚拟机

    1
    2
    3
    4
    5
    6
    7
    # 修改默认软件源
    sudo sed -e 's|^metalink=|#metalink=|g' \
    -e 's|^#baseurl=http://download.example/pub/fedora/linux|baseurl=https://mirrors.tuna.tsinghua.edu.cn/fedora|g' \
    -i.bak \
    /etc/yum.repos.d/fedora.repo \
    /etc/yum.repos.d/fedora-updates.repo
    sudo dnf makecache
  4. 测试

    1
    docker run --rm -d -p 80:80 --name httpd docker.io/library/httpd:latest
  5. 配置镜像加速
    podman的配置文件在容器内 /etc/containers/registries.conf,配置格式如下

    1
    2
    3
    4
    5
    unqualified-search-regustrues = ["docker.io"]

    [[registry]] # 注意此处配置不需要加'https'
    prefix = "docker.io" # 访问地址
    location = "docker.m.daocloud.io" # 加速地址
  6. 配置私有镜像库

1
2
3
[[registry]]
location = "harbor.example.io"
insecure = true

如果访问地址为https需要配置信任证书

1
2
sudo mkdir /etc/containers/certs.d
sudo cp <path to cert> /etc/containers/certs.d/ca.crt
  1. 配置文件翻译
    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
    # 有关此配置文件的更多信息,请参阅 containers-registries.conf(5)。
    #
    # 注意:使用未完全限定镜像名称的风险
    # 我们建议始终使用包括注册表服务器(完整 DNS 名称)、命名空间、镜像名称和标签在内的完全限定镜像名称
    # (例如,registry.redhat.io/ubi8/ubi:latest)。通过摘要(例如,
    # quay.io/repository/name@digest)拉取镜像可以进一步消除标签的不确定性。
    # 使用短名称时,始终存在镜像被伪造的风险。例如,用户想从某个注册表中拉取名为
    # `foobar` 的镜像,并期望该镜像来自 myregistry.com。如果
    # myregistry.com 不是搜索列表中的第一个,攻击者可能会在列表中靠前的位置
    # 放置另一个名为 `foobar` 的镜像。用户可能会意外拉取并运行攻击者的镜像和代码,而不是
    # 预期的内容。我们建议只添加完全可信的注册表(即,不允许未知或匿名用户
    # 创建任意名称的账户的注册表)。这将防止镜像被伪造、抢占或以其他方式变得不安全。
    # 如果有必要使用这些注册表,它应该添加到列表的末尾。
    #
    # # 一个主机[:端口]格式的注册表数组,当拉取未完全限定镜像时,按顺序尝试这些注册表。
    unqualified-search-registries = ["registry.fedoraproject.org", "registry.access.redhat.com", "docker.io"]
    #
    # [[registry]]
    # # "prefix" 字段用于选择相关的 [[registry]] TOML 表;
    # # 使用输入镜像名称时,只有与该名称最长匹配的 TOML 表会被使用
    # # (考虑到命名空间/库/标签/摘要分隔符)。
    # #
    # # 如果缺少 prefix 字段,则默认与 "location" 字段相同。
    prefix = "example.com/foo"
    #
    # # 如果为 true,则允许未加密的 HTTP 连接以及使用不受信任证书的 TLS 连接。
    insecure = false
    #
    # # 如果为 true,则禁止拉取匹配名称的镜像。
    blocked = false
    #
    # # "prefix" 所在命名空间的物理位置。
    # #
    # # 默认情况下,与 "prefix" 相同(在这种情况下,可以省略 "prefix",并且 [[registry]] TOML 表只指定 "location")。
    # #
    # # 例如:假设
    # # prefix = "example.com/foo"
    # # location = "internal-registry-for-example.net/bar"
    # # 那么对镜像 example.com/foo/myimage:latest 的请求实际上会与
    # # internal-registry-for-example.net/bar/myimage:latest 镜像匹配。
    location = "internal-registry-for-example.com/bar"
    #
    # # "prefix" 所在命名空间的(可能部分的)镜像。
    # #
    # # 将按指定顺序尝试这些镜像;第一个可以联系到并包含镜像的将被使用
    # # (如果所有镜像都没有该镜像,则最后尝试 "registry.location" 字段指定的主位置,或者使用未修改的用户指定引用)。
    # #
    # # "mirror" 数组中的每个 TOML 表可以包含以下字段,语义与直接在 [[registry]] TOML 表中指定的相同:
    # # - location
    # # - insecure
    [[registry.mirror]]
    location = "example-mirror-0.local/mirror-for-foo"
    [[registry.mirror]]
    location = "example-mirror-1.local/mirrors/foo"
    insecure = true
    # # 根据上述配置,拉取 example.com/foo/image:latest 时将按顺序尝试:
    # # 1. example-mirror-0.local/mirror-for-foo/image:latest
    # # 2. example-mirror-1.local/mirrors/foo/image:latest
    # # 3. internal-registry-for-example.net/bar/image:latest
    # # 并使用第一个存在的镜像。
    #
    # short-name-mode="enforcing"
    # 强制使用完全限定镜像名称

    [[registry]]
    location="localhost:5000"
    insecure=true
    # 允许使用不安全的连接拉取本地镜像。

1
2
3
4
git config --global http."内网域名".sslCAInfo "证书所在路径"

# 示例
git config --global http."https://example.io".sslCAInfo ~/.certs/selfsigned-root-ca.crt

1. Co., Ltd.

  • 全称:Company Limited
  • 含义:有限责任公司,常见于英国、中国及亚洲地区
  • 特点:”Co.“为Company缩写,”.“表示缩写符号,”,”用于分隔前后词

2. Inc.

  • 全称:Incorporated
  • 含义:股份有限公司,多用于美国、加拿大
  • 示例:Apple Inc.,强调股东责任限于股份投资

3. LLC

  • 全称:Limited Liability Company
  • 含义:有限责任公司(美国特有形式)
  • 特点:兼具合伙制灵活性与股份制有限责任,如Google LLC

4. GmbH

  • 全称:Gesellschaft mit beschränkter Haftung
  • 含义:有限责任公司,德国及德语区专用
  • 示例:Bosch GmbH1

5. AG

  • 全称:Aktiengesellschaft
  • 含义:股份有限公司,德国及瑞士常见
  • 示例:BMW AG

6. S.A.

- 全称:Société Anonyme(法)/Sociedad Anónima(西)
- 含义:股份有限公司,流行于法国、西班牙等拉丁语系国家
- 示例:L’Oréal S.A.1

7. Plc

  • 全称:Public Limited Company
  • 含义:公众有限公司(英国上市企业专用)
  • 示例:HSBC Holdings plc1

8. 株式会社(Kabushiki Kaisha)

  • 缩写:KK
  • 含义:日本股份有限公司
  • 示例:Toyota Motor Corporation KK

地域差异提示

  • 英国”Ltd.”与美国”LLC”虽均表有限责任,但法律结构不同
  • 荷兰用”BV”(私人有限公司),意大利用”S.p.A.”(股份公司)

方式一

通过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