ubuntu中的WIFI与自身热点切换

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. 对于服务器/无界面系统 :使用 方案1(create_ap),最稳定

  2. 对于桌面系统 :使用 方案2(NetworkManager + Python脚本),集成度好

4. 关键配置步骤

  1. 检查网卡驱动:确保无线网卡驱动支持AP模式

    bash 复制代码
    iw list | grep -A10 "Supported interface modes"
  2. 配置防火墙

    bash 复制代码
    sudo ufw allow 53    # DNS
    sudo ufw allow 67    # DHCP
    sudo ufw allow 68    # DHCP
    sudo ufw allow 5353  # mDNS
  3. 设置开机自启

    bash 复制代码
    sudo systemctl enable <服务名>
  4. 调试工具

    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
相关推荐
huainingning26 分钟前
盈高安全准入设备与深信服实现单点登录对接配置
服务器·网络·安全
网硕互联的小客服1 小时前
如何在Ubuntu系统上查看和刷新DNS缓存?操作方法与原理解析
运维·服务器·网络·ubuntu
Lynne3091 小时前
工业边缘计算网关到底解决什么问题?从设备接入到AI推理的技术链路
网络·数据分析·数据
鲁邦通物联网2 小时前
海外设备怎么远程维护?工业路由器远程运维架构设计
运维·网络·智能路由器·工业路由器·工业级路由器·5g路由器·5g工业路由器
艾芯微科技2 小时前
ESDUNL24VC1 单向 ESD 静电保护二极管参数、电路设计与 PCB 防护布局
网络·单片机·嵌入式硬件·集成测试·51单片机
❁满城风絮*2 小时前
Nginx—从默认页面到高性能网
网络·nginx
java_nnnn3 小时前
面试题(网络部分前传)-13问
服务器·网络·网络协议·tcp/ip·面试
码少女3 小时前
Linux--套接字编程
linux·服务器·网络
上海云盾-小余4 小时前
业务被 DDoS 打崩?四层、七层攻击特征与防护方案复盘
网络·网络协议·tcp/ip·ddos
优化Henry4 小时前
学习笔记之关于MME不通问题归纳
运维·网络·学习·5g·信息与通信