При огранизации соединения между несколькими компьютерами посредством Wi-Fi часто возникает необходимость оценить качество приёма в различных точках помещения. А если говорить об организации Wi-Fi-моста и/или настройке направленных антенн то необходимо ещё учитывать соседние Wi-Fi-точки.
Полноценное исследование эфира требует достаточно высоких затрат, которые обычно не оправданы. Чаще всего просто нужен сканер эфира, который показывает доступные точки и качество их сигнала. Для смартфонов таких приложений существует великое множество, а вот под Linux кроме громоздкого Kismet ничего подходящего найти не удалось. В итоге оказалось проще написать свой инструмент.
Основная идея при написании своего инструмента заключалась в том, что вся необходимая информация содержится в выводе команды:
iwlist wlan0 scan
Но вывод этой команды не удобен для восприятия. В итоге было решено написать скрипт, который в бесконечном цикле будет запускать эту команду, парсить её вывод и отображать результат. Листинг полученного скрипта:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use Math::Round;
# Если число аргументов не равно единице
if (@ARGV != 1) {
# Печатаем краткую справку
print "Usage:\n";
print " $0 ifname\n\n";
# Завершаем работу
exit;
}
# Будем использовать полученные данные для очистки экрана в дальнейшем
my $clear_screen = `clear`;
# Получаем имя интерфейса
my $ifname = shift;
while (1) {
# Сканируем эфир
my $scan_result = `iwlist $ifname scan`;
# Получаем код ошибки
my $error_code = $?;
# Завершаем работу если что-то не так
exit if $error_code;
# Наскорую руку разбиваем результат сканирования на элементы
my @scan_results_tmp = split /Cell \d+/is, $scan_result;
# Начинаем полноценный разбор
my @scan_results = ();
# Перебираем элементы
foreach my $hotspot_line (@scan_results_tmp) {
# Если нет номера канала значит это мусор, который надо пропустить
next if $hotspot_line !~ m{Channel\:}is;
# Строим элемент
my %hotspot = ();
# Номер канала
$hotspot{'Channel'} = $hotspot_line;
$hotspot{'Channel'} =~ s{^.+Channel\:(\d+).+$}{$1}is;
# SSID
$hotspot{'SSID'} = $hotspot_line;
$hotspot{'SSID'} =~ s{^.+ESSID\:"((.+?)?)".+$}{$1}is;
# Наличие шифрований
$hotspot{'Crypted'} = $hotspot_line;
$hotspot{'Crypted'} =~ s{^.+Encryption key:(\w+?)\s.+$}{$1}is;
# Уровень сигнала. И сразу переводим его в проценты
my $q1 = $hotspot_line;
$q1 =~ s{^.+Quality=(\d+)/\d+.+$}{$1}is;
my $q2 = $hotspot_line;
$q2 =~ s{^.+Quality=\d+/(\d+).+$}{$1}is;
$hotspot{'Quality'} = round($q1 * 100 / $q2);
push @scan_results, \%hotspot;
}
# Сортируем
@scan_results = sort { sprintf("%02d", $a->{Channel}) cmp sprintf("%02d", $b->{Channel}) } @scan_results;
# Очищаем экран
print $clear_screen;
# Печатаем данные
print sprintf(" % 2.2s [% 9.9s] [% 32.32s] [% 7.7s]\n", "Ch", "Quality", "SSID", "Crypt");
print sprintf('%1$s'x61 . "\n", "-");
foreach my $hotspot (@scan_results) {
print sprintf(" %02d [% 8d%%] [% 32.32s] [% 7.7s]\n",
$hotspot->{Channel},
$hotspot->{Quality},
$hotspot->{SSID},
$hotspot->{Crypted});
}
# Делаем паузу
sleep 1;
}
Скрипт принимает один единственный параметр: имя интерфейса, на котором надо осуществлять мониторинг. Например так:
./wifiscan.pl wlan2
Вывод скрипта выглядит примерно так:
Ch [ Quality] [ SSID] [ Crypt] ------------------------------------------------------------- 01 [ 93%] [ Yuldash House] [ on] 02 [ 94%] [ serr_dom] [ on] 04 [ 94%] [ home-of-moose] [ on] 06 [ 93%] [ wifi.tattele.com] [ off] 06 [ 93%] [ KEENETIC 4G] [ on] 06 [ 94%] [ MTS_telefon_2-65-60-30] [ on] 06 [ 94%] [ home.net] [ on] 08 [ 93%] [ YOTA] [ on] 10 [ 93%] [ Estucador] [ on] 10 [ 93%] [ DIR-300NRUB6] [ on]
Если нужны будут какие-то другие параметры то их получение и отображение легко дописать в скрипт. Автор использовал этот скрипт при эксприментах с баночными антеннами и с помощью этого скрипта смог найти нужное направление на необходимую точку.
На этом всё. Приятной работы!

oermolaev 2013-05-20 23:51:05 (#)
:~$ perl ./scanerwifi.pl wlan0 Can't locate Math/Round.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.14.2 /usr/local/share/perl/5.14.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.14 /usr/share/perl/5.14 /usr/local/lib/site_perl .) at ./scanerwifi.pl line 7. BEGIN failed--compilation aborted at ./scanerwifi.pl line 7 (#1) (F) You said to do (or require, or use) a file that couldn't be found. Perl looks for the file in all the locations mentioned in @INC, unless the file name included the full path to the file. Perhaps you need to set the PERL5LIB or PERL5OPT environment variable to say where the extra library is, or maybe the script needs to add the library name to @INC. Or maybe you just misspelled the name of the file. See "require" in perlfunc and lib. Uncaught exception from user code: Can't locate Math/Round.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.14.2 /usr/local/share/perl/5.14.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.14 /usr/share/perl/5.14 /usr/local/lib/site_perl .) at ./scanerwifi.pl line 7. BEGIN failed--compilation aborted at ./scanerwifi.pl line 7. at ./scanerwifi.pl line 7