
- •ОГлавление
- •Введение
- •1 Анализ предметной области
- •Обзор аналогов программных средств
- •1.2 Постановка задачи
- •Разработка программного средства
- •2.1Разработка спецификации требований к пс
- •2.2 Обоснование выбора среды и языка программирования
- •2.3Разработка структурной схемы пс
- •2.4 Разработка схемы-алгоритма пс
- •2.5 Программная реализация пс
- •3 Тестирование пс
- •Руководство пользователя
- •Заключение
- •Список использованных источников
2.4 Разработка схемы-алгоритма пс
Входными данными для работы программы является: IP и номер порта.
Сканер портов будет использован для получения списка открытых или закрытых портов.
Согласно поставленным задачам, в приложении должен быть список IP адресов или доменов, а также диапазон портов подключения. Вся программа будет реализована с использованием оконного режима.
Программа сканирования портов, пытается установить на удаленном компьютере какие порты закрыты, а какие открыты, согласно указанному циклу. Сообщаем об успешных соединениях, а если установить соединение не удается, то неуспешных подключения в графический интерфейс пользователю.
Тк в приложении будет использоваться несколько IP адресов и какой-то диапазон портов – процесс сканирования будет осуществляться через вложенный цикл со счетчиком.
Рис 3. Блок-схема
2.5 Программная реализация пс
Графический интерфейс программы был разработан в стили минимализма и современности.
Рис 4. Графический интерфейс программы
Для хранения данных IP адресов и портов подключения было принято решение создать отдельные файлы. Данные файлы будут создаваться при включении программы в случае их отсутствия и считываться при их наличии.
private void Form1_Load(object sender, EventArgs e)
{
//создает новый если такого нет , либо открывает имеющийся и пишет путем добавления
File.AppendAllText("ips.txt", "");
File.AppendAllText("ports.txt", "");
read_arr_lb1(); // Заполняем массив из файла и обновляем листбокс
read_arr_lb2(); // Заполняем массив из файла и обновляем листбокс
}
Для удобной работы с данными все входные параметры помещаются в отдельный массив данных. Для взаимодействия пользователя с данными заполняются listbox.
void read_arr_lb1()
{
listBox1.Items.Clear();
// Считываем строки в массив
ips = File.ReadAllLines("ips.txt", Encoding.GetEncoding(1251));
// Добавляем каждую строку
foreach (string line in ips)
listBox1.Items.Add(line);
}
Для взаимодействия пользователя с данными были добавлены отдельные кнопки «Добавить» и «Удалить». Данные элементы управления позволяют изменять входные данные для оптимальной работы программы. Алгоритм управления этих кнопок основан на изменении начальных файлов и последующем обновлении данных в пользовательском интерфейсе.
void save_txt_lb1()
{
// Сохранение в текстовый файл после редактирования listbox
TextWriter writer = new StreamWriter("ips.txt");
foreach (var item in listBox1.Items)
writer.WriteLine(item.ToString());
writer.Close();
}
private void button1_Click(object sender, EventArgs e)
{
//IP добавить строчку
//В меню Project выбираем пункт Add Reference и в диалоговом окне ищем элемент Microsoft.VisualBasic.dll
//далее в редакторе кода добавляем: using Microsoft.VisualBasic;
//и это позволит нам непосредственно использовать InputBox, например:
String ip = Microsoft.VisualBasic.Interaction.InputBox("Введите IP или доменное имя:", "Сканер портов", "",
((this.Width + this.Location.X) / 2 ),
((this.Height + this.Location.Y) / 2 ));
if (ip != ""){
listBox1.Items.Add(ip);
}
save_txt_lb1(); // сохраняем;
read_arr_lb1(); // обновляем;
}
При нажатии пользователем кнопки сканировать происходит ряд попыток установки подключений с выводом данных в поле textbox.
foreach (string ip in ips)
{
foreach (string port in pts)
{
richTextBox1.SelectedText = (ip + ":" + port + " - ");
//Соединение с удаленным устройством
//Устанавливаем удаленную конечную точку для сокета
IPHostEntry ipHost = Dns.Resolve(ip);
IPAddress ipAddr = ipHost.AddressList[0];
//преобразуем строку из port в число в переменную p (!ошибка = 0)
int p = 0;
Int32.TryParse(port, out p);
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, p);
//Создаем сокет и соединяем его с удаленной конечной точкой
Socket senders = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Сокращаем время синхронного ожидания делая асинхронное соединение
IAsyncResult result = senders.BeginConnect(ipEndPoint, null, sender);
//Время ожидания ответа 100 миллисекунд
bool success = result.AsyncWaitHandle.WaitOne(100, true);
if (senders.Connected)
{
richTextBox1.SelectedText = ("Socket connected to "+ senders.RemoteEndPoint.ToString() + "\r\n");
senders.Shutdown(SocketShutdown.Both);
senders.EndConnect(result);
senders.Close();
}
else
{
richTextBox1.SelectedText = ("Socket not connected to " + ipEndPoint.ToString() + "\r\n");
senders.Shutdown(SocketShutdown.Both);
senders.Close();
}
}
}
Тк мы пишем программы, которая сканирует порты, мы серверную часть не пишем. Мы заранее предполагаем, что где-то есть уже удаленный компьютер, на котором открыты какие-то порты и просто пытаемся понять какие открыты. Но так как мы заранее не знаем какие открыты, а какие закрыты нам придется перебирать порты по отдельности. Для этого мы будем создавать сокет для каждой пары IP адрес – порт и пытаться соединиться с удаленным сервером.
Сначала создается конечная точка доступа для сокета IPEndPoint, которой передается в качестве параметров IP адрес и некоторый порт. Для получения IP адреса используется класс Dns и его метод Resolve. С помощью данной функции мы можем получить IP адрес удаленного компьютера.
Но у севера может быть не 1 IP адрес, поэтому данная функция возвращает массив IP адресов из которых мы вытаскиваем только [0] элемент
//Устанавливаем удаленную конечную точку для сокета
IPHostEntry ipHost = Dns.Resolve(ip);
IPAddress ipAddr = ipHost.AddressList[0];
Дальше идет процесс непосредственно создания точки подключения
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, p);
Сюда передается IP адрес и порт подключения.
Далее создаем сокет используя класс Soket
Socket senders = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
В качестве параметров передается тип протокола, тип сокета (потоковый сокет), и тип протокола подключения (tcp протокол)
Существует два способа соединения синхронное и асинхронное. При асинхронной попытке соединения мы можем сами задать интервал ожидания ответа. Тк мы будем тестировать большой пакет соединений мы будем использовать именно этот метод.
// Сокращаем время синхронного ожидания делая асинхронное соединение
IAsyncResult result = senders.BeginConnect(ipEndPoint, null, sender);
//Время ожидания ответа 100 миллисекунд
bool success = result.AsyncWaitHandle.WaitOne(100, true);
У сокета sender который мы создали есть функция connect которой мы передаем ту самую точку доступа. Данная функция имеет булево значение в результате чего мы можем сказать было установлено соединение или нет. В результате чего мы выводим сообщение пользователю.
Протокол tcs который мы используем имеет процедуру установления соединения и разрыва соединения. После попытки установки соединения мы освобождаем сокет.
senders.Shutdown(SocketShutdown.Both);
senders.Close();
Данный алгоритм будет повторяться пока не закончиться вложенный цикл со счетчиком, и мы не переберем все варианты подключения.
В конце работы программы пользователю будет выведен список успешных и неуспешных попыток установки соединений согласно списку IP адресов и портов.