Сети_РПЗ - sevikfiletransfer

advertisement
Содержание
Введение .................................................................................................................2
1. Аналитический раздел ....................................................................................3
1.1
Выбор языка программирования.............................................................3
1.2
Создание протокола взаимодействия сервера и клиента....................4
2. Технологический раздел.................................................................................7
2.1
Описание сообщений протокола .............................................................7
2.2
Описание программной реализации клиента ......................................10
2.3
Описание модели протокола .................................................................13
Выводы .................................................................................................................14
Список использованной литературы .................................................................15
1
Введение
В наше время всё большее внимание уделяется взаимодействию компьютеров
внутри локальной сети. Большинство сетей организованы с помощью стека протоколов
TCP/IP, на основе этого стека протоколов и будет работать программа.
Целью курсового проекта является изучение протоколов вычислительных сетей
на практике. Для достижения поставленной цели было выдано задание на курсовой
проект, текст которого приведён ниже.
Задание на курсовой:
 Разработать протокол взаимодействия клиентов и сервера для сети обмена
файлами между клиентами.
 Создать его программную реализацию.
 Создать модель протокола на языке PROMELA и верифицировать ее.
Дополнительно к заданию был приведён перечень указаний, их выполнение и
реализация будет раскрыта в следующих главах.
2
1. Аналитический раздел
1.1 Выбор языка программирования
На выбор языка программирования были наложены серьёзные (с точки зрения
студента) ограничения:
Требования к программной реализации: сервер - используется ФЯП (erlang, ocaml
или иной по выбору, F# нельзя в силу этапа бурного развития), клиенты используется любой свободный кросс-платформенный графический тулкит и
любой
язык,
допускающий
использование
свободного
компилятора/интерпретатора, и не совпадающий с C#/Java/C++/Delphi. При
желании использовать язык без работающих биндинов к графическим тулкитам
допускается интерфейс командной строки. Клиент должен быть переносим на
уровне (как минимум) исходного текста и работать под всеми платформами, для
которых есть используемый им графический тулкит и среда исполнения /
интерпретатор.
Для написания сервера был выбран язык Lisp, поскольку я не принимал участие в
выборе этого языка (в данной работе описано создание клиента) я не буду
останавливаться на этой проблеме, но выбор данного языка важен, так как именно
исходя из особенностей этого языка была построена непосредственная реализация
протокола.
Для написания клиента был выбран язык Nemerle. Приведу характеристику
данного языка, приведённую в Wikipedia:
Nemerle — это компилируемый язык программирования высокого уровня со
статической типизацией и сборкой мусора для .NET. Язык предлагает разработчикам
возможности
использования
функционального,
объектно-ориентированного
и
императивного стиля разработки. Язык обладает простым C-подобным синтаксисом и
мощной системой метапрограммирования.
Ключевым моментом при выборе данного языка стала его простота и понятность, а так
же наличие мощной (хотя и не бесплатной) среды разработки Visual Studio .NET 2005.
Для полной интеграции данного языка в среду разработки необходимо лишь установить
бесплатный плагин, создаваемый сообществом rsdn.ru. Так как компилятор данного
языка входит в стандартную поставку Mono (Nemerle является полноценным, хотя и
молодым .NET языком), проблем с переносимостью программы, несмотря на
использование WinForms не возникло.
3
1.2 Создание протокола взаимодействия сервера и клиента
Я уверен, что нет смысла в рамках данной работы излагать содержание и
особенности работы стека протоколов TCP/IP ввиду того, что эти данные известны как
мне, так и читающему. Поэтому перейду непосредственно к реализации взаимодействия
клиента и сервера. Исходя из указаний к курсовой работе.
Весь процесс взаимодействия клиента и сервера можно описать в Таблице 1:
Таблица 1. Описание сообщений между клиентом и сервером
Тип
Передаваемые
сообщения
серверу данные
Данные,
возвращаемые
Описание
клиенту
Клиент подключается и
передаёт серверу массив
Uid – сервер
Connect
List(file,hash)
возвращает
уникальный id
клиента
записей типа имя файла хеш. Сервер обновляет
данные о клиенте и ставит
его в список активных.
Сервер генерирует
уникальный uid для
клиента
Клиент отключается,
Disconnect
Uid
сервер удаляет данный
клиент из списка активных
Клиент высылает строку
поиска, сервер производит
Search
SearchString
{List(file,hash),error}
поиск и высылает список
найденных файлов, если
клиент не был подключен,
то ошибка
Сервер находит клиентов с
GetFileLocation (Uid, hash)
{(locationIP,port),error}
выбранным файлом и
выбирет из них 1.
Сохраняет информацию,
4
что файл передаётся
с locationIP на
destinationIP. Если это не
первый запрос с
destinationIP, то
предыдущие запросы
помечаются как
неудавшиеся
Сервер проверяет, что
запрос послал клиент с
locationIP и сверяет со
Verify
download
(hash, uid)
{ok,error}
списком запросов, если
всё удачно, то помечает
старт передачи, иначе
ошибка
В случае нормального хода работы по передаче файлов, загрузку 1 файла можно
описать следующим алгоритмом:
1. Человек добавляет файл в клиент, то есть сообщает вручную клиенту
местонахождение файла и тем самым даёт понять, что необходимо сделать
этот файл общим.
2. Клиент сохраняет данные об этом файле (имя и путь к файлу) а также
вычисляет хеш данного файла (уникальный идентификатор). Подробности
реализации каждого шага будут описаны в технологическом разделе.
3. Клиент запускает свой собственный сервер для передачи данных (который
будет передавать данные).
4. Клиент подключается к серверу и сообщает ему список своих файлов в форме
имя-хеш (полный путь к файлу знает только клиент).
5. Сервер добавляет данные о файле в своё хранилище (для дальнейшего
поиска).
6. Клиент составляет поисковый запрос и отправляет его на сервер.
7. Сервер ищет в своём хранилище файлы, удовлетворяющие данному запросу.
8. Сервер передаёт найденные файлы клиенту.
9. Человек (пользователь) выбирает файл, который он хочет загрузить.
5
10. Клиент запрашивает у сервера имя клиента(выступающего в роли сервера)
содержащего этот файл.
11. Сервер передаёт клиенту адрес клиента с файлом.
12. Клиент запрашивает у клиента-сервера (условно можно обозначить его так)
искомый файл.
13. Клиент-сервер запрашивает у сервера подтверждение, что данный клиент
хочет загрузить файл. И получает подтверждение.
14. Клиент-сервер начинает передаёт файл клиенту.
15. Клиент получает необходимый файл.
На каждом шаге может возникнуть ошибка, что приведёт к остановке алгоритма
передачи файла.
6
2. Технологический раздел
В данном разделе перейдём непосредственно к реализации протокола описанного в
аналитическом разделе, а так же к реализации клиента.
2.1 Описание сообщений протокола
На реализацию протокола очень сильно повлиял язык, на котором написан сервер, то
есть язык Lisp. Приведу описание данного языка из Wikipedia:
Лисп (LISP, от англ. LISt Processing — «обработка списков»; современное
написание: Lisp) — семейство языков программирования, программы и данные в
которых представляются системами линейных списков символов. Лисп считается
вторым после Фортрана старейшим высокоуровневым языком программирования. Слово
"lisp" имеет также значение «детский лепет», что не случайно, так как тематика, которая
интересовала создателя лиспа Джон Мак-Карти была тесным образом связана с
исследованиями человеческой речи: Мак-Карти занимался исследованиями в области
искусственного интеллекта и созданный им язык по сию пору является одним из
основных средств моделирования различных аспектов ИИ.
Так как данный язык создавался для моделирования искусственного интеллекта,
очевидно, что его использование не могло не привести к использованию S-выражений.
Все мы привыкли вычислять с числами. Можно вычислять не только с числами ,
можно пойти дальше и проводить вычисления над символами , что и сделал McCarthy,
создавший систему символьного вычисления, основанного на теории рекурсии.
McCarthy создал формализацию для проведения вычисления над символьными
выражениями (S-expression). Почему нам важно символьное вычисление? Давайте
сначала подробнее рассмотрим, что есть S-выражение. S-выражения это способ
представления структур данных в текстовой форме. С помощью S-выражения мы можем
представить
любой
XML-документ.
Например, следующий XML документ
<Student>
<FullName>
<FirstName>
Ruslan
</FirstName>
<LastName>
Gizatullin
7
</LastName>
</FullName>
<University>
MEPhI
</University>
</Student>
Может
быть
преобразован
в
S-выражение:(Student
(FullName
(FirstName
“Ruslan”)(LastName “Gizatulin”))(University “MEPhI”)) и как мы видим запись через Sвыражение немного короче.В действительности S-выражения шире чем XML , так как
свободны от некоторой стандартизации.
Любую структуру данных мы можем записать в виде S-выражения это может
быть список или массив, также это может быть специально размеченный файл или
структурированный текст. В Lisp и код и данные представлены в виде S-выражений, то
есть программа тоже может являться данными и может вычисляться какой-нибудь
функцией вычисления других программ. Таким образом S-выражения это метаязык для
представления различных структур данных. Из этого мы можем видеть ,что Sвыражения это довольно полезная структура и возможность вычислять на S-выражениях
была бы очень нужной. Это и вычисление различных программ записанных в виде Sвыражения и хранение и обработка данных в виде S-выражений.
Теперь, когда стало более понятно, что такое S-выражение становится понятно,
что мы используем XML-подобную штуку для обмена сообщения между клиентом и
сервером. Обмен между клиентами осуществляется на более низком уровне (без S
выражений), это связано со сложностями передавать корректные S-выражения
размерностью в несколько мегабайт, и корректно их обрабатывать.
Перейдём непосредственно к реализации протокола на основе S выражений
(Таблица 2).
Таблица 2. Протокол
Команда
Составляющие
Заголовок
C
Параметры
S-выражения со списком файлов
Ответ
UID - уникальный идентификатор клиента
Пример
Запрос:
C
((:IP "192.168.0.2" :PORT 8080)
((:NAME "Home" :HASH 78654)
(:NAME "Fly" :HASH 78645)
Connect
8
(:NAME "Roses" :HASH 47684)))
Ответ:
1235
Заголовок
D
Параметры
UID - уникальный идентификатор клиента
Пример
Запрос:
D
(:ID 1245)
Заголовок
S
Параметры
Строка поиска
Ответ
Список файлов
Пример
Запрос:
S
(file_name)
Ответ:
((:NAME "fie_name x" :HASH 32132)
(:NAME "file_name y" :HASH 5322))
Заголовок
G
Параметры
(Id Хэш)
Ответ
IP + port или E
Пример
Запрос:
G
(:ID 1312 :HASH 54612)
Ответ:
(:IP "192.168.0.2" :PORT 8080)
Заголовок
V
Параметры
Id клиента, который хочет скачать + Хэщ
Ответ
Y/N
Пример
Запрос:
V
(:ID 78456 :HASH 1354)
Ответ:
Y
Disconnect
Search
Get file location
Verify download
После полного описания модели взаимодействия между клиентом и сервером
перейдём непосредственно к реализации всего этого на Nemerle.
9
2.2 Описание программной реализации клиента
Внутренний протокол для клиентов необходим при непосредственной передаче
файлов, он выбивается из общей концепции использования S-выражений, но это
связанно прежде всего с тем, что клиенты написаны не на языке Lisp и им необходимо
передавать достаточно большие объёмы данных, не обременённых некоторой
метаинформацией.
Протокол можно описать следующим образом:
Запрос: FileRequest(uid, hash)
Ответ: File
Клиент в любом случае получает файл при соединении с сервером. Если клиент не
получил подтверждение у сервера, то он просто отправит пустой файл.
Перейдём к непосредственной реализации всего, что описано выше.
Реализация взаимодействия между клиентами:
Каждый клиент перед подключением к серверу создаёт у себя сокет на
прослушивание (Socket и SocketListener). При подключении к этому сокету создаётся
отдельный поток Thread, это сделано для реализации условия «Клиент должен быть
способен высылать свои файлы сразу нескольким клиентам. Файл передается целиком в
течении одной сессии между клиентами, докачка не требуются». Соответственно
каждый клиент работает с отдельным обслуживающим его потоком и не блокирует
работу остальных. Данная реализация не является единственно возможной, но была
выбрана из-за простоты и очевидности реализации и работы (в отличие, например, от
асинхронных сокетов).
Непосредственными составляющими клиента является следующее:
1) Список файлов, выбранных пользователем для общего доступа.
Хранится следующая информация о файле:
i. Путь к файлу (с именем)
ii. Имя файла (для передачи серверу)
iii. Hash файла – вычисляется довольно своеобразно, пояснение к
функции вычисления hash будет дано ниже.
2) Слушающий сокет – сокет по которому принимаются запросы на
передачу файлов.
3) Данные о сервере. При необходимости Клиент создаёт сокет для связи
с сервером, высылает данные, принимает их и закрывает сокет. Данное
поведение клиента (с постоянным созданием и уничтожением сокетов)
10
полностью связано с особенностью реализации сервера (связь
осуществляется по аналогии с веб-браузерами).
Этапы работы клиента:
1. Пользователь добавляет в список файлы для общего доступа. Файлы добавляются
в ListBox в виде полного пути к файлу.
2. Происходит старт сервера пользователя. На этом этапе у всех добавленных
файлов
определяется
хеш,
с
помощью
стандартной
функции
MD5(MD5CryptoServiceProvider ComputeHash). Однако так как данная программа
является мини курсовым, на мой взгляд нецелесообразно использовать 16
байтный хеш, поэтому я его режу и оставляю от него только 3 байта, преобразую
в int. Также на этом этапе определяется имя файла путём отрезания части адреса
до последнего служебного символа-разделителя (\ или / в зависимости от ФС).
Также на этом этапе запускается многопоточный слушатель порта, который в
дальнейшем
будет
передавать
файл
(запускается
поток
при
каждом
подключении).
3. Подключение к серверу. Из-за особенности реализации сервера как таковое
физическое (на уровне TCP/IP) подключение не удерживается, однако создаётся
логическое подключение. Клиент создаёт подключение, передаёт сигнал
соединения «С», далее передаёт список всех файлов, которые добавил клиент в
формате Имя файла – Хеш, получает от сервера свой уникальный uid и закрывает
соединение. При этом в результате у клиента определён uid, что позволяет ему
производить запросы к серверу и обмениваться файлами с другими клиентами.
4. Поиск файлов на сервере. Данный этап крайне прост: пользователь вводит
поисковый запрос, клиент отправляет сего серверу и получает список файлов,
удовлетворяющих запросу в форме имя файла – хеш и выводит это всё в ListBox.
5. Передача файла. Пользователь выбирает нужный ему файл. Клиент отправляет
хеш этого файла серверу, сервер возвращает ip и порт клиента, раздающего
данный файл(далее сервер-клиент). Клиент пытается создать соединение с этим к
сервер-клиентом, если соединение не успешно, то посылаются повторные
запросы до тех пор, пока не будет найден рабочий клиент, если сервер
возвращает ошибку, то выводится сообщение, что файл не найден и
прекращаются попытки. Если соединение установлено, то клиент посылает свой
uid и хеш нужного файла (клиент посылает эти данные не подряд, а через пустое
сообщение, посланное сервер-клиентом для синхронизации). Сервер-клиент
получает uid и хеш, высылает их серверу для проверки. В случае если сервер не
11
подтвердит авторизацию клиента, то сервер-клиент передаёт клиенту пустой
файл, иначе сервер-клиент ищет в своём списке файлов файл с совпадающим
хешем и начинает передачу. Передача осуществляется порциями по 256 байт из
которых 1 байт (нулевой) представляет собой количество значащих последующих
байт. В случае если количество значащих байт меньше 255, данный пакет данных
является последним (если размер файла кратен 255, то посылается контрольный
пустой пакет). Клиент получает файл и сохраняет его.
12
2.3 Описание модели протокола
Для проверки правильности созданного протокола необходимо его
верифицировать. Формальная верификация — доказательство с помощью формальных
методов правильности или неправильности системы в соответствии с формальным
описанием свойств системы. В данном случае под верификацией будем понимать
проверку исходного протокола на его модели.
В качестве системы, верифицирующей модель, взята система «SPIN», которая
работает с моделями, описанными на языке «PROMELA».
В созданной модели принимают участие следующие сущности:
 Server (сервер) – описывает модель сервера, который отвечает за координацию
действий клиентов;
 Client (клиент) – описывает модель клиентов, которые передают друг другу
файлы в сети.
 Client_id – процесс, генерирующий случайные числа, для присвоения
идентификаторов клиентам;
 Init – корневой процесс инициализирующий начальные данные.
Для взаимодействия этих сущностей в системе присутствует ряд каналов и
переменных:
 In и Out – очереди генератора случайных чисел;
 server_client – канал, моделирующий связи между сервером и клиентом,
используется для передачи уникальных идентификаторов от клиентов к
серверу;
 client-server – канал, моделирующий связи между клиентом и сервером,
используется для передачи сообщений от клиентов серверу;
 verify – канал, моделирующий связь между клиентом и сервером,
используется для проверки перед скачиванием файлов;
 client_input – массив каналов для связи сервера с клиентом для передачи
адресных сообщений клиентам;
 client_output – массив каналов для связи клиентов между собой;
 clients – массив отображающий активных клиентов, подключенных к
серверу;
 downloads – массив отображающий текущие запросы на скачивание
файлов.
Рис. 1 Модель системы
13
Выводы
В результате работы были выполнены следующие задачи:
 Разработан протокол взаимодействия клиентов и сервера, а также клиентов
между собой
 Создана
программная
реализация
клиента
и
сервера,
работающих
по
разработанному протоколу
 Создана модель на языке Promela разработанного протокола и проведена
верификация данной модели
Так как данная курсовая работа позиционируется как большая лабораторная работа, то о
глобальных выводах и каких-либо серьёзных результатах, полученных в ходе данной
работы, говорить не приходится. Однако получен некоторый опыт в разработке
протокола
взаимодействия
приложений,
написанных
на
разных
языках
программирования. Получен опыт написания кроссплатформенных приложений на
экзотических (для нас) языках программирования, в моём случае это молодой язык
Nemerle.
14
Список использованной литературы
1.
Nemerle / Сергей Туленцев, Владислав Чистяков // RSDN Magazine, - #1-2006
(http://www.rsdn.ru/article/nemerle/NemerleIntro.xml)
2.
Википедия. Свободная энциклопедия. (http://ru.wikipedia.org)
3.
Winsock / Дэрин Кили // MSDN Magazine: Русская Редакция, - Август 2005
(http://www.microsoft.com/Rus/Msdn/Magazine/2005/08/Winsock.mspx)
4.
Крищенко В.А., Протоколы вычислительных сетей : курс лекций – МГТУ,
2007.
15
Download