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
相关推荐
CodeByV2 小时前
【网络】UDP 协议深度解析:从五元组标识到缓冲区
网络·网络协议·udp
虹科网络安全3 小时前
艾体宝洞察 | 利用“隐形字符”的钓鱼邮件:传统防御为何失效,AI安全意识培训如何补上最后一道防线
运维·网络·安全
石像鬼₧魂石3 小时前
Kali Linux 网络端口深度扫描
linux·运维·网络
适应规律4 小时前
UNeXt-Stripe网络架构解释
网络
纸带6 小时前
USB通信的状态
网络
无敌最俊朗@6 小时前
WebSocket与Webhook:实时通信技术对比
网络·websocket·网络协议
悟空空心7 小时前
服务器长ping,traceroute
linux·服务器·网络·ssh·ip·ping++
F133168929577 小时前
5030A 芯片 24V 转 5V 15A 大电流快充选型
网络·单片机·嵌入式硬件·物联网·汽车
2301_773730318 小时前
系统编程—IPC进程间通信
网络·网络协议