【瑞芯微Rockchip Linux平台】SoftAp需求实现(1)进程代码实现
一、SoftAp启动命令二、SoftAp启动命令封装实现过程2.1 在log前添加系统时间2.2 查看进程是否正在运行 process_is_alive()2.3 杀死进程 kill_process()2.4 循环监控相关进程的运行状态2.5 添加异常处理函数三、dnsmasq.conf 文件配置四、hostapd.conf 文件配置五、完整代码最近上层有个需求,需要实现启动SoftAp热点,如果记录下所有的实现过程。
本文链接:《【瑞芯微Rockchip Linux平台】SoftAp需求实现(1)进程代码实现》
本系列文章链接:
《【瑞芯微Rockchip Linux平台】SoftAp需求实现(1)进程代码实现》《【瑞芯微Rockchip Linux平台】SoftAp需求实现(2)根据传参修改SSID和密码,SSID以wifi MAC地址后四位对结尾》《【瑞芯微Rockchip Linux平台】SoftAp需求实现(3)动态获取BT Mac地址并更新beacon帧中的mac信息》
一、SoftAp启动命令
其实这些,使用命令就能够实现,
打开命令如下:
iw phy0 interface add wlan1 type managed
ifconfig wlan1 up
ifconfig wlan1 192.168.50.1 netmask 255.255.255.0
route add default gw 192.168.50.1 wlan1
dnsmasq -C /data/bin/dnsmasq_softap.conf --interface=wlan1
hostapd /data/bin/hostapd.conf -t -B
关闭命令如下:
kill -15 dnsmasq
kill -15 hostapd
route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1
ifconfig wlan1 down
iw dev wlan1 del
其他命令配置
二、SoftAp启动命令封装实现过程
根据上层的需求,将前面的这些命令进行封装,封装成库和都可执行程序都行。
本需求,我选择的是封装成可执行程序。
2.1 在log前添加系统时间
主要是利用宏控来重写printf函数,这样,在打印每一句log前都会调用get_cur_time
获取下当前的系统时间,精确到ms。
#include <time.h>static char *get_cur_time(void){static char s[50]={0};char s_ms[10]={0};time_t t;struct tm *ltime;struct timeval tv; time(&t);ltime = localtime(&t);gettimeofday(&tv,NULL); //tv.tv_sec * 1000 + tv.tv_usec / 1000; strftime(s, 50, "%Y-%m-%d %H:%M:%S", ltime);sprintf(s_ms, ".%03d", tv.tv_usec / 1000);strcat(s, s_ms);return s;}#define printf_t(fmt, ...) printf("[%s][Dongle_Soft_ap] "fmt, get_cur_time(), ##__VA_ARGS__)
2.2 查看进程是否正在运行 process_is_alive()
这个比较简单,主要是通过ps -A | grep dnsmasq | wc -l
来对进程数量进行统计,如果数量大于等1,则说明当前进程正在运行。
该函数返回的是进程运行的数量。
int process_is_alive(const char *process){FILE *fp = NULL;int pid = 0;char buff_tmp[100]={0};sprintf(buff_tmp, "ps -A | grep %s | wc -l", process);fp = popen(buff_tmp, "r");if(fp){memset(buff_tmp, 0, 100);fgets(buff_tmp, sizeof(buff_tmp)-1, fp);pclose(fp);if(buff_tmp != NULL){pid = atoi(buff_tmp);return pid;}}return -1;}
2.3 杀死进程 kill_process()
通过popen
来获取命令的输出信息来解析到进程的进程号,然后再kill 掉。
一般来说,建议使用kill -15
来杀进程,它会等待进程释放相关的资源,不容易出来资源泄漏的问题。
void kill_process(const char *process, int level){FILE *fp = NULL;int pid = 0;char buff_tmp[100]={0}, *p_buff=NULL, *p_buff1=NULL;sprintf(buff_tmp, "ps -A | grep %s", process);fp = popen(buff_tmp, "r");if(fp){memset(buff_tmp, 0, 100);while(fgets(buff_tmp, sizeof(buff_tmp)-1, fp) >0){p_buff = buff_tmp;while(p_buff!=NULL && *p_buff!='\0' && *p_buff==' ') p_buff++;p_buff1 = p_buff;while(p_buff1!=NULL && *p_buff1!='\0' && *p_buff1!=' ') p_buff1++;*p_buff1 = '\0';pid = atoi(p_buff);if( kill(pid, level) == 0)// kill(pid, 15)printf_t("===>杀死后台%s进程(%d)(-%d) success\n",process, pid, level);}pclose(fp);}}
2.4 循环监控相关进程的运行状态
在main
函数中,主要工作 就是启动hostapdf
进程,然后,循环监控hostapd
和dnsmasq
进程的存活状态,
只要其中有任何一个进程出现异常,都会关注softap
热点,然后释放相关资源。
int main(int argc, char *argv[]){// 1. 启动前杀死现有的 dnsmasq 和 hostapdkill_all_process();usleep(200000);// 2. 启动 hostapdsystem("iw phy0 interface add wlan1 type managed");system("ifconfig wlan1 up");sleep(1);system("ifconfig wlan1 192.168.50.1 netmask 255.255.255.0");system("route add default gw 192.168.50.1 wlan1");printf_t("===>运行命令:dnsmasq -C /data/bin/dnsmasq_softap.conf --interface=wlan1\n");system("dnsmasq -C /data/bin/dnsmasq_softap.conf --interface=wlan1");printf_t("===>运行命令:hostapd /data/bin/hostapd.conf -t -B\n");system("hostapd /data/bin/hostapd.conf -t -B");printf_t("===>开始循环监控dnsmasq 和 hostapd -------\n");while(keep_alive == 1){sleep(1);if( process_is_alive("dnsmasq") == 0){printf_t("===>dnsmasq进程异常,开始关闭hostap\n");break;}if( process_is_alive("hostapd") == 0){printf_t("===>hostapd进程异常,开始关闭hostap\n");break;}}// 3. 恢复初始状态kill_all_process();printf_t("===>route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1\n");system("route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1");printf_t("===>ifconfig wlan1 down\n");system("ifconfig wlan1 down");system("iw dev wlan1 del");printf_t("程序运行结束-------------\n");return 0;}
2.5 添加异常处理函数
添加一个全局变量keep_alive
用于确认当前进程是否需要主动退出。
在main
函数中,注册SIGINT、SIGABRT、SIGTERM、SIGKILL
四个信号,绑定函数sig_handler
,
当过程在运行过程中,收到这四个信号中的任何一个,都会进入sig_handler
函数,将keep_alive
清0,结束main
函数中的循环监控,释放相关的资源。
void sig_handler( int sig ){if ( sig == SIGINT || sig == SIGABRT || sig == SIGTERM || sig == SIGKILL){keep_alive = 0;printf_t("===>收到停止信号, keep_alive=%d\n", keep_alive);}}int main(int argc, char *argv[]){// 注册异常处理函数signal( SIGINT, sig_handler );signal( SIGABRT, sig_handler );signal( SIGTERM, sig_handler );signal( SIGKILL, sig_handler );}
三、dnsmasq.conf 文件配置
user=root# listen-address=127.0.0.1except-interface=usb0#interface=p2p-wlan0-0# dhcp-option=p2p-wlan0-0,1,255.255.225.0#指定掩码# dhcp-option=p2p-wlan0-0,3,192.168.50.1#指定网关# dhcp-option=p2p-wlan0-0,6,192.168.50.1#指定dnsdhcp-range=192.168.50.2,192.168.50.51# log-queries# log-facility=/data/dnsmasq.log
四、hostapd.conf 文件配置
interface=wlan0ctrl_interface=/var/run/hostapddriver=nl80211ssid=soft-apauth_algs=1wpa=2wpa_passphrase=12345678wpa_key_mgmt=WPA-PSK#wpa_pairwise=TKIPrsn_pairwise=CCMP# 5G 149 channel=149hw_mode=aieee80211ac=1ignore_broadcast_ssid=0# 2.4G 6#channel=6#hw_mode=g#ieee80211n=1#ignore_broadcast_ssid=0
五、完整代码
#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <time.h>#include <unistd.h>#include <string.h>#ifdef __cplusplusextern "C" {#endifstatic int keep_alive = 1;static char *get_cur_time(void){static char s[50]={0};char s_ms[10]={0};time_t t;struct tm *ltime;struct timeval tv; time(&t);ltime = localtime(&t);gettimeofday(&tv,NULL); //tv.tv_sec * 1000 + tv.tv_usec / 1000; strftime(s, 50, "%Y-%m-%d %H:%M:%S", ltime);sprintf(s_ms, ".%03d", tv.tv_usec / 1000);strcat(s, s_ms);return s;}#define printf_t(fmt, ...) printf("[%s][Dongle_Soft_ap] "fmt, get_cur_time(), ##__VA_ARGS__)void sig_handler( int sig ){if ( sig == SIGINT || sig == SIGABRT || sig == SIGTERM || sig == SIGKILL){keep_alive = 0;printf_t("===>收到停止信号, keep_alive=%d\n", keep_alive);}}int process_is_alive(const char *process){FILE *fp = NULL;int pid = 0;char buff_tmp[100]={0};sprintf(buff_tmp, "ps -A | grep %s | wc -l", process);fp = popen(buff_tmp, "r");if(fp){memset(buff_tmp, 0, 100);fgets(buff_tmp, sizeof(buff_tmp)-1, fp);pclose(fp);if(buff_tmp != NULL){pid = atoi(buff_tmp);return pid;}}return -1;}void kill_process(const char *process, int level){FILE *fp = NULL;int pid = 0;char buff_tmp[100]={0}, *p_buff=NULL, *p_buff1=NULL;sprintf(buff_tmp, "ps -A | grep %s", process);fp = popen(buff_tmp, "r");if(fp){memset(buff_tmp, 0, 100);while(fgets(buff_tmp, sizeof(buff_tmp)-1, fp) >0){p_buff = buff_tmp;while(p_buff!=NULL && *p_buff!='\0' && *p_buff==' ') p_buff++;p_buff1 = p_buff;while(p_buff1!=NULL && *p_buff1!='\0' && *p_buff1!=' ') p_buff1++;*p_buff1 = '\0';pid = atoi(p_buff);if( kill(pid, level) == 0)// kill(pid, 15)printf_t("===>杀死后台%s进程(%d)(-%d) success\n",process, pid, level);}pclose(fp);}}void kill_all_process(void){if( process_is_alive("dnsmasq") >= 1){kill_process("dnsmasq", 15);// kill -15usleep(10000);//10ms 后重新检测是否关注成功if( process_is_alive("dnsmasq") >= 1){kill_process("dnsmasq", 9); // 暴力关闭 kill -9}}if( process_is_alive("hostapd") >= 1){kill_process("hostapd", 15);// kill -15sleep(1);//1ms 后重新检测是否关注成功if( process_is_alive("hostapd") >= 1){kill_process("hostapd", 9); // 暴力关闭 kill -9}}}int main(int argc, char *argv[]){// 注册异常处理函数signal( SIGINT, sig_handler );signal( SIGABRT, sig_handler );signal( SIGTERM, sig_handler );signal( SIGKILL, sig_handler );// 1. 启动前杀死现有的 dnsmasq 和 hostapdkill_all_process();usleep(200000);// 2. 启动 hostapdsystem("iw phy0 interface add wlan1 type managed");system("ifconfig wlan1 up");sleep(1);system("ifconfig wlan1 192.168.50.1 netmask 255.255.255.0");system("route add default gw 192.168.50.1 wlan1");printf_t("===>运行命令:dnsmasq -C /data/bin/dnsmasq_softap.conf --interface=wlan1\n");system("dnsmasq -C /data/bin/dnsmasq_softap.conf --interface=wlan1");printf_t("===>运行命令:hostapd /data/bin/hostapd.conf -t -B\n");system("hostapd /data/bin/hostapd.conf -t -B");printf_t("===>开始循环监控dnsmasq 和 hostapd -------\n");while(keep_alive == 1){sleep(1);if( process_is_alive("dnsmasq") == 0){printf_t("===>dnsmasq进程异常,开始关闭hostap\n");break;}if( process_is_alive("hostapd") == 0){printf_t("===>hostapd进程异常,开始关闭hostap\n");break;}}// 3. 恢复初始状态kill_all_process();printf_t("===>route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1\n");system("route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1");printf_t("===>ifconfig wlan1 down\n");system("ifconfig wlan1 down");system("iw dev wlan1 del");printf_t("程序运行结束-------------\n");return 0;}