ARM虚拟机安装OMV
OMV(OpenMediaVault)是基于 Debian GNU/Linux 的网络连接存储(network attached storage,NAS)解决方案。它包含 SSH、(S) FTP、SMB/CIFS、DAAP 媒体服务器、rsync、 BitTorrent 等很多种服务。它可用于 x86-64 和 ARM 平台。
在x86-64平台上,基于x86-64虚拟机安装OMV软件是相对容易的事情,例如使用VirtualBox创建一个x86-64虚拟机,参考官方的x86-64平台安装文档可以轻松搞定。但是基于ARM虚拟机则没有那么容易,因为在x86-64平台上,VirtualBox不支持创建ARM虚拟机,这时就需要用到QEMU了。
根据官方文档,在ARM平台上安装,需要Armbian镜像,这里选用通用的ARM64镜像,而不是用于特定ARM开发板例如树莓派等的镜像。
============================================================
操作流程(基于Ubuntu 24.04 LTS系统):
----------------------------------
安装QEMU:
sudo apt install qemu-system-arm
验证QEMU:
qemu-system-aarch64 -version
----------------------------
下载Armbian 24.2.1 Bookworm CLI(OMV不支持桌面环境,因此下载这个版本):
wget https://dl.armbian.com/uefi-arm64/archive/Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img.xz
解压Armbian镜像:
xz -kd Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img.xz
OMV系统盘和数据盘是分开的,并且要求系统盘可用空间大于4GB。
系统盘就是用Armbian镜像虚拟的硬盘,基本上已经没有多少可用空间了,因此需要先扩容。
给Armbian镜像增加8GB容量用于安装OMV等软件:
qemu-img resize Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img +8G
创建一个qcow2格式的虚拟硬盘作为OMV数据盘:
qemu-img create -f qcow2 omvdata.qcow2 16G
虚拟硬盘是动态分配大小的,因此创建完成后文件大小只有几百KB,不是8GB。
---------------------------
创建虚拟网桥和虚拟网卡:
sudo apt install iproute2(系统默认已经安装)
可选安装:brctl、tunctl、dhclient
sudo apt install bridge-utils
sudo apt install uml-utilities
sudo apt install isc-dhcp-client-ddns
创建虚拟网桥和虚拟网卡:
sudo ip link add br0 type bridge
sudo ip tuntap add dev tap0 mode tap
连接虚拟网桥和虚拟网卡:
sudo ip link set dev tap0 master br0
连接物理网卡(WiFi网卡需要配置4-address 模式支持WDS桥接)到虚拟网桥:
sudo iw dev wlx14cf92fe3d77 set 4addr on
sudo ip link set dev wlx14cf92fe3d77 master br0
启动虚拟网桥:
sudo ip link set dev br0 up
查看网桥连接的网卡:
sudo brctl show br0
清除物理网卡上的IP地址(同时也会清除路由):
sudo ip address flush wlx14cf92fe3d77 dynamic
使用
DHCP
方式给网桥分配
IP
(会自动配置网关和
DNS
):
sudo dhclient br0
或者给网桥配置静态IP,这种情况需要同时需要手动配置网关和DNS(否则无法连接外网):
sudo ip address flush wlx14cf92fe3d77 dynamic
sudo ip address add 192.168.2.99/24 dev br0
sudo ip route add default via 192.168.2.1 dev br0
sudo resolvectl dns br0 192.168.2.1 8.8.8.8
也可以使用brctl和tunctl命令配置网桥更简单:
sudo brctl addbr br0
sudo brctl stp br0 on
sudo tunctl -t tap0
sudo brctl addif br0 tap0
sudo iw dev wlx14cf92fe3d77 set 4addr on
sudo brctl addif br0 wlx14cf92fe3d77
sudo ip link set dev br0 up
sudo ip address flush wlx14cf92fe3d77 dynamic
sudo dhclient br0
使用无线网卡,桥接网络可能不稳定,DHCP获取IP时间也会长一些。如果连接中断,重新连接WiFi,检查网卡是否还连接网桥,重新配置IP地址。
网桥连接有线网卡会稳定一些:
sudo ip link add br0 type bridge
sudo ip tuntap add dev tap0 mode tap
sudo ip link set dev tap0 master br0
sudo ip link set dev enp4s0 master br0
sudo ip link set dev br0 up
也可以使用
brctl
和
tunctl
命令:
sudo brctl addbr br0
sudo brctl stp br0 on
sudo tunctl -t tap0
sudo brctl addif br0 tap0
sudo brctl addif br0 enp4s0
sudo ip link set dev br0 up
清除物理网卡上的
IP
(同时也清除路由),通过
DHCP
给网桥分配
IP
:
sudo ip address flush enp4s0 dynamic
sudo dhclient br0
如果给网桥配置静态
IP
,需要同时配置默认路由和
DNS
(否则无法访问外网):
sudo ip address flush enp4s0 dynamic
sudo ip address add 192.168.2.99/24 dev br0
sudo ip route add default via 192.168.2.1 dev br0
sudo resolvectl dns br0 192.168.2.1 8.8.8.8
注:系统重启之后,这些虚拟网桥、虚拟网卡都没有了,需要再次配置。
配置好虚拟网桥和虚拟网卡之后,后面启动
QEMU
就可以使用这里配置的虚拟网卡
tap0
了。
-----------------------
启动Armbian系统,并使用上面准备好的镜像,数据盘和虚拟网卡:
sudo qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 8 -m 8G -nographic -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -drive file=Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img,if=virtio -drive file=omvdata.qcow2,if=virtio -net nic -net tap,ifname=tap0
需要注意的是,这里要指定BIOS,可以使用QEMU自带的BIOS,默认路径/usr/share/qemu-efi-aarch64/QEMU_EFI.fd。
如果在第一次启动之前就将系统镜像扩容,进入系统后根分区会自动扩容。如果根分区没有扩容,使用resize2fs命令扩容根分区:
resize2fs /dev/vda2
注:使用网桥比使用user网络或者user网络加端口转发启动QEMU,下面的操作要省事很多。
---------------------------------
以下操作在Armbian系统上执行:
第一次启动Armbian系统,根据提示创建root密码,并创建一个普通用户alpha:
配置完成后,系统已经自动分配了IP(跟网桥同一个网段,跟外网直通):
注:登录界面也可以看到IP地址(但这些IP信息可能是过时的),如果系统没有自动获取到IP,可以手动配置IP,并确保能ping通网桥IP,能连接外网。这时主机上root和新建的普通用户都可以通过ssh登录Armbian系统。
查看系统盘(vda)和数据盘(vdb)也都正常:
先安装两个工具软件:
sudo apt install vim
sudo apt install net-tools
查看系统的TCP端口,可以看到sshd服务已经打开:
netstat -antp
注:虽然sshd服务已经打开,但不要通过ssh连接安装OMV,否则可能安装不完整,安装完成后,进入OMV的web管理页面,左边栏目什么条目都没有。
安装OMV软件:
安装前的工作:
检查systemd-networkd.service,如果是指向/dev/null的符号连接,将其删除:
ls -al /etc/systemd/system/systemd-networkd.service
删除systemd-networkd.service文件:
rm /etc/systemd/system/systemd-networkd.service
修改armbian-ramlog.service服务文件:
vi /etc/systemd/system/sysinit.target.wants/armbian-ramlog.service
将默认的TimeoutStartSec=30sec
改为TimeoutStartSec=180sec
安装OMV keyring:
apt-get install --yes gnupg
wget --quiet --output-document=- https://packages.openmediavault.org/public/archive.key | gpg --dearmor --yes --output "/usr/share/keyrings/openmediavault-archive-keyring.gpg"
添加OMV官方的软件源:
cat <<EOF >> /etc/apt/sources.list.d/openmediavault.list
deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://packages.openmediavault.org/public sandworm main
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://downloads.sourceforge.net/project/openmediavault/packages sandworm main
## Uncomment the following line to add software from the proposed repository.
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://packages.openmediavault.org/public sandworm-proposed main
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://downloads.sourceforge.net/project/openmediavault/packages sandworm-proposed main
## This software is not part of OpenMediaVault, but is offered by third-party
## developers as a service to OpenMediaVault users.
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://packages.openmediavault.org/public sandworm partner
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://downloads.sourceforge.net/project/openmediavault/packages sandworm partner
EOF
OMV软件源也可以用清华大学的软件源:
cat <<EOF > /etc/apt/sources.list.d/openmediavault.list
deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/OpenMediaVault/public sandworm main
deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/OpenMediaVault/packages sandworm main
## Uncomment the following line to add software from the proposed repository.
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/OpenMediaVault/public sandworm-proposed main
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/OpenMediaVault/packages sandworm-proposed main
## This software is not part of OpenMediaVault, but is offered by third-party
## developers as a service to OpenMediaVault users.
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/OpenMediaVault/public sandworm partner
# deb [signed-by=/usr/share/keyrings/openmediavault-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/OpenMediaVault/packages sandworm partner
EOF
安装OMV软件包:
export LANG=C.UTF-8
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none
apt-get update
apt-get --yes --auto-remove --show-upgraded \
--allow-downgrades --allow-change-held-packages \
--no-install-recommends \
--option DPkg::Options::="--force-confdef" \
--option DPkg::Options::="--force-confold" \
install openmediavault
执行这个命令之后,开始从OMV源下载软件版安装。
软件下载和安装需要较长时间,耐心等待安装完毕。
安装失败问题解决:
Failed to preset unit, unit /etc/systemd/system/systemd-networkd.service is masked.
/usr/bin/deb-systemd-helper: error: systemctl preset failed on systemd-networkd.service: No such file or directory
dpkg: error processing package openmediavault (--configure):
installed openmediavault package post-installation script subprocess returned error exit status 1
Processing triggers for libc-bin (2.36-9+deb12u4) ...
Processing triggers for rsyslog (8.2302.0-1) ...
Processing triggers for man-db (2.11.2-2) ...
Processing triggers for dbus (1.14.10-1~deb12u1) ...
Processing triggers for initramfs-tools (0.142) ...
update-initramfs: Generating /boot/initrd.img-6.6.16-current-arm64
Processing triggers for php8.2-cli (8.2.18-1~deb12u1) ...
Processing triggers for php8.2-fpm (8.2.18-1~deb12u1) ...
Processing triggers for php8.2-cgi (8.2.18-1~deb12u1) ...
Errors were encountered while processing:
openmediavault
E: Sub-process /usr/bin/dpkg returned an error code (1)
失败原因是/etc/systemd/system/systemd-networkd.service文件是指向/dev/null的软连接:
root@uefi-arm64:~# ls -al /etc/systemd/system/systemd-networkd.service
lrwxrwxrwx 1 root root 9 Feb 13 18:45 /etc/systemd/system/systemd-networkd.service -> /dev/null
解决办法是删除该文件,然后执行修复安装:
rm /etc/systemd/system/systemd-networkd.service
apt install -f
也可以在安装之前先删除这个文件,这样就不会有这个问题了。
安装最后的update-initramfs步骤需要花较长时间:
update-initramfs: Generating /boot/initrd.img-6.6.16-current-arm64
启动失败问题解决:
重启之后,查看TCP端口,并没有发现web服务(workbench)的80端口。
回头检查启动过程的日志,可以发现nginx.service服务启动失败:
[FAILED] Failed to start nginx.serv…server and a reverse proxy server.
See 'systemctl status nginx.service' for details.
失败原因是/var/log/nginx/error.log文件不存在,实际上/var/log/nginx目录不存在。
再往前看,还有两个失败:
一个是 systemd-networkd-wait-online.service启动失败:
[ *] Job systemd-networkd-wait-online.se…ice/start running (49s / no limit)
[FAILED] Failed to start systemd-ne…Wait for Network to be Configured.
See 'systemctl status systemd-networkd-wait-online.service' for details.
这个失败可以忽略。
另外一个是armbian-ramlog.service启动失败:
[ 58.738034] systemd[1]: armbian-ramlog.service: Main process exited, code=killed, status=15/TERM
[ 59.154114] systemd[1]: armbian-ramlog.service: Failed with result 'timeout'.
[FAILED] Failed to start armbian-ra… Armbian memory supported logging.
See 'systemctl status armbian-ramlog.service' for details.
这个失败原因是启动超时。
armbian-ramlog.service服务负责创建和恢复/var/log/nginx目录和日志,启动失败导致nginx日志目录和文件无法创建。
检查服务安装情况:
dpkg -s "nginx" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
dpkg -s "apache2" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
dpkg -s "samba" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
dpkg -s "cron-apt" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
dpkg -s "proftpd-basic" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
dpkg -s "lighttpd" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
dpkg -s "unattended-upgrades" 2>/dev/null | awk -F": " '/^Status/ {print $2}'
这些服务需要在/var/log/目录创建子目录保存日志,而/var/log/目录的内容是保存在内存中的,是用zram内存区域虚拟的硬盘(Mounting /dev/zram1 as /var/log),重启之后数据丢失,需要重新创建子目录。/usr/lib/armbian/armbian-ramlog负责系统启动后自动创建这些子目录(以及从硬盘恢复日志数据),通过armbian-ramlog.service
服务运行
。
解决办法:
armbian-ramlog.service服务启动需要一分多钟,默认30s无法完成启动,因此需要等待长一点时间(例如3分钟,如果改为0s,则不检测超时)。
修改armbian-ramlog.service服务文件:
vi /etc/systemd/system/sysinit.target.wants/armbian-ramlog.service
将默认TimeoutStartSec=30sec
改为TimeoutStartSec=180sec
保存后重启系统
。
armbian-ramlog.service
服务启动时间也可以在安装
OMV
软件之前就修改
。
注:
如果在
QEMU
终端修改,
默认vi窗口大小只有23行76列,看起来不舒服甚至显示错乱,可以通过stty命令修改终端大小,例如:
stty rows 36 cols 140
需要注意的是,窗口大小不要超过虚拟终端行列大小(主机上可以通用
stty -a
查看),不然
vi
窗口显示也会错乱。
打开
OMV
管理页面(
workbench
):
系统重启之后,在登录界面可以看到系统
IP
,以及
OMV
管理
web
的用户名和密码:
使用浏览器打开这个
web
页面:
可以使用
IPv4
地址:
也可以使用
IPv6
地址(需要将
IPv6
地址放在方括号内):
输入用户名和密码登录后,可以看到WEB管理页面:
配置普通用户
ssh
登录:
安装完
OMV
软件后,
Armbian
系统第一次启动时创建的普通用户不能
ssh
登录(在安装
OMV
之前是可以登录的)。
可以通过
OMV
管理界面,编辑用户信息,将用户加入
_ssh
组,保存并应用之后就可以了。
配置
SMB
服务:
配置SMB
服务有几个主要的步骤:
1
、使用
OMV
数据盘创建文件系统并挂载。
2
、在上面挂载的文件系统上创建共享文件夹。
3
、配置共享文件夹权限。
4
、用前面创建的共享文件夹配置
SMB/CIFS
服务共享。
5
、在用户管理页面,创建用户,给用户配置访问共享文件夹的权限。
6
、通过系统创建的用户,需要使用
smbpasswd
命令将用户配置为
samba
用户。可以使用
pdbedit -L
命令查询
samba
用户列表。
打开存储器配置界面,创建
EXT4
文件系统,选择
OMV
数据盘(
/dev/sdb
),保存:
然后挂载该文件系统,保存并应用:
成功之后可以看到挂载的文件系统:
打开共享文件夹页面,创建共享文件夹
:
配置好共享文件夹的名称、路径、权限,保存并应用:
成功后可以看到刚才创建的共享文件夹:
配置共享文件夹权限,给用户和用户组增加读写权限,保存并应用:
进入SMB/CIFS服务,配置共享:
选择刚才创建的共享文件夹,保存并应用:
成功之后,在SMB/CIFS共享页面,可以看到刚才创建的SMB共享文件夹:
可以在OMV系统上使用netstat -antp命令看到smbd服务端口139已经开启。
此时,在文件管理器输入smb://192.168.3.191可以打开SMB服务器,看到共享文件夹,但是无法访问该文件夹。
将用户添加到sambashare组,保存并应用:
但这个时候仍然无法打开共享文件夹,并且使用smbclient命令浏览共享文件夹也可能会失败:
smbclient --user=alpha -L 192.168.3.191
Password for [WORKGROUP\alpha]:
session setup failed: NT_STATUS_LOGON_FAILURE
系统创建的用户,无法通过WEB配置访问SMB服务,需要在系统上通过smbpasswd命令将用户配置为samba用户才可以:
sudo smbpasswd alpha
执行该命令后,用户可以正常打开OMV共享目录了。
通过OMV的用户管理创建的用户,按照上面的配置,直接可以访问SMB共享文件夹。
例如创建一个名为samba的用户,用户组为sambashare,保存并应用:
在用户权限管理页面,配置用户访问SMB共享文件夹的权限,保存并应用,就可以访问SMB共享文件夹了:
电脑打开smb://192.168.3.191访问共享文件夹:
连接在同一个网络手机也可以访问SMB共享文件夹,通过文件管理的网络邻居扫描网络邻居,可以找个OMV主机,使用前面配置的samba用户(alpha或者samba两个用户),就可以打开共享文件夹了。
========================================================
测试定位问题过程参考:
下载Armbian镜像(qemu-uboot-arm64镜像):
从https://www.armbian.com/download/入口,选择qemu,aarch64,就可以找到qemu-uboot-arm64镜像了。
下载Armbian Noble Minimal (U-boot bin):
https://github.com/armbian/os/releases/download/24.5.0-trunk.558/Armbian_24.5.0-trunk.558_Qemu-uboot-arm64_noble_current_6.6.30_minimal.u-boot.bin.xz
下载Armbian Noble Minimal (QCOW2):
https://github.com/armbian/os/releases/download/24.5.0-trunk.558/Armbian_24.5.0-trunk.558_Qemu-uboot-arm64_noble_current_6.6.30_minimal.img.qcow2.xz
下载uefi-arm64镜像:
从https://www.armbian.com/download/入口,选择ARM,aarch64,找到uefi-arm64镜像:
下载Armbian 24.2.1 Bookworm CLI(OMV不支持桌面环境,因此下载这个版本):
https://dl.armbian.com/uefi-arm64/archive/Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img.xz
或者
https://dl.armbian.com/uefi-arm64/archive/Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16_minimal.img.xz
启动Armbian系统(uefi-arm64镜像):
先解压Armbian镜像:
xz -kd Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img.xz
带GUI启动Armbian系统:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 8 -m 8G-drive file=Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img,if=virtio -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd
运行命令后会显示QEMU窗口,将View菜单切换到serial0项可以看到系统输出:
不带GUI启动Armbian系统:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 8 -m 8G -drive file=Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img,if=virtio -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -nographic
启动uefi-arm64镜像需要指定-bios参数,可以使用qemu安装的BIOS,默认路径/usr/share/qemu-efi-aarch64/QEMU_EFI.fd。
启动虚拟机加上端口转发,以便可以在主机上访问虚拟机上的服务
:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 8 -m 8G -drive file=Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img,if=virtio -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -nographic -nic user,model=virtio-net-pci,hostfwd=tcp::20022-:22,hostfwd=tcp::20080-:80,hostfwd=tcp::20139-:139
增加数据盘:
先创建一个qcow2格式的虚拟硬盘:
qemu-img create -f qcow2 omvdata.qcow2 16G
把这个硬盘加到系统上:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 8 -m 8G -drive file=Armbian_24.2.1_Uefi-arm64_bookworm_current_6.6.16.img,if=virtio -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -nographic -nic user,model=virtio-net-pci,hostfwd=tcp::20022-:22,hostfwd=tcp::20080-:80,hostfwd=tcp::20139-:139 -drive file=omvdata.qcow2,if=virtio
创建SMB共享目录,使用端口转发的方式不能访问在主机访问共享目录。
使用连接网桥的虚拟网卡启动系统:
sudo qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 8 -m 8G -drive file=Armbian_24.2.1_U
efi-arm64_bookworm_current_6.6.16.img,if=virtio -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -nographic -drive file=omvdata.qcow2,if=virtio -net nic -net tap,ifname=tap0
启动Armbian系统(qemu-uboot-arm64镜像):
TODO
===================================================================
参考:
Armbian(默认用户名/密码):https://docs.armbian.com/
OMV硬件要求:https://docs.openmediavault.org/en/stable/prerequisites.html
OMV安装指导:https://docs.openmediavault.org/en/stable/installation/index.html
OMV安装指导:https://docs.openmediavault.org/en/stable/installation/on_debian.html
OMV 版本:Releases — openmediavault 7.x.y documentation
OMV清华源:https://mirrors.tuna.tsinghua.edu.cn/help/openmediavault/
OMV 编译与安装:一起NAS吧!开源NAS系统Openmediavault 编译与安装过程 - 哔哩哔哩
修改vi窗口大小:https://superuser.com/questions/598877/vi-only-show-16-lines-how-to-show-full-screen
zRAM 内存压缩机制:https://cloud.tencent.com/developer/article/2335437
systemd和TimeoutStartSec
:
https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
虚拟网桥和虚拟网卡配置:Documentation/Networking - QEMU
虚拟网桥和虚拟网卡配置:https://blog.csdn.net/qq_38505969/article/details/129645659
虚拟网桥和虚拟网卡配置:https://unix.stackexchange.com/questions/714921/adding-a-physical-ethernet-interface-to-kvm-qemu-bridge
相关文章:

ARM虚拟机安装OMV
OMV(OpenMediaVault)是基于 Debian GNU/Linux 的网络连接存储(network attached storage,NAS)解决方案。它包含 SSH、(S) FTP、SMB/CIFS、DAAP 媒体服务器、rsync、 BitTorrent 等很多种服务。它可用于 x86-64 和 ARM 平台。 在x86-64平台上&…...

【协议开发系列】梳理关于TCP和UDP两种协议的区别和使用场景
起源 前二天项目上在核对外部对接服务的五元组列表的时候,有一位客户提问对于同样的服务同时支持tcp和udp二种方式,有什么优点和缺点,应该如何选择?这个问题突然让我愣了一下,确实好久没有“温故”了,相关…...
vue blob实现自定义多sheet数据导出到excel文件
背景:最近vue项目遇到一个需求,就是需要将多个表格分成不同sheet页并导出,之前的工具类只能导出一个sheet页,所以在原有的基础上,调整一下,让它支持多sheet导出。 vue blob文件流,这个肯定要的…...

Python—面向对象小解(3)
一、多态 多态指的是一类事物的多中形态 相同的方法,产生不同的执行结果 运算符 * 的多态 int int 加法计算 str str 字符串拼接 list list 列表的数据合并 在python中可以使用类实现一个多态效果 在python中使用重写的方式实现多态 (1)定…...
Nginx超时时间
Nginx是一款自由、开源、高性能的HTTP和反向代理服务器,它可以通过不同的设置来提高网站的性能和安全性。其中,设置Nginx超时时间非常重要,因为它将直接影响网站的响应速度和用户体验。本文将从多个方面详细阐述Nginx超时时间的设置方法与注意…...
Imgs,GT,Edge,Gradient_all,Gradient_Foreground
保存一下: 做个记录: import cv2 import os import numpy as np# 对整张图片做canny检测 得到纹理图 def canny_all(input_path, output_path):# 遍历文件夹中的所有文件for filename in os.listdir(input_path):# 构造完整的文件路径image_path os.p…...
自学成才Flutter 弹性布局、线性布局
本文我们要介绍 Flutter 中布局 Widget,包括弹性布局、线性布局 流式布局和层叠布局。 Flutter中文网 Flutter开发 一、弹性布局--Flex Flex 类似 Android 中的 FlexboxLayout,和 Expanded 配合使用可以实现子Widget 按照一定比例来分配父容器空间。 使…...

Part 3.1 深度优先搜索
深度优先搜索(DFS),即按照深度优先的顺序搜索的算法。 深度优先搜索一般使用栈来实现。 [USACO1.5] 八皇后 Checker Challenge 题目描述 一个如下的 6 6 6 \times 6 66 的跳棋棋盘,有六个棋子被放置在棋盘上,使得…...

前端Vue小兔鲜儿电商项目实战Day03
一、Home - 整体结构搭建和分类实现 1. 页面结构 ①按照结构新增5个组件,准备最简单的模板,分别在Home模块的入口组件中引入 src/views/Home/components/ HomeCategory.vue HomeBanner.vue HomeNew.vue HomeHot.vue HomeProduct.vue <script …...
ORACLE 查询SQL优化
1 使用EXPLAIN PLAN 使用EXPLAIN PLAN查看查询的执行计划,这可以帮助你理解查询是如何被Oracle执行的。基于执行计划,你可以确定是否存在索引缺失、不必要的全表扫描等问题。 以下是几种使用EXPLAIN PLAN的方法: 使用EXPLAIN PLAN FOR: 你可以…...

Ansible03-Ansible Playbook剧本详解
目录 写在前面5. Ansible Playbook 剧本5.1 YAML语法5.1.1 语法规定5.1.2 示例5.1.3 YAML数据类型 5.2 Playbook组件5.3 Playbook 案例5.3.1 Playbook语句5.3.2 Playbook1 分发hosts文件5.3.3 Playbook2 分发软件包,安装软件包,启动服务5.3.3.1 任务拆解…...

Qt-qrencode生成二维码
Qt-qrencode开发-生成二维码📀 文章目录 Qt-qrencode开发-生成二维码📀[toc]1、概述📸2、实现效果💽3、编译qrencode🔍4、在QT中引入编译为静态库的QRencode5、在Qt中直接使用QRencode源码6、在Qt中使用QRencode生成二…...
长安链使用Golang编写智能合约教程(三)
本篇主要介绍长安链Go SDK写智能合约的一些常见方法的使用方法或介绍 资料来源: 官方文档官方示例合约库 官方SDK接口文档 教程一:智能合约编写1 教程二:智能合约编写2 一、获取参数、获取状态、获取历史记录的方法解析 注意! …...

Vercel deploy- Nextjs project error-URL link-env variable
Vercel deploy- Nextjs project error-URL link-env variable Error Check Database URL Check next-auth URL NEXTAUTH_URLhttps://yourappname.vercel.app/ 依次排查可能性 Application error: a server-side exception has occurred (see the server logs for more in…...

Java | Leetcode Java题解之第123题买卖股票的最佳时机III
题目: 题解: class Solution {public int maxProfit(int[] prices) {int n prices.length;int buy1 -prices[0], sell1 0;int buy2 -prices[0], sell2 0;for (int i 1; i < n; i) {buy1 Math.max(buy1, -prices[i]);sell1 Math.max(sell1, b…...

Ubuntu22.04之扩展并挂载4T硬盘(二百三十三)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...
Redis实现延迟队列
最近用到一个延迟消息的功能,第一时间想到使用MQ或者MQ的插件,因为数据量不大,所以尝试使用Redis来实现了,毕竟Redis也天生支持类似MQ的队列消费,所以,在这里总结了一下Redis实现延迟消息队列的方式。 一、…...

如何准确查找论文数据库?
在学术研究过程中,查找相关论文是获取最新研究成果、支持自己研究的重要途径。准确查找论文数据库不仅可以节省时间,还能确保找到高质量的学术资源。本文将介绍一些有效的方法和策略,帮助您准确查找论文数据库。 1. 选择合适的数据库 不同的…...

翻译《The Old New Thing》- What a drag: Dragging a virtual file (IStream edition)
What a drag: Dragging a virtual file (IStream edition) - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20080319-00/?p23073 Raymond Chen 2008年03月19日 拖拽虚拟文件(IStream 版本) 上一次,我们看…...

【FPGA】Verilog语言从零到精通
接触fpga一段时间,也能写点跑点吧……试试系统地康康呢~这个需要耐心但是回报巨大的工作。正原子&&小梅哥 15_语法篇:Verilog高级知识点_哔哩哔哩_bilibili 1Verilog基础 Verilog程序框架:模块的结构 类比:c语言的基础…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...

《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...