ubuntu应当如何设置,才能在有WIFI时自动连接; 没有WIFI时开启自身的WIFI热点?
这个问题可以通过多种方法实现。
1. 使用 create_ap 工具(推荐)
安装 create_ap
bash
# 安装依赖
sudo apt update
sudo apt install -y hostapd dnsmasq iw
# 安装 create_ap
cd /tmp
git clone https://github.com/oblique/create_ap
cd create_ap
sudo make install
# 检查网卡是否支持AP模式
iw list | grep "AP"
创建自动切换脚本
bash
#!/bin/bash
# wifi_auto_switch.sh
# 保存为 /usr/local/bin/wifi_auto_switch.sh
# 配置参数
WIFI_INTERFACE="wlan0" # 无线网卡名称
ETH_INTERFACE="eth0" # 有线网卡(如果有)
HOTSPOT_SSID="Ubuntu-AP"
HOTSPOT_PASSWORD="ubuntu1234"
CHECK_INTERVAL=30 # 检查间隔(秒)
SCAN_TIMEOUT=10 # 扫描超时(秒)
# 日志文件
LOG_FILE="/var/log/wifi_auto_switch.log"
touch $LOG_FILE
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 检查是否已连接WIFI
check_wifi_connected() {
# 方法1: 使用 nmcli
if command -v nmcli &> /dev/null; then
nmcli -t -f GENERAL.STATE dev show $WIFI_INTERFACE | grep -q "connected"
return $?
fi
# 方法2: 使用 iw
iw dev $WIFI_INTERFACE link | grep -q "Connected"
return $?
}
# 检查是否有可用的WIFI网络
scan_available_wifi() {
log "扫描可用WIFI网络..."
# 保存已知的WIFI网络
known_networks=()
if [ -f "/etc/NetworkManager/system-connections/" ]; then
known_networks=($(sudo ls /etc/NetworkManager/system-connections/ | sed 's/\.nmconnection//'))
fi
# 扫描网络
scan_result=$(timeout $SCAN_TIMEOUT sudo iw dev $WIFI_INTERFACE scan | grep "SSID:" | awk '{print $2}' | sort | uniq)
for network in $scan_result; do
for known in "${known_networks[@]}"; do
if [ "$network" = "$known" ]; then
log "找到已知网络: $network"
return 0 # 找到已知网络
fi
done
done
return 1 # 未找到已知网络
}
# 连接到已知WIFI
connect_to_wifi() {
log "尝试连接到已知WIFI..."
# 使用NetworkManager自动连接
if command -v nmcli &> /dev/null; then
sudo nmcli connection up $(sudo nmcli -t -f NAME,UUID,DEVICE con show | grep $WIFI_INTERFACE | cut -d: -f1 | head -1)
sleep 5
return $?
fi
return 1
}
# 启动热点模式
start_hotspot() {
log "启动热点模式..."
# 停止可能存在的create_ap进程
sudo pkill create_ap
sleep 2
# 启动热点
sudo create_ap $WIFI_INTERFACE $ETH_INTERFACE $HOTSPOT_SSID $HOTSPOT_PASSWORD \
--no-virt \
--freq-band 2.4 \
--channel 6 \
--ht_capab '[HT40+]' \
--hidden \
--isolate-clients \
--mac-filter \
--mac-filter-accept /etc/hostapd/hostapd.accept \
--daemon \
--logfile /var/log/create_ap.log
if [ $? -eq 0 ]; then
log "热点启动成功: SSID=$HOTSPOT_SSID"
return 0
else
log "热点启动失败"
return 1
fi
}
# 停止热点模式
stop_hotspot() {
log "停止热点模式..."
sudo pkill create_ap
sleep 2
}
# 主循环
main() {
log "WIFI自动切换服务启动"
log "网卡: $WIFI_INTERFACE"
log "检查间隔: ${CHECK_INTERVAL}秒"
hotspot_running=false
while true; do
log "检查网络状态..."
# 检查WIFI是否已连接
if check_wifi_connected; then
log "WIFI已连接"
# 如果热点正在运行,停止它
if [ "$hotspot_running" = true ]; then
stop_hotspot
hotspot_running=false
fi
else
log "WIFI未连接,扫描可用网络..."
# 扫描可用网络
if scan_available_wifi; then
log "发现已知网络,尝试连接..."
connect_to_wifi
if check_wifi_connected; then
log "WIFI连接成功"
continue
fi
fi
# 没有可用的WIFI,启动热点
if [ "$hotspot_running" = false ]; then
log "没有可用WIFI,启动热点..."
start_hotspot
if [ $? -eq 0 ]; then
hotspot_running=true
fi
else
log "热点模式已运行"
fi
fi
# 等待下一次检查
sleep $CHECK_INTERVAL
done
}
# 运行主函数
main "$@"
创建systemd服务
bash
# 创建服务文件
sudo tee /etc/systemd/system/wifi-auto-switch.service << 'EOF'
[Unit]
Description=Auto switch between WIFI client and hotspot mode
After=network.target
Wants=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/wifi_auto_switch.sh
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# 启用服务
sudo systemctl daemon-reload
sudo systemctl enable wifi-auto-switch.service
sudo systemctl start wifi-auto-switch.service
# 查看状态
sudo systemctl status wifi-auto-switch.service
2. 使用 NetworkManager 和 dnsmasq
创建热点配置文件
bash
# 创建热点配置
sudo tee /etc/NetworkManager/system-connections/Hotspot.nmconnection << 'EOF'
[connection]
id=Hotspot
uuid=$(uuidgen)
type=wifi
interface-name=wlan0
permissions=
[wifi]
mode=ap
ssid=Ubuntu-Hotspot
band=bg
channel=6
[wifi-security]
key-mgmt=wpa-psk
psk=ubuntu1234
[ipv4]
method=shared
address1=192.168.42.1/24
[ipv6]
addr-gen-mode=stable-privacy
method=shared
EOF
创建自动切换脚本
python
#!/usr/bin/env python3
# /usr/local/bin/wifi_monitor.py
import subprocess
import time
import re
import logging
from pathlib import Path
# 配置
WIFI_INTERFACE = "wlan0"
HOTSPOT_CONNECTION = "Hotspot"
CHECK_INTERVAL = 30 # 秒
LOG_FILE = "/var/log/wifi_monitor.log"
# 设置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler()
]
)
class WifiManager:
def __init__(self):
self.current_mode = None
def check_wifi_connection(self):
"""检查WIFI是否连接"""
try:
# 使用 nmcli 检查连接状态
result = subprocess.run(
['nmcli', '-t', '-f', 'GENERAL.STATE', 'dev', 'show', WIFI_INTERFACE],
capture_output=True,
text=True
)
if 'connected' in result.stdout:
return True
# 检查是否有活跃的连接
result = subprocess.run(
['nmcli', '-t', '-f', 'NAME,DEVICE', 'con', 'show', '--active'],
capture_output=True,
text=True
)
for line in result.stdout.strip().split('\n'):
if WIFI_INTERFACE in line:
return True
return False
except Exception as e:
logging.error(f"检查WIFI连接失败: {e}")
return False
def scan_available_networks(self):
"""扫描可用网络"""
try:
# 获取已知网络
known_networks = []
connections_path = Path('/etc/NetworkManager/system-connections/')
if connections_path.exists():
for file in connections_path.glob('*.nmconnection'):
with open(file, 'r') as f:
content = f.read()
if 'type=wifi' in content and 'mode=infrastructure' in content:
# 提取SSID
match = re.search(r'ssid=([^\n]+)', content)
if match:
known_networks.append(match.group(1))
# 扫描当前网络
result = subprocess.run(
['nmcli', '-t', '-f', 'SSID,SIGNAL', 'dev', 'wifi', 'list'],
capture_output=True,
text=True,
timeout=10
)
available_networks = []
for line in result.stdout.strip().split('\n'):
if ':' in line:
ssid, signal = line.split(':')[:2]
if ssid and ssid not in ['--', '']:
available_networks.append(ssid)
# 检查是否有已知网络可用
for network in known_networks:
if network in available_networks:
logging.info(f"找到已知网络: {network}")
return True
return False
except Exception as e:
logging.error(f"扫描网络失败: {e}")
return False
def connect_to_wifi(self):
"""自动连接到WIFI"""
try:
logging.info("尝试自动连接WIFI...")
# 使用NetworkManager自动连接
result = subprocess.run(
['nmcli', 'con', 'up', 'id', '$(nmcli -t -f NAME,UUID,DEVICE con show | grep wlan0 | cut -d: -f1 | head -1)'],
shell=True,
capture_output=True,
text=True
)
if result.returncode == 0:
logging.info("WIFI连接成功")
return True
else:
logging.warning("自动连接失败,尝试手动连接已知网络")
# 获取已知网络列表
result = subprocess.run(
['nmcli', '-t', '-f', 'NAME,TYPE', 'con', 'show'],
capture_output=True,
text=True
)
for line in result.stdout.strip().split('\n'):
if 'wifi' in line.lower():
connection_name = line.split(':')[0]
logging.info(f"尝试连接: {connection_name}")
subprocess.run(
['nmcli', 'con', 'up', 'id', connection_name],
capture_output=True
)
time.sleep(5)
if self.check_wifi_connection():
return True
return False
except Exception as e:
logging.error(f"连接WIFI失败: {e}")
return False
def start_hotspot(self):
"""启动热点"""
try:
logging.info("启动热点模式...")
# 先断开所有WIFI连接
subprocess.run(['nmcli', 'dev', 'disconnect', WIFI_INTERFACE])
time.sleep(2)
# 启动热点连接
result = subprocess.run(
['nmcli', 'con', 'up', HOTSPOT_CONNECTION],
capture_output=True,
text=True
)
if result.returncode == 0:
logging.info("热点启动成功")
self.current_mode = 'hotspot'
return True
else:
logging.error(f"热点启动失败: {result.stderr}")
return False
except Exception as e:
logging.error(f"启动热点失败: {e}")
return False
def stop_hotspot(self):
"""停止热点"""
try:
logging.info("停止热点模式...")
subprocess.run(['nmcli', 'con', 'down', HOTSPOT_CONNECTION])
time.sleep(2)
self.current_mode = None
return True
except Exception as e:
logging.error(f"停止热点失败: {e}")
return False
def run(self):
"""主循环"""
logging.info("WIFI管理器启动")
while True:
try:
# 检查当前状态
wifi_connected = self.check_wifi_connection()
if wifi_connected:
logging.info("WIFI已连接")
# 如果热点正在运行,停止它
if self.current_mode == 'hotspot':
self.stop_hotspot()
else:
logging.info("WIFI未连接,检查可用网络...")
# 扫描可用网络
if self.scan_available_networks():
# 尝试连接
if self.connect_to_wifi():
continue
# 没有可用网络,启动热点
if self.current_mode != 'hotspot':
logging.info("没有可用网络,启动热点...")
self.start_hotspot()
else:
logging.info("热点模式运行中...")
# 等待下次检查
time.sleep(CHECK_INTERVAL)
except KeyboardInterrupt:
logging.info("收到停止信号")
break
except Exception as e:
logging.error(f"主循环错误: {e}")
time.sleep(10)
if __name__ == "__main__":
manager = WifiManager()
manager.run()
创建systemd服务
bash
# 创建服务文件
sudo tee /etc/systemd/system/wifi-manager.service << 'EOF'
[Unit]
Description=Python WIFI Manager
After=network.target NetworkManager.service
Wants=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/bin/python3 /usr/local/bin/wifi_monitor.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# 启用服务
sudo systemctl daemon-reload
sudo systemctl enable wifi-manager.service
sudo systemctl start wifi-manager.service
3. 最佳实践总结
-
对于服务器/无界面系统 :使用 方案1(create_ap),最稳定
-
对于桌面系统 :使用 方案2(NetworkManager + Python脚本),集成度好
4. 关键配置步骤
-
检查网卡驱动:确保无线网卡驱动支持AP模式
bashiw list | grep -A10 "Supported interface modes" -
配置防火墙
bashsudo ufw allow 53 # DNS sudo ufw allow 67 # DHCP sudo ufw allow 68 # DHCP sudo ufw allow 5353 # mDNS -
设置开机自启
bashsudo systemctl enable <服务名> -
调试工具
bash# 查看网络状态 ip addr show wlan0 iw dev wlan0 link # 查看服务日志 sudo journalctl -u wifi-auto-switch -f # 手动测试 sudo create_ap wlan0 eth0 MyHotspot MyPassword
- 电源管理:关闭WIFI电源管理避免断开
bash
echo 'options iwlwifi power_save=0' | sudo tee /etc/modprobe.d/iwlwifi.conf
- 冲突避免:确保NetworkManager不会干扰hostapd
bash
sudo nmcli radio wifi off