首页 > 技术文章 > 【原创】修改WIFI保持连接脚本

M-Bing 2014-04-05 21:52 原文

【原创】修改WIFI保持连接脚本

  项目中用到wifi,由于无线网络的不稳定性,可能会造成wifi的掉线,这就需要在程序中判断网络的是否联通,并且能在断线后继续搜寻无线网络并重新连接。

并且因为wifi连接有许多现成的工具,所以在这里就利用shell脚本来实现此功能。

  本篇博客主要是记录我修改此脚本到当前项目的记录,包含shell脚本的一些用法和wifi连接工具的用法:

一、初始化函数init_var

init_var() {
	#until [ -d $SYSFS ] ; do sleep 1; done
	#find the first useable wifi card
	local wifi_dev               #定义局部变量wifi_dev
	wifi_dev=$(iwconfig 2>&1  | grep -v "no wireless" ) #查看当前设备有的无线设备,grep -v 指的是去除no wireless这一行
	while true; do                #无限循环
		if [ -z "$wifi_dev" ]; then #判断wifi_dev字符串是否为空 是空则执行下面的命令
			sleep 3
			wifi_dev=$(iwconfig 2>&1  | grep -v "no wireless" )
		else                   #不为空  获取当前wifi设备名
			IFACE=$(iwconfig 2>&1 | grep -v -n "no wireless" | awk '{print $1}' | awk -F: '{print $2}' | grep 0)
			break
		fi
	done

	# support only pc run dhclient
	which dhclient     #判断 dhclient工具是否存在
	if [ $? -ne 0 ]; then
		RUN_PC=0
	else
		RUN_PC=1
	fi

	if [ "$RUN_PC" = "0" ] ; then
		DHCP_CLIENT=udhcpc
		DHCP_CLIENT_OPT=" -i "
		PING_KEYWORD=round-trip
		DHCP_WAIT_TIMES=5
	else
		DHCP_CLIENT=dhclient
		PING_KEYWORD=rtt
		DHCP_WAIT_TIMES=5
		rm -f /var/lib/dhclient/dhclient.leases
	fi

	tmpfsloc=$(mount | grep tmpfs | awk '{print $3}' | head -n 1)
	loc=${tmpfsloc:-/dev}
	WPA_CONFIGFILE=$loc/wpa_supplicant.conf


	echo dhcp client app is $DHCP_CLIENT    #打印相关信息
	echo ping key words is $PING_KEYWORD
	echo ESSID is $CONF_ESSID
	echo interface is $IFACE
	echo run mode is $RUN_MODE
}

  

二、主循环程序如下

while [ -d $SYSFS ] ; do
	network_connect

	if [ $? -ne 0 ]; then
		echo --INFO--:network is disconnected? try to reconnect
		ifconfig $IFACE 0.0.0.0
		setup_wifi
	fi

	sleep $CHECK_PERIOD

done

  network_connect是一个函数,其主要功能是判断网络是否联通,然后是一个判断语句,如过network_connect不成功(返回的不是0),

则执行setup_wifi函数,此函数的主要功能重新设置并连接wifi。如果网络联通则睡眠CHECK_PERIOD秒后再重新判断连接是否正常。

三、判断网络是否连接函数network_connect

network_connect() {
	#get ip first
	ifconfig $IFACE | grep -q "inet addr"  #判断当前是否有IP地址
	if [ $? -ne 0 ]; then
		echo can\'t find IP 
		return 1
	fi	


	#get default gateway
	route | grep -q default | awk '{print $2}'  #获取当前连接路由的网关地址
	if [ $? -ne 0 ]; then
		echo can\'t get default gatway
		return 1
	else
		SERVER_IP=$(route | grep default | awk '{print $2}')
	fi

	if [ -z $SERVER_IP ]; then
		echo did not get server ip by route, server_ip=$SERVER_IP
		return 1
	fi

	if ! ping -c $PING_RETRY_COUNT -q $SERVER_IP | grep -q $PING_KEYWORD; then  #利用ping命令查看网络是否联通
		echo ping $SERVER_IP failed
		return 1
	
	fi
}

  

 四、加入路由函数setup_wifi

setup_wifi() {

	ifconfig $IFACE down
	ifconfig $IFACE up        #将无线网卡重启
	echo start wireless scanning

	local count=0
	until [ $count -ge 3 ]  ;
	do
		get_auth_mode          #获取AP加密方式等信息,如果未找到指定AP,将会返回1
		if [ $? -ne 0 ]; then
			echo "AP $CONF_ESSID not found, sleeping...";
			sleep 5;
			let 'count=count+1';              
		else
			break                         #找到后返回
		fi
	done
	
	#scan ok
	if [ $count -lt 3 ] ; then
		if [ "$RUN_MODE" = "debug" ] ; then
			set_wifi_mode
			return 0
		fi
	fi

	local index
	if [ $count -lt 3 ] ; then
		echo APs list: ${mac_ary[*]}  #打印获取后的同名AP列表
		echo signal list: ${siglevel_ary[*]}
		echo sort index: ${sort_ary[*]}
		for(( i = 1; i <= $AP_COUNT; i++)) #下面的功能是找到最大信号的那个AP  并加入到其中,如果加入不成功,依次加次强的那个
		do
			index=${sort_ary[i]} #the first is most signal
			bssid=${mac_ary[index]}
			echo try AP: ${ssid_name_ary[index]}  $bssid
			set_wifi_mode                      #该函数是设置wifi模式,并调用WPA_CONFIGFILE工具,连接AP
			if [ $? -ne 0 ]; then
				echo association with $bssid failed
			else
				echo association with $bssid OK
				break
			fi
		done
	fi
}

五、搜寻指定AP,并获得AP加密方式函数get_auth_mode

get_auth_mode() {
	local grep_expr found
	local ad_hoc_grep

	iwlist_log=$(iwlist $IFACE scanning)  #扫描所有AP信息
	grep_expr="ESSID:\"$CONF_ESSID\""
	ad_hoc_grep="Mode:$ADHOC_MODE"

	

	local start_line
	start_line=$(printf "%s \n" "$iwlist_log" | grep -n $grep_expr | awk -F: '{print $1}')#找到符合指定AP名的行
	AP_COUNT=$(echo $start_line | wc -w)   #判断有几行
	echo total ap number is $AP_COUNT    #有几行就说明有几个同名AP
	# if AP_COUNT > 0
	if [ $AP_COUNT -gt 0 ]; then   #如果大于0就说明找到指定AP
		found=true
	else
		return 1
	fi
	start_line=$(printf "%s \n" "$iwlist_log" | grep  $grep_expr -B 2 | grep Cell | awk '{print $2}') #获得全部指定AP名的Cell

	local i cell
	for((i = 1; i <= $AP_COUNT; i++ )) #将每个同名AP分离出来  并存到数组内
	do
		cell=$(echo $start_line | awk '{print $('$i')}')
		get_ssid_str $cell  $i                   #根据Cell编号,获取每个同名AP的加密信息
	done

	#suppose all APs used the same encryption settings, for supporting roaming
	ssid_str=${ssid_str_ary[1]}   #数组内第一个AP就是同名AP中信号最强的

	Encryption=$(printf "%s \n" "$ssid_str" | grep Encryption | awk -F: '{print $2}')#下面是获取其加密类型
	Auth_Suite=$(printf "%s \n" "$ssid_str" | grep "Authentication Suites" | awk '{print $5}')
	Group_cipher=$(printf "%s \n" "$ssid_str" | grep "Group Cipher" | head -n 1 | awk '{print $4}')
	echo --INFO--:Group_cipher=$Group_cipher
	#Pair_ciper=$(printf "%s \n" "$ssid_str" | grep "Pairwise Ciphers" | awk '{print $5}')	

	if [ "$Auth_Suite" = "802.1X" ]; then #转化为wpa_supplicant对应的加密类型
		#Auth_Suite is PSK or 802.1X
		echo didn\'t support WPA Enterprise, Authentication Suites is $Auth_Suite
		return 1
	fi

	if [ "$Group_cipher" = "CCMP" -o "$Group_cipher" = "TKIP" ]; then
		EncrypType=$Group_cipher
	fi

	AuthMode=WEP
	if [ "$Encryption" = "off"  ]; then
		AuthMode=
		return 0
	fi

	if  echo $ssid_str | grep -q "802.11i/WPA2"  ; then
		AuthMode=WPA2
		return 0
	fi
	
	if  echo $ssid_str | grep -q "WPA Version" ; then
		AuthMode=WPA
		return 0
	fi
	
	return 0
	
}

六、加入AP函数set_wifi_mode

set_wifi_mode() {

	echo auth mode is $AuthMode

	if [ "$RUN_MODE" = "debug" ] ; then
		killall $DHCP_CLIENT
		killall wpa_supplicant
		sleep 5
		ifconfig $IFACE up
		sleep 2
		#iwconfig $IFACE key off
		iwconfig $IFACE mode $ADHOC_MODE
		sleep 2
		iwconfig $IFACE essid "$DEBUG_CONF_ESSID"
		ifconfig $IFACE $DEBUG_FIX_IP
		return
	fi

	if [ "$AuthMode" = "WEP" ] ; then #判断加密类型  生成wpa_supplicant所需的.conf文件
		local pref
		if [ "$WEP_KEY_TYPE" = "char" ] ; then
			pref="s:"
		fi
		iwconfig $IFACE key open $pref$PASSWORD  [$WEP_KEYINDEX] 
		iwconfig $IFACE essid "$CONF_ESSID"
		echo try "open" Authentication mode
		sleep 5
		name=$(iwconfig $IFACE | head -1 | awk -F\" '{print $2}')
		
		if [ "$name" != "$CONF_ESSID" ];then
			echo "open" Authentication mode failed, try shard mode
			iwconfig $IFACE key restricted $pref$PASSWORD  [$WEP_KEYINDEX]
			iwconfig $IFACE essid "$CONF_ESSID"
		fi
	
	elif [ "$AuthMode" = "WPA2" -o "$AuthMode" = "WPA" ] ; then
		killall wpa_supplicant
		write_wpa_config                       #此函数生产.conf文件
		sleep 2
		ifconfig $IFACE up
		sleep 2
		wpa_supplicant -i $IFACE -B -c $WPA_CONFIGFILE  #利用wpa_supplicant工具加AP
		#wait wpa config, associ
		sleep 10
	else
		iwconfig $IFACE key off
		iwconfig $IFACE essid "$CONF_ESSID"
	fi

	if [ "$AuthMode" != "WPA2" -a "$AuthMode" != "WPA" ]; then
		if [ "$SET_MODE" = "yes" ] ; then
			if [ "$RUN_MODE" = "debug" ] ; then
				killall $DHCP_CLIENT
				killall wpa_supplicant
				sleep 2
				ifconfig $IFACE up
				sleep 2
			fi
			iwconfig $IFACE mode $ADHOC_MODE
		else
			iwconfig $IFACE mode $DEFAULT_MODE
		fi
	fi

	#check if successed  #判断是否加入成功
	ssidname=$(iwconfig $IFACE | grep $IFACE | awk -F: '{print $2}' | awk '{print $1}')
	cur_bssid=$(iwconfig $IFACE | grep "Access Point:" | awk  '{print $6}')
	cur_mode=$(iwconfig $IFACE | grep Mode | awk -F: '{print $2}' | awk '{print $1}')

	echo $ssidname $cur_bssid $cur_mode
	if [ "$ssidname" != "\"$CONF_ESSID\"" -o "$bssid" != "$cur_bssid" \
			-o "$cur_mode" != "$DEFAULT_MODE" ]; then
		#fail
		return 1
	fi

	if [ -z $FIX_IP ] ; then
		dhcp_pc
		dhcp_ok=$(ifconfig $IFACE  | grep "inet addr" | awk '{print $1}')
		if [ -z $dhcp_ok ]; then
			return 1
		fi 
	else
		ifconfig $IFACE $FIX_IP
	fi

	if [ "$RUN_MODE" != "debug" ] ; then
		route add default gateway $SERVER_IP $IFACE
	fi
	return 0

}

 七、生产wpa_supplicant所需.conf文件函数

write_wpa_config() {
	#init wpa_supplicant.conf file
	if [ -f $WPA_CONFIGFILE ]; then
		rm -f $WPA_CONFIGFILE
	fi

	cat >$WPA_CONFIGFILE<<-EOF
	ctrl_interface=/var/run/wpa_supplicant
	
	network={
			ssid="$CONF_ESSID"
			bssid=$bssid
			scan_ssid=1
			key_mgmt=WPA-PSK
			proto=$AuthMode
			pairwise=$EncrypType
			group=$EncrypType
			psk="$PASSWORD"

	}
	EOF
}

  至此,此脚本全部结束,这个脚本的最好处在于支持wifi信号的漫游。

 

  

  

推荐阅读