Linux network namespace 访问外网以及多命名空间通信(经典容器组网 veth pair + bridge 模式认知)

写在前面


  • 整理K8s网络相关笔记
  • 博文内容涉及 Linux network namespace 访问外网方案 Demo
  • 实际上也就是 经典容器组网 veth pair + bridge 模式
  • 理解不足小伙伴帮忙指正

不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上春树


关于什么是 Linux network namespace ,小伙伴可以看我之前的文章,这里不多介绍

我们知道从 Linux network namespace 发包到因特网是无法通信,所以我们需要一些魔法(Linux bridge 桥接设备)

同时两个 network namespace 可以通过 veth pair 虚拟网卡对连接,但要做到两个以上 network namespace 相互连接,veth pair 就显得捉襟见肘了,这里我们也需要 Linux bridge 桥接设备实现多网络命名空间通信

Linux bridge 就是 Linux 系统中的网桥,但是Linux bridge 的行为更像是一台虚拟的 网络交换机,任意的真实物理设备(例如 eth0)虚拟设备(例如,前面讲到的veth pair以及 tap设备)都可以连接到 Linux bridge 上。但是需要注意的是,Linux bridge 不能跨机连接网络设备.

Linux bridge 与 Linux上其他网络设备的区别在于,普通的网络设备只有两端,从一端进来的数据会从另一端出去。例如,物理网卡从外面网络中收到的数据会转发给内核协议栈,而从协议栈过来的数据会转发到外面的物理网络中。

Linux bridge则有多个端口,数据可以从任何端口进来,进来之后从哪个口出去取决于目的MAC地址,原理和物理交换机差不多。

Linux network namespace 访问外网 配置

我们看一个实际的 Demo,使用Linux内部网桥实用程序创建网桥(vnet-br0),创建红色绿色两个网络名称空间。为redgreen命名空间创建两个veth虚拟网卡对,将veth对的一端连接到特定的命名空间,另一端连接到内部网桥,确保红色绿色命名空间中的接口可以于网桥(vnet-bro)与内部和外部网络通信。

创建两个网络命名空间,创建网桥vnet-br0

┌──[root@liruilongs.github.io]-[~]
└─$ip netns list
┌──[root@liruilongs.github.io]-[~]
└─$ip netns add red
┌──[root@liruilongs.github.io]-[~]
└─$ip netns add green

用于在 Linux 上创建一个名为 vnet-br0桥接设备桥接设备是用于连接多个网络设备的虚拟设备。它可以实现数据包的转发和交换,使得连接到桥接设备的网络设备可以相互通信。

┌──[root@liruilongs.github.io]-[~]
└─$ip link add vnet-br0 type bridge

创建桥接设备后,可以将其他网络设备(如物理网卡、虚拟网卡等)添加到桥接设备上,将它们连接在同一个逻辑网络中,实现数据的转发和交换

桥接设备(Bridge Device)是在网络层次结构中工作的二层设备(Data Link Layer),它主要用于连接多个网络设备,类似于网络交换机的功能。桥接设备通过学习和转发数据帧的方式,将连接到它的网络设备组成一个共享的以太网段,使得这些设备可以直接通信。桥接设备工作在数据链路层(第二层),它不涉及 IP 地址或路由。

通过 ip link 查看设备的状态、属性和配置信息

┌──[root@liruilongs.github.io]-[~]
└─$ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000link/ether 00:0c:29:93:51:67 brd ff:ff:ff:ff:ff:ffaltname enp3s0
5: vnet-br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether ce:93:3b:6d:37:48 brd ff:ff:ff:ff:ff:ff

可以看到刚刚添加的虚拟桥接设备,目前处于 DOWN 状态。

添加虚拟网卡对eth0-r 和 veth-reth0-g 和 veth-g

┌──[root@liruilongs.github.io]-[~]
└─$ip link add eth0-r type veth peer name veth-r
┌──[root@liruilongs.github.io]-[~]
└─$ip link add eth0-g type veth peer name veth-g

把两个虚拟网卡对中的一端放到上面创建的网络命名空间

┌──[root@liruilongs.github.io]-[~]
└─$ip link set eth0-r netns red
┌──[root@liruilongs.github.io]-[~]
└─$ip link set eth0-g netns green

然后将虚拟网卡对的另一端连接到vnet-br0桥。

┌──[root@liruilongs.github.io]-[~]
└─$ip link set veth-r master vnet-br0
┌──[root@liruilongs.github.io]-[~]
└─$ip link set veth-g master vnet-br0

查看根网络命名空间的桥接设备类型的网络设备(桥接表)。

┌──[root@liruilongs.github.io]-[~]
└─$ip link show type bridge
5: vnet-br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 62:2b:41:f9:39:b3 brd ff:ff:ff:ff:ff:ff

查看桥接设备(vnet-br0)关联的网络设备。

┌──[root@liruilongs.github.io]-[~]
└─$ip link show master vnet-br0
6: veth-r@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vnet-br0 state DOWN mode DEFAULT group default qlen 1000link/ether 62:2b:41:f9:39:b3 brd ff:ff:ff:ff:ff:ff link-netns red
8: veth-g@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vnet-br0 state DOWN mode DEFAULT group default qlen 1000link/ether be:a3:9a:1c:a1:06 brd ff:ff:ff:ff:ff:ff link-netns green

根据输出,有两个网络设备与 vnet-br0 桥接设备关联:

veth-r@if7:这是一个虚拟网络设备(veth pair),它与 vnet-br0 桥接设备关联。它的状态是 DOWN,表示当前处于未激活状态。它的 MAC 地址为 62:2b:41:f9:39:b3。此设备属于 red 网络命名空间。

veth-g@if9:这是另一个虚拟网络设备(veth pair),也与 vnet-br0 桥接设备关联。它的状态是 DOWN,表示当前处于未激活状态。它的 MAC 地址为 be:a3:9a:1c:a1:06。此设备属于 green 网络命名空间。

激活桥接对应的网络设备

┌──[root@liruilongs.github.io]-[~]
└─$ip link set vnet-br0 up
┌──[root@liruilongs.github.io]-[~]
└─$ip link set veth-r up
┌──[root@liruilongs.github.io]-[~]
└─$ip link set veth-g up

激活 网络命名空间中的回环地址和对应的虚拟网卡对

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red ip link set lo up
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red ip link set eth0-r up
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green ip link set lo up
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green ip link set eth0-g up

ip link 确认设备状态

┌──[root@liruilongs.github.io]-[~]
└─$ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000link/ether 00:0c:29:93:51:67 brd ff:ff:ff:ff:ff:ffaltname enp3s0
5: vnet-br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000link/ether 62:2b:41:f9:39:b3 brd ff:ff:ff:ff:ff:ff
6: veth-r@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vnet-br0 state UP mode DEFAULT group default qlen 1000link/ether 62:2b:41:f9:39:b3 brd ff:ff:ff:ff:ff:ff link-netns red
8: veth-g@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vnet-br0 state UP mode DEFAULT group default qlen 1000link/ether be:a3:9a:1c:a1:06 brd ff:ff:ff:ff:ff:ff link-netns green

进入网络命名空间 shell 环境,分配 IP

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red bash
┌──[root@liruilongs.github.io]-[~]
└─$ip address add 192.168.20.2/24 dev eth0-r
┌──[root@liruilongs.github.io]-[~]
└─$ip r
# 对于目标网络 192.168.20.0/24 的数据包,它们将使用 eth0-r 设备进行本地通信。
192.168.20.0/24 dev eth0-r proto kernel scope link src 192.168.20.2
┌──[root@liruilongs.github.io]-[~]
└─$ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
7: eth0-r@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000link/ether ca:b0:b2:80:25:43 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 192.168.20.2/24 scope global eth0-rvalid_lft forever preferred_lft foreverinet6 fe80::c8b0:b2ff:fe80:2543/64 scope linkvalid_lft forever preferred_lft forever
┌──[root@liruilongs.github.io]-[~]
└─$exit
exit

对另一个命名空间操作

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green bash
┌──[root@liruilongs.github.io]-[~]
└─$ip address add 192.168.20.3/24 dev eth0-g
┌──[root@liruilongs.github.io]-[~]
└─$ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
9: eth0-g@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000link/ether 36:5e:d9:8d:04:a8 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 192.168.20.3/24 scope global eth0-gvalid_lft forever preferred_lft foreverinet6 fe80::345e:d9ff:fe8d:4a8/64 scope linkvalid_lft forever preferred_lft forever
┌──[root@liruilongs.github.io]-[~]
└─$ip r
192.168.20.0/24 dev eth0-g proto kernel scope link src 192.168.20.3
┌──[root@liruilongs.github.io]-[~]
└─$exit
exit

两个命名空间之间的连通性测试

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green bash
┌──[root@liruilongs.github.io]-[~]
└─$ping -c 2 192.168.20.2
PING 192.168.20.2 (192.168.20.2) 56(84) bytes of data.
64 bytes from 192.168.20.2: icmp_seq=1 ttl=64 time=0.252 ms
64 bytes from 192.168.20.2: icmp_seq=2 ttl=64 time=0.047 ms--- 192.168.20.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1034ms
rtt min/avg/max/mdev = 0.047/0.149/0.252/0.102 ms┌──[root@liruilongs.github.io]-[~]
└─$exit
exit
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red bash
┌──[root@liruilongs.github.io]-[~]
└─$ping -c 2 192.168.20.3
PING 192.168.20.3 (192.168.20.3) 56(84) bytes of data.
64 bytes from 192.168.20.3: icmp_seq=1 ttl=64 time=0.241 ms
64 bytes from 192.168.20.3: icmp_seq=2 ttl=64 time=0.129 ms--- 192.168.20.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1038ms
rtt min/avg/max/mdev = 0.129/0.185/0.241/0.056 ms
┌──[root@liruilongs.github.io]-[~]
└─$exit
exit

将 IP 192.168.20.1/24 分配给根网络命名空间中的 vnet-br0 桥接口,以允许来自红色和绿色名称空间的外部通信,它将成为该网络的默认网关

┌──[root@liruilongs.github.io]-[~]
└─$ip address add 192.168.20.1/24 dev vnet-br0

192.168.20.1配置为绿色和红色命名空间中的默认网关。将所有目标不在本地网络中的数据包发送到该网关进行进一步路由。

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red bash
┌──[root@liruilongs.github.io]-[~]
└─$route add default gw 192.168.20.1
┌──[root@liruilongs.github.io]-[~]
└─$exit
exit
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green bash
┌──[root@liruilongs.github.io]-[~]
└─$route add default gw 192.168.20.1
┌──[root@liruilongs.github.io]-[~]
└─$exit
exit

在 NAT 表中添加一个规则,将源 IP 地址为 192.168.20.0/24 的数据包进行源地址转换 (Source NAT)。

┌──[root@liruilongs.github.io]-[~]
└─$iptables -s 192.168.20.0/24 -t nat -A POSTROUTING -j MASQUERADE

执行该命令后,数据包从子网 192.168.20.0/24 发送到外部网络时,源 IP 地址将被替换为执行 NAT 的接口的 IP 地址。这通常用于实现网络地址转换 (NAT),将内部网络的私有 IP 地址转换为公共 IP 地址,以便与外部网络进行通信。

根命名空间做内网和公网地址Ping

┌──[root@liruilongs.github.io]-[~]
└─$ping 192.169.26.149 -c 3
PING 192.169.26.149 (192.169.26.149) 56(84) bytes of data.
64 bytes from 192.169.26.149: icmp_seq=1 ttl=128 time=199 ms
64 bytes from 192.169.26.149: icmp_seq=2 ttl=128 time=199 ms
64 bytes from 192.169.26.149: icmp_seq=3 ttl=128 time=216 ms--- 192.169.26.149 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 199.020/204.755/215.909/7.888 ms
┌──[root@liruilongs.github.io]-[~]
└─$ping baidu.com -c 3
PING baidu.com (39.156.66.10) 56(84) bytes of data.
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=1 ttl=128 time=11.9 ms
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=2 ttl=128 time=11.9 ms
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=3 ttl=128 time=12.1 ms--- baidu.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 11.919/11.999/12.142/0.100 ms

在主机系统上启用IPV4转发以允许外部通信。执行该命令后,系统将开启 IP 转发功能,允许数据包在不同的网络接口之间进行转发。

┌──[root@liruilongs.github.io]-[~]
└─$sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

在两个命名空间中做内网 ping 测试

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green ping baidu.com -c 3
PING baidu.com (110.242.68.66) 56(84) bytes of data.
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=1 ttl=127 time=20.5 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=2 ttl=127 time=20.0 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=3 ttl=127 time=20.3 ms--- baidu.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 20.031/20.261/20.475/0.181 ms
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red ping baidu.com -c 3
PING baidu.com (110.242.68.66) 56(84) bytes of data.
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=1 ttl=127 time=20.2 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=2 ttl=127 time=20.3 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=3 ttl=127 time=20.1 ms--- baidu.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 20.085/20.197/20.278/0.082 ms

在两个命名空间中做公网 ping 测试

┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec red ping 192.168.26.149 -c 3
PING 192.168.26.149 (192.168.26.149) 56(84) bytes of data.
64 bytes from 192.168.26.149: icmp_seq=1 ttl=64 time=0.241 ms
64 bytes from 192.168.26.149: icmp_seq=2 ttl=64 time=0.110 ms
64 bytes from 192.168.26.149: icmp_seq=3 ttl=64 time=0.075 ms--- 192.168.26.149 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2074ms
rtt min/avg/max/mdev = 0.075/0.142/0.241/0.071 ms
┌──[root@liruilongs.github.io]-[~]
└─$ip netns exec green ping 192.168.26.149 -c 3
PING 192.168.26.149 (192.168.26.149) 56(84) bytes of data.
64 bytes from 192.168.26.149: icmp_seq=1 ttl=64 time=0.258 ms
64 bytes from 192.168.26.149: icmp_seq=2 ttl=64 time=0.097 ms
64 bytes from 192.168.26.149: icmp_seq=3 ttl=64 time=0.094 ms--- 192.168.26.149 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2043ms
rtt min/avg/max/mdev = 0.094/0.149/0.258/0.076 ms
┌──[root@liruilongs.github.io]-[~]
└─$

在这里插入图片描述

到这里,我们实现和两个网络命名空间彼此通信,并且和根命名空间通信,同时可以和公网通信。

简单回顾一下我们干了什么:

  • 在主机的根网络命名空间中创建一个 Linux 网桥,创建两个 Linux 网络命名空间
  • 创建两个 veth pair,将其中一个端口连接到根命名空间中的网桥上,另一个端口放置在目标命名空间中。
  • 在目标命名空间中配置 IP 地址,并将该端口启动起来。
  • 在根命名空间中启用 IP 转发功能(通过设置 net.ipv4.ip_forward=1),分配IP地址,同时在命名空间配置默认网关。
  • 配置 NAT 规则SNAT,将目标命名空间中的流量转发的源IP地址转化为根命名空间中的IP地址。
  • 目标命名空间中的流量将通过默认网关走网桥IP地址转发到根命名空间中,并通过根命名空间中的网络设备连接到互联网。

实际中的应用

实际上上面的 Demo 就是 经典的容器组网模型,veth pair + bridge 的模式,用过 docker 的小伙伴会发现,默认情况下,安装完 docker 会自动创建一个 桥接设备 docker0.

┌──[root@vms100.liruilongs.github.io]-[~/ansible]
└─$ip link show type bridge
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULTlink/ether 02:42:68:f8:90:26 brd ff:ff:ff:ff:ff:ff
┌──[root@vms100.liruilongs.github.io]-[~/ansible]
└─$ip link show master docker0
┌──[root@vms100.liruilongs.github.io]-[~/ansible]
└─$

在不修改网络类型的情况下,docker 也使用桥接的模式,主机中部署的 容器访问公网即通过我们上面配置的方式

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知,这是一个开源项目,如果你认可它,不要吝啬星星哦 😃


https://ramesh-sahoo.medium.com/linux-network-namespace-and-five-use-cases-using-various-methods-f45b1ec5db8f

《Kubernetes 网络权威指南:基础、原理与实践》


© 2018-2024 liruilonger@gmail.com, All rights reserved. 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

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

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

相关文章

【后端高频面试题--Nginx篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;后端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 后端高频面试题--Nginx篇 什么是Nginx&#xff1f;为什么要用Nginx&#xff1f;为什么Nginx性能…

基于Locust实现MQTT协议服务的压测脚本

一、背景简介 业务背景大概介绍一下&#xff0c;就是按照国标规定&#xff0c;车辆需要上传一些指定的数据到ZF的指定平台&#xff0c;同时车辆也会把数据传到企业云端服务上&#xff0c;于是乎就产生了一些性能需求。 目前我们只是先简单的进行了一个性能场景的测试&#xf…

没更新的日子也在努力呀,布局2024!

文章目录 ⭐ 没更新的日子也在努力呀⭐ 近期的一个状态 - 已圆满⭐ 又到了2024的许愿时间了⭐ 开发者要如何去 "创富" ⭐ 没更新的日子也在努力呀 感觉很久没有更新视频了&#xff0c;好吧&#xff0c;其实真的很久没有更新短视频了。最近的一两个月真的太忙了&#…

MATLAB Coder从入门到放弃

一、MATLAB Coder入门 1 MATLAB Coder是什么 从 MATLAB 代码生成 C 和 C 代码 MATLAB Coder™ 可从 MATLAB 代码生成适用于各种硬件平台&#xff08;从桌面计算机系统到嵌入式硬件&#xff09;的 C 和 C 代码。它支持大多数 MATLAB 语言和广泛的工具箱。您可以将生成的代码作…

SHA-512在Go中的实战应用: 性能优化和安全最佳实践

SHA-512在Go中的实战应用: 性能优化和安全最佳实践 简介深入理解SHA-512算法SHA-512的工作原理安全性分析SHA-512与SHA-256的比较结论 实际案例分析数据完整性验证用户密码存储数字签名总结 性能优化技巧1. 利用并发处理2. 避免不必要的内存分配3. 适当的数据块大小总结 与其他…

【玩转408数据结构】线性表——线性表的顺序表示(顺序表)

知识回顾 通过前文&#xff0c;我们了解到线性表是具有相同数据类型的有限个数据元素序列&#xff1b;并且&#xff0c;线性表只是一种逻辑结构&#xff0c;其不同存储形式所展现出的也略有不同&#xff0c;那么今天我们来了解一下线性表的顺序存储——顺序表。 顺序表的定义 …

上个月刚跟男朋友一起买了个三百万的房子,准备明年结婚,这个月他突然被裁了...

职场变动&#xff0c;尤其是裁员&#xff0c;已经成为我们无法忽视的现实。不管你是互联网大佬&#xff0c;还是刚入行的新人&#xff0c;这个问题都可能突如其来&#xff0c;影响到你的生活和计划。 想象一下&#xff0c;你和你的另一半刚刚为了将来的幸福生活&#xff0c;拼尽…

使用 Windows 11/10 上的最佳 PDF 转 Word 转换器释放 PDF 的潜力

毫无疑问&#xff0c;PDF 是最好的文档格式之一&#xff0c;但就像其他格式一样&#xff0c;有时它们确实会带来一些限制。例如&#xff0c;在某些情况下&#xff0c;您可能想要将 PDF 转换为 Word。在这种情况下&#xff0c;您始终可以借助 PDF 到 Word 转换器的帮助。 为了说…

python - 模块使用详解

前言 Python有非常强大的第三方库&#xff0c;也有非常多的内置模块帮助开发人员实现某些功能&#xff0c;无需开发人员自己造轮子。本文介绍Python的模块。 什么是模块 模块简单来说就是一系列功能的集合体&#xff0c;如果将程序的开发比喻成拼图&#xff0c;模块就是各种…

12.atoi函数

文章目录 函数简介函数原型 代码运行 函数简介 函数原型 int atoi(char const *string);函数把字符转化为正数 代码运行 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h>int main() {int ret 0;char str[20] "112233";ret …

Day 43 | 动态规划 1049. 最后一块石头的重量 II 、494. 目标和 、 474.一和零

1049. 最后一块石头的重量 II 题目 文章讲解 视频讲解 思路&#xff1a;dp[j] 表示容量为 j 的背包&#xff0c;最多可以背最大重量为dp[j]。 class Solution {public int lastStoneWeightII(int[] stones) {int sum 0;for (int i 0; i < stones.length; i) {sum stone…

Django模型层part two - 多表关系创建和多表操作

前言 继续上面一篇文章的内容&#xff0c;本文介绍多表操作。使用django ORM可以创建多表关系&#xff0c;并且也支持多张表之间的操作&#xff0c;以创建表关系和查询两部分说明django ORM的多表操作。以作者、图书、出版社和作者信息几张表作为案例进行说明。 创建表关系 …

视觉slam十四讲学习笔记(三)李群与李代数

1. 理解李群与李代数的概念&#xff0c;掌握 SO(3), SE(3) 与对应李代数的表示方式。 2. 理解 BCH 近似的意义。 3. 学会在李代数上的扰动模型。 4. 使用 Sophus 对李代数进行运算。 目录 前言 一、李群李代数基础 1 群 2 李代数的引出 3 李代数的定义 4 李代数 so(3…

Docker笔记-搭建Python环境、安装依赖、打包镜像、导入镜像、编写bash脚本灵活调用

说明 适合无联网的机器及多Python的机器进行部署。 制作docker版Python环境 有网络及有docker的,拉取指定版本的python如: docker pull python:3.7 安装好后进入容器: docker run -it <name> /bin/bash 使用pip安装各种依赖: pip install <name> pip in…

Python访问数据库

目录 SQLite数据库 SQLite数据类型 Python数据类型与SQLite数据类型的映射 使用GUI管理工具管理SQLite数据库 数据库编程的基本操作过程 sqlite3模块API 数据库连接对象Connection 游标对象Cursor 数据库的CRUD操作示例 示例中的数据表 无条件查询 有条件查询 插入…

重学JavaScript高级(十二):async/await-事件循环-面试高频

async/await-事件循环 前面我们学习了生成器和迭代器&#xff0c;那么在本篇文章中&#xff0c;我们主要讲解生成器与Promise的结合使用&#xff0c;从而引出async/await语法&#xff0c;同时会涉及面试中频次最高的一个知识点&#xff1a;事件循环 生成器与异步处理 首先需要…

【Chrono Engine学习总结】4-vehicle-4.1-vehicle的基本概念

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 1、基本介绍 Vehicle Overview Vehicle Mannel Vehicle的官方demo 1.1 Vehicle的构型 一个车辆由许多子系统构成&#xff1a;悬挂、转向、轮子/履带、刹车/油门、动…

搜索专项---最短路模型

文章目录 迷宫问题武士风度的牛抓住那头牛 一、迷宫问题OJ链接 本题思路:只需要记录各个点是有哪个点走过来的&#xff0c;就能递推得出路径。记录前驱假设从 1,1 这个点向下走到了2, 1&#xff0c;则将2,1这个点的前驱记为1,1。这样&#xff0c;将整张地图 bfs 后&#xff0c…

C++进阶(十五)C++的类型转换

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、C语言中的类型转换二、为什么C需要四种类型转换三、C强制类型转换1、static_cast2、reint…

【必看】Onlyfans如何使用搜索功能?Onlyfans如何搜索博主?如何在OnlyFans搜索HongkongDoll

1. 什么是Onlyfans OnlyFans是一种内容订阅服务平台&#xff0c;它成立于2016年。 它允许内容创作者在平台上面分享自己的创作&#xff0c;如图片、视频等等&#xff0c;用户需要支付订阅费用才能查看创作者的内容。此外&#xff0c;用户还可以通过打赏的方式来让创作者为自己…