Use saved searches to filter your results more quickly
Cancel Create saved search
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window.
Reload to refresh your session.
Простой симулятор передачи пакетов в локальной сети — семестровая работа к курсу «Сетевое ПО»
Garrus007/NetworkSimulator
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch branches/tags
Branches Tags
Could not load branches
Nothing to show
Could not load tags
Nothing to show
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Cancel Create
- Local
- Codespaces
HTTPS GitHub CLI
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more about the CLI.
Как настроить локальную сеть между компьютерами на Windows 10
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
Latest commit message
Commit time
README.md
Простой симулятор передачи пакетов в локальной сети
Моделирует передачу в локальной сети между устройствами и отображает путь пакета. Создан в рамках курсового проекта по курсу Сети ЭВМ и телекоммуникации
- Создание сети из ПК, хабов, роуетров
- Отправка пакета с ПК на произвольный IP
- Отображение маршрута всех пакетов
- Роутеры с поддержкой статической маршрутизации и PROXY-таблицы
- Визуальное отображение схемы сети
- Анимация передачи пакетов
Основа симулятора выполнена в виде велосипедов, скрепленных синей изолентой с костылями в виде библиотеки, содержащей компоненты Windows Forms.
Hub | Неуправляемый хаб. Рассылает пакеты на все порты, кромп того, с которого он пришел.Имеет произвольное число интерфейсов. |
Server | Роуетр. Осуществляет маршрутизацию. Имеет произвольное число интерфейсов |
PCGroup | Группа ПК. Автоматически создает много ПК с IP в заданном диапазоне |
Gate | Шлюз в интернет. Не реализован адекватно. Работает как ПК, не умеющий отправлять пакет. |
Как настроить локальную сеть между ПК, с помощью роутера на Windows 10, 7
Все они должны располагаться на NetDrawer, который отвечает за отрисовку связей между ними и анимацию пакетов.
Настройка и подготовка костылей
Ниже приведен пример необходимых предварительных настроек
Logger.TextWrited += Logger_TextWrited; PackageManager.NewPackage += PackageManager_NewPackage; AbstractNetworkDevice.SendingDrawDelay = 1000; //Время анимации отправки пакета AbstractNetworkDevice.Drawer = netDrawer1; //Указание объекта, использующегося для анимации пакетов
Logger — отвечает за логгирование прохождения пакетов при помощи событий и в отладочную консоль. PackageManager — хранит все существующие пакеты в системе, информаирует об изменении их состояния и добавлении новых.
Далее необходимо сконфигурировать сеть. После этого необходимо завершить настройку.
netDrawer1.Init(); netDrawer1.UpdateConnections();
Для анимации пакетов необходимо таймеров вызывать метод NetDrawer.UpdatePackages(uint interval)
Компоненты можно расположить в конструкторе форм или создать программно. После этого их надо настроиь и соединить:
Необходимо задать IP и маску подсети. Опционально — задать основной шлюз
admin.SetIP(«197.253.67.10/24»); admin.SetGateway(«197.253.67.1»);
Просто указать количество портов свойством InterfacesCount_U (можно в конструкторе)
Указать список IP и масок интерфейсов, задать таблицу маршрутизации и PROXY-таблицу. Количество интерфейсов — это params , сколько IP перечислите — столько интерфейсов и будет создано
Указывается начальный и конечный IP-адреса диапазона, маска и основной шлюз
pcGroup1.SetPCs(«197.253.85.3», «197.253.85.4», «255.255.255.128», «197.253.85.2»);
Для соединения устройств необходимо установить соответстве между портами.
/// /// Подключает другое устройство к этому устройству /// /// Номер порта, к которому подключается /// Подключаемое устройство /// public void Connect(int port_number, AbstractNetworkDevice device) /// /// Подключает другое устройство к этому устройству /// /// Номер порта, к которму подключается /// Номер порта на другом устройстве, которым оно полкючается /// Подключаемое устройство public void DuplexConnect(int port_number, int other_port_number, AbstractNetworkDevice device)
Connect устанавливает связь устройства с текущим, но не наоборот (такой вот косяк). Чтобы сделать нормальное двустороннее соединение используйте DuplexConnect
PCGroup соединяется путем указания начального порта. Например, если указан начальный порт 1, и подключается группа из 3х ПК, они займут порты 1,2,3.
Пример: Создание группы ПК, подключение ее к хабу, а хаба — к роутеру
Do What The Fuck You Want To Public License
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO.
Марков Алексей, 2016
About
Простой симулятор передачи пакетов в локальной сети — семестровая работа к курсу «Сетевое ПО»
Источник: github.com
Пишем чат для локальной сети, используя C++ Builder. Серверная часть
Несколько месяцев назад понадобилось разработать чат для локальной сети одного офиса, а также выступить с этой программой на научной конференции. Делать его я решил в среде разработки Builder C++ 2006. При написании статьи у меня возникла одна самая главная проблема — полное отсутствие опыта в работе с сетями в билдере, поэтому статью пишу для таких же «программистов», как я. Отмечу сразу, в интернете найдется множество программ, которые, несомненно, будут лучше моей, но задание было не найти программу, а разработать. Статья получится большая, поэтому разделю ее на 2 части — серверную и клиентскую.
Первым делом надо было решить, что это будет за приложение.
Идея
Первое, что пришло в голову — открывать сервер на каждом компьютере, объединяя все компьютеры в кольцо. Сообщение передавать тому клиенту, к которому мы сейчас подключены. Там проверять, нам ли это сообщение, или нет; если нет — то отправлять дальше до тех пор, пока оно не достигнет адресата. Идея не понравилась, главным образом из-за того, что не хотелось, чтобы сообщение проходило через промежуточных пользователей.
Вторая идея мне понравилась. Пусть это будет клиент-серверное приложение. Открываем на одном компьютере сервер, все клиенты подключаются к нему. С клиента отправляем сообщение на сервер, а он уже перенаправляет его адресату. Кстати говоря, второе преимущество этой сетевой архитектуры состоит в том, что каждому клиенту нужно знать только один IP адрес — IP-адрес сервера.
Да и при выходе клиента из сети не придется искать того, к кому он был подключен.
Конечно же, должен присутствовать графический интерфейс, причем такой, чтобы работал по принципу «plug and play» — запустил программу и сразу можно приниматься за переписку. Поэтому в окне программы будет минимум компонентов, даже не будет меню бара.
Как будем пересыпать сообщения? Используя сокеты, а именно стандартные компоненты билдера ClientSocket и ServerSocket, которые будут использоваться в программах клиента и сервера соответственно.
Реализация
Сервер
Программа-сервер рассчитана на одноразовое использование. Т.е. при выходе из нее не сохраняется никакая информация о клиентах, в самой же программе все хранится в массиве. Вообще, сам интерфейс сокетов достаточно интересен.
Для того, чтобы отправить сообщение клиенту, используется команда SendText, принимающая строку сообщения типа AnsiString (где-то я вычитал про длину в 4,3 миллиарда символов, что само собой впечатляет), но чтобы отправить его именно тому, кому нужно, следует указывать номер клиента, а не, например, его IP-адрес. При этом номера клиентам выдаются в том порядке, в каком они подключились.
В .h файле объявлен массив m типа AnsiString, состоящий из 100 элементов. Честно говоря, я не проверил максимально возможное количество подключений к серверу, поэтому будем считать, что оно ограничивается только величиной этого массива. При подключении клиента первым делом отправляется его имя на сервер. Оно вносится в первую свободную ячейку массива, при этом номер элемента и будет являться номером клиента, по которому мы будем отправлять сообщения. Чтобы найти первую пустую ячейку, я написал функцию analog(), которая просто перебирает массив и возвращает номер пустой ячейки.
int TFormMain::analog() < int a; for(int i=0;i> return a; >
В событии OnConnect сервера запускается таймер. Почему-то код исполняемый таймером у меня не получилось выполнять сразу в событии, поэтому таймер выполняет его и сразу же отключается.
По таймеру сервер с помощью цикла отправляет всем клиентам сообщение, в котором в одной строке содержатся все имена подключенных в данный момент клиентов. Зачем это сделано — я расскажу в описании клиента. Список же клиентов формирует функция online() «склеивающая» имена клиентов из массива.
Подключение клиентов
void __fastcall TFormMain::ServerSocketClientConnect(TObject *Sender, TCustomWinSocket *Socket) < Timer1->Enabled=true; > //————————————————————————— void __fastcall TFormMain::Timer1Timer(TObject *Sender) < if(ServerSocket->Socket->ActiveConnections!=0) for(int i=0;iSocket->ActiveConnections;i++) ServerSocket->Socket->Connections[i]->SendText(«8714″+online()); Timer1->Enabled=false; > //—————————————————————————
AnsiString TFormMain::online() < char str[500]=»»; for(int i=0;ireturn str; >
Однако, все самое интересное происходит в событии сервера OnRead. Структура каждого сообщения, посылаемого как клиентом, так и сервером, обязательно содержит в начале 4 цифры. Это случайная комбинация цифр, придуманная мной для того, чтобы сервер и клиент могли различать сообщения, необходимые для «авторизации», или же сообщения, содержащие в себе текст для пересылки.
Всего клиент может посылать серверу 4 типа сообщений. Сообщения с кодом 6141 посылаются серверу при первом подключении, они также сообщают серверу имя нового клиента, а сервер вносит его в массив и выводит в Memo (декоративном элементе, созданном просто чтобы знать, кто в данный момент подключен). Сообщение с кодами 5280 и 5487 потеряли свою актуальность, но почему то не были убраны мной из кода сервера. Сообщения с кодом 3988 самые важные. Это и есть сообщения содержащие в себе всю информацию для обмена сообщениями между пользователями. Структура такого сообщения:
Вообще, из каждого полученного сообщения сервер первым делом выделяет код методом SubString, от этом в дальнейшем зависят его дальнейшие действия. Из этого же сообщения сервер также выделяет меня отправителя и получателя, а также текст сообщения. Затем формируется сообщение вида 7788:. Оно отправляется клиенту-получателю. Как, если известно только его номер а не имя?
Для этого написана функция numer(AnsiString), принимающая имя, перебирающая массив и возвращающая номер ячейки в котором это имя находится.
Обработка входящих сообщений
void __fastcall TFormMain::ServerSocketClientRead(TObject *Sender, TCustomWinSocket *Socket) < message=Socket->ReceiveText(); time=Now().CurrentDateTime(); if(message.SubString(1,4).AnsiCompare(«6141»)==0) < m[analog()]=message.SubString(5,message.Length()); ListBox1->Clear(); for(int i=0;iSocket->ActiveConnections;i++) < ListBox1->Items->Add(m[i]); > > else if(message.SubString(1,4).AnsiCompare(«5487»)==0) < for(int i=0;iSocket->ActiveConnections;i++) ServerSocket->Socket->Connections[i]->SendText(«8714″+online()); > else if(message.SubString(1,4).AnsiCompare(«3988»)==0) < nametowho=message.SubString(message.AnsiPos(‘Й’)+1,message.AnsiPos(‘:’)-message.AnsiPos(‘Й’)-1); name=message.SubString(5,message.AnsiPos(‘Й’)-5); if(nametowho.IsEmpty()==false (message.SubString(message.AnsiPos(‘:’)+1,message.Length()).IsEmpty())==false) < ServerSocket->Socket->Connections[numer(nametowho)]->SendText(«7788″+name+»:»+message.SubString(message.AnsiPos(‘:’)+1,message.Length())); ofstream fout(«chat.txt»,ios::app); fout > else if(message.SubString(1,4).AnsiCompare(«5280»)==0) < ServerSocket->Socket->Connections[numer(message.SubString(message.Pos(‘#’)+1,message.Pos(‘%’)-message.Pos(‘#’)-1))]->SendText( «6734»+message.SubString(message.Pos(‘%’)+1,message.Length()-message.Pos(‘%’))); > >
При отключении какого либо из клиента массив очищается, клиентам опять отправляется запрос на получение имени (при этом имена отправляются и принимаются в том порядке в каком подключены клиенты) и массив заново заполняется. Также клиентам сразу же отправляется новый список клиентов, находящихся в сети. Делается это также внутри таймера. Сообщения с запросом имени отправляются клиентам с помощью цикла:
void __fastcall TFormMain::ServerSocketClientDisconnect(TObject *Sender, TCustomWinSocket *Socket) < if(ServerSocket->Socket->ActiveConnections!=0) < for(int i=0;iTestNames(); Timer1->Enabled=true; > >
Графическая часть
Внешний вид окна сервера:
Изначально у меня не было в планах выводить какую либо информацию в окне сервера, но в итоге решил выводить самое важное: IP-адрес сервера, количество активных подключений, порт сервера, имя компьютера ка котором он запущен (почему-то всегда «1», исправить я это пока не смог), и список имен подключенных клиентов. Сервер сворачивается в область уведомлений. Реализовано это несколькими функциями, подробно разбирать я их не буду. Также на сервере полностью отключен отлов ошибок (которых вообще за 2 недели непрерывной работы не возникало, но мало ли, все таки полностью парализуется работа сети).
Графическая часть
void __fastcall TFormMain::DrawItem(TMessage IconDrawItem((LPDRAWITEMSTRUCT)Msg.LParam); TForm::Dispatch( >//————————————————————————— void __fastcall TFormMain::MyNotify(TMessage POINT MousePos; switch(Msg.LParam) < case WM_RBUTTONUP: if (GetCursorPos( PopupMenu1->PopupComponent = FormMain; SetForegroundWindow(Handle); PopupMenu1->Popup(MousePos.x, MousePos.y); > else Show(); break; case WM_LBUTTONDBLCLK: Show(); break; default: break; > TForm::Dispatch( > //————————————————————————— //————————————————————————— bool __fastcall TFormMain::TrayMessage(DWORD dwMessage) < NOTIFYICONDATA tnd; PSTR pszTip; pszTip = TipText(); tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = Handle; tnd.uID = IDC_MYICON; tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; tnd.uCallbackMessage = MYWM_NOTIFY; if (dwMessage == NIM_MODIFY) < tnd.hIcon = (HICON)IconHandle(); if (pszTip) lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip)); else tnd.szTip[0] = ‘