Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка_лаб_ОТТ.doc
Скачиваний:
32
Добавлен:
23.11.2019
Размер:
13.25 Mб
Скачать

Лабораторная работа № 4 передача данных на основе протокола tcp/ip

ЦЕЛЬ РАБОТЫ

Целью работы является изучение основ передачи дискретной информации в компьютерных сетях, а также разработка простейшего ПО для ПЭВМ, выполняющего обмен данными в сетях на основе протокола TCP/IP.

ЗАДАНИЕ К РАБОТЕ

1. Изучить принципы организации компьютерных сетей на основе протокола TCP/IP;

2. В программной среде C++ Builder 6 разработать ПО, осуществляющее обмен данными по протоколу TCP;

3. Произвести передачу и прием данных (файлов различного формата) с помощью разработанного ПО.

4. Сделать выводы по результатам работы.

ПОЯСНЕНИЯ К РАБОТЕ

В настоящее время очень часто возникает задача разработки ПО, осуществляющего управление некоторыми удаленными (т. е. находящимися на значительном расстоянии от ПЭВМ) устройствами. В связи с развитием и распространением сетей передачи данных наиболее удобным является использование технологий локальных и глобальных сетей и в частности технологии Ethernet [1, 2]. Для организации межсетевого взаимодействия, как правило используется протокол (набор протоколов) TCP/IP.

Протокол TCP/IP представляет собой совокупность правил, на базе которых строится связь (обмен информацией) между компьютерами в сети Интернет. Аббревиатура TCP/IP расшифровывается как «Протокол управления передачей/межсетевой протокол» (transmission control protocol/internet protocol) [1]. Этот протокол организует взаимодействие программ, работающих на разных компьютерах, на разных платформах и языках. При этом организуемый обмен данными между компьютерами, входящими в сеть является надежным и имеет высокую достоверность.

ПЭВМ в составе сети обмениваются информацией. Точнее обмен информацией производит ПО, установленное на компьютерах. Как правило взаимодействие между программами на ПЭВМ в составе сети осуществляется по схеме «клиент-сервер» [1, 3]. Клиент запрашивает какую-либо информацию (страницу сайта, файл и т. д.) у сервера, а сервер принимает запрос, обрабатывает его и отправляет результат клиенту [1].

Протокол TCP/IP включает в себя несколько протоколов различного уровня. При этом уровни протоколов соответствуют уровням модели взаимодействия открытых систем OSI [1]. Двумя основными протоколами транспортного уровня являются надежный протокол управления передачей данных TCP (Transmission Control Protocol) и быстрый протокол UDP (User Datagram Protocol). TCP реализует сетевое взаимодействие с установлением логического (виртуального) соединения, а UDP не требует поддерживания соединения с удаленным компьютером [1]. При использовании протокола UDP получателю не гарантируется доставка пакета передаваемых данных.

Протокол транспортного уровня (например, TCP) взаимодействует с пользовательским ПО, а также с протоколом, обеспечивающим «низкоуровневые» функции (маршрутизацию, адресацию пакетов данных и т. д.). В качестве «низкоуровневого» протокола, как правило, используется протокол IP [1].

В операционной системе реализация протокола TCP представляет собой отдельный системный модуль (драйвер), через который, как правило, проходят все вызовы функций протокола. Интерфейс между пользовательским ПО и TCP представляет собой библиотеку системных вызовов. Так, например, пользовательское ПО при взаимодействии с модулем TCP может открывать или закрывать соединение, отправлять или принимать данные, получать статус соединения и т. д. Эти вызовы подобны любым другим вызовам функций операционной системы из пользовательского ПО, таким как открытие, чтение или запись файла и др.

Схема работы пользовательского ПО с TCP, в общих чертах, состоит в следующем. Для передачи данных пользовательскому ПО необходимо вызвать соответствующую функцию TCP, с указанием буфера передаваемых данных. TCP упаковывает эти данные в сегменты [1], т. е. разбивает их на байтовые посылки определенной длины, добавляет к посылкам заголовок и т. д. После формирования сегментов TCP вызывает функцию передачи протокола более низкого уровня, например протокола IP. На приемном конце, TCP группирует поступившие от протокола низкого уровня данные в буфер, проверяет целостность данных, передает данные пользовательскому ПО и уведомляет отправителя об их получении.

Для идентификации компьютеров в сети технология TCP/IP имеет систему глобальной адресации [1]. Каждый компьютер (или другое устройство) в рамках сети Интернет имеет уникальный адрес, который называется IP-адресом (Internet Pointer), например 192.168.0.55. IP-адрес состоит из четырех однобайтовых чисел, разделенных точкой. На каждом компьютере может быть размещено различное ПО, одновременно осуществляющее обмен информацией. Поэтому каждой выполняемой программе присваивается определенный уникальный номер, именуемый номером порта.

Особый смысл имеет IP-адрес, первый байт которого равен 127. Он используется для тестирования программ и взаимодействия процессов в пределах одной машины. Когда программа посылает данные по IP-адресу 127.x.x.x, эти данные не передаются по сети, а возвращаются как только что принятые. Поэтому в IP-сети компьютерам запрещается присваивать IP-адреса, начинающиеся со 127.

Сервер имеет фиксированный IP-адрес и фиксированный номер порта. Номера портов клиента не фиксированы. Они назначаются операционной системой динамически. Фиксированные серверные порты как правило имеют номера до 1024, а клиентские начинаются после 1024.

ХОД РАБОТЫ

Для выполнения лабораторной работы используются два ПЭВМ с операционной системой Windows XP/7, подключенных к Интернету (локальной сети). Студентами разрабатывается ПО, состоящее из двух оконных приложений. Первое приложение выполняет функции сервера (размещается на первой ПЭВМ), второе – функции клиента (устанавливается на второй ПЭВМ). Таким образом, в ходе лабораторной работы ставится задача разработать простейшие приложения клиент/сервер, передающие друг другу текстовые сообщения, а также осуществляющие файловый обмен между ПЭВМ.

Разрабатываемые приложения должны использовать простой протокол файлового обмена. В простейшем случае протокол файлового обмена должен предусматривать различение байтов текстовой информации и байтов файла. Чтобы различать текстовые и файловые посылки начало файловой посылки может сопровождаться передачей текстовой строки вида [4]

file#filename#filesize# ,

где file - маркер начала файла, filename – имя файла (например «Transmit_file.txt»), filesize – размер файла в байтах. Байты, передаваемые после рассмотренной строки – это байты файла (количество байтов файла равно значению filesize).

1. Собрать рабочее место для выполнения лабораторной работы согласно рис. 4.1 (на ПЭВМ1 будет размещено приложение, выполняющее функции сервера, на ПЭВМ2 – приложение, играющее роль клиента);

Рис. 4.1

Указания п. 2-4 выполнить на каждой из ПЭВМ, входящих в состав рабочего места.

2. Запустить программную среду C++ Builder 6, создать новый проект (тип проекта - Application) [3];

3. Cохранить проект на жестком диске ПЭВМ используя пункт Save All меню File (рис. 4.2);

Рис. 4.2

4. Разместить на форме один компонент Memo, три компонента Button, один компонент OpenDialog, один компонент SaveDialog, три компонента Edit [5]. Далее будем использовать следующие имена компонентов: Memo1, Button1, Button2, Button3, OpenDialog1, SaveDialog1, Edit1, Edit2, Edit3 (примерный вид окна после размещения указанных компонентов показан на рис. 4.3);

Рис. 4.3

5. На ПЭВМ1 задать свойству Caption компонента Button1 значение «ЗАПУСК СЕРВЕРА», задать свойству Caption компонента Button2 значение «ПЕРЕДАТЬ ТЕКСТ», задать свойству Caption компонента Button3 значение «ПЕРЕДАТЬ ФАЙЛ»;

6. На ПЭВМ1 задать свойству Text компонента Edit1 значение IP-адреса ПЭВМ1 (например «192.168.1.101»). IP-адрес компьютера можно узнать открыв окно панели управления операционной системы Windows 7/XP;

7. На ПЭВМ1 задать свойству Text компонента Edit2 значение номера порта (например «1001»);

8. На ПЭВМ1 разместить на форме один компонент ServerSocket. Далее будем использовать для этого компонента имя ServerSocket1 (примерный вид окна после выполнения п. 5-8 показан на рис. 4.4);

Рис. 4.4

9. На ПЭВМ1 задать свойству ServerType компонента ServerSocket1 значение «stNonBlocking»;

10. На ПЭВМ1 в обработчике события OnClick компонента Button1 разместить следующий программный код:

ServerSocket1->Port=StrToInt(Edit2->Text);

// Запуск сервера

ServerSocket1->Active = true;

ServerSocket1->Open();

Memo1->Lines->Add("Создан сервер.");

11. На ПЭВМ1 в обработчике события OnAccept компонента ServerSocket1 разместить следующий программный код:

Memo1->Lines->Add("К Вам подключились.");

12. На ПЭВМ1 в обработчике события OnClientError компонента ServerSocket1 разместить следующий программный код:

ErrorCode = 0;

ShowMessage("Client Error");

13. На ПЭВМ1 в обработчике события OnClick компонента Button2 разместить следующий программный код:

ServerSocket1->Socket->Connections[0]->SendText(Edit3->Text);

Memo1->Lines->Add("Отправлен текст: " + Edit3->Text);

14. На ПЭВМ1 в обработчике события OnClientRead компонента ServerSocket1 разместить следующий программный код:

AnsiString Rtext ; // текст, который посылает клиент

Rtext=ServerSocket1->Socket->Connections[0]->ReceiveText();

Memo1->Lines->Add("Принят текст: " + Rtext);

15. На ПЭВМ2 задать свойству Caption компонента Button1 значение «ПОДКЛЮЧИТЬСЯ К СЕРВЕРУ», задать свойству Caption компонента Button2 значение «ПЕРЕДАТЬ ТЕКСТ», задать свойству Caption компонента Button3 значение «ПЕРЕДАТЬ ФАЙЛ»;

16. На ПЭВМ2 задать свойству Text компонента Edit1 значение IP-адреса ПЭВМ1 (т. е. значение IP-адреса сервера к которому клиент должен подключиться, например «192.168.1.101»);

17. На ПЭВМ2 задать свойству Text компонента Edit2 значение номера порта (номер порта должен быть тот же, что и у сервера, например «1001»);

18. На ПЭВМ2 разместить на форме один компонент ClientSocket. Далее будем использовать для этого компонента имя ClientSocket1 (примерный вид окна после выполнения п. 12-15 показан на рис. 4.5);

Рис. 4.5

19. На ПЭВМ2 задать свойству ClientType компонента ClientSocket1 значение «ctNonBlocking»;

20. На ПЭВМ2 в обработчике события OnClick компонента Button1 разместить следующий программный код:

Memo1->Lines->Add("Подключение к указанному серверу...");

ClientSocket1->Address=Edit1->Text;

ClientSocket1->Port=StrToInt(Edit2->Text);

// подключаемся к серверу

ClientSocket1->Open() ;

21. На ПЭВМ2 в обработчике события OnConnect компонента ClientSocket1 разместить следующий программный код:

Memo1->Lines->Add("Произведено подключение к серверу.");

22. На ПЭВМ2 в обработчике события OnError компонента ClientSocket1 разместить следующий программный код:

ErrorCode=0;

ShowMessage("Client Error");

23. На ПЭВМ2 в обработчике события OnClick компонента Button2 разместить следующий программный код:

Form1->ClientSocket1->Socket->SendText(Edit3->Text);

Memo1->Lines->Add("Отправлена строка: " + Edit3->Text);

24. На ПЭВМ2 в обработчике события OnRead компонента ClientSocket1 разместить следующий программный код:

AnsiString Rtext ; // текст, который посылает сервер

Rtext = ClientSocket1->Socket->ReceiveText() ;

Memo1->Lines->Add("Принят текст :" + Rtext);

Указания п. 25 выполнить на каждой из ПЭВМ, входящих в состав рабочего места.

25. Откомпилировать и выполнить разработанное ПО (примерный вид экранных форм приложений на ПЭВМ1 и ПЭВМ2 показан на рис. 4.6 и 4.7 соответственно);

Рис. 4.6 Рис. 4.7

26. На ПЭВМ1 в окне экранной формы нажать кнопку «ЗАПУСК СЕРВЕРА». В текстовом поле Memo1 экранной формы должен появиться текст «Создан сервер.»;

27. На ПЭВМ2 в окне экранной формы нажать кнопку «ПОДКЛЮЧИТЬСЯ К СЕРВЕРУ». В текстовом поле Memo1 экранной формы должен появиться текст «Произведено подключение к серверу.»;

28. На ПЭВМ1 в окне экранной формы в текстовом поле Edit3 написать любой текст и нажать кнопку «ПЕРЕДАТЬ ТЕКСТ». Убедиться, что напечатанный текст совпадает с текстом, принятым ПЭВМ2;

29. На ПЭВМ2 в окне экранной формы в текстовом поле Edit3 написать любой текст и нажать кнопку «ПЕРЕДАТЬ ТЕКСТ». Убедиться, что напечатанный текст совпадает с текстом, принятым ПЭВМ1;

30. На ПЭВМ1 и ПЭВМ2 закрыть экранные формы;

31. На ПЭВМ1 и ПЭВМ2 в модуле формы разместить следующий программный код:

// создаем поток под принимаемый файл

TMemoryStream *MS = new TMemoryStream ;

// ф-я записи получаемой информации в поток

void Write_1(AnsiString Text);

// размер принимаемого файла

int Size_1=0;

// передаем ли мы на данный момент файл

bool Receive;

32. На ПЭВМ1 в обработчике события OnClick компонента Button3 разместить следующий программный код:

void *P; // указатель на файл

int Size_2=0; // размер передаваемого файла

if(OpenDialog1->Execute())

{

// выбираем файл

MS->LoadFromFile(OpenDialog1->FileName);

Memo1->Lines->Add("Файл загружен в поток...");

}

// отправляем заголовок

ServerSocket1->Socket->Connections[0]->SendText( "file#" + OpenDialog1->FileName + "#" + IntToStr( MS->Size ) + "#" );

Memo1->Lines->Add ("Отправлен заголовок");

MS->Position=0;// Устанавливаем поток в начальную позицию;

P=MS->Memory; // присваиваем указателю поток файла

//отправляем буфер клиенту;

Size_2=ServerSocket1->Socket->Connections[0]

->SendBuf(P, MS->Size);

Memo1->Lines->Add("Отправлено: " + IntToStr(Size_2) +

" из " + IntToStr(MS->Size));

33. На ПЭВМ1 в модуле формы (после имеющегося кода) разместить следующий программный код:

void Write_1(AnsiString Text)

{

if(MS->Size < Size_1) // если идет прием

{

MS->Write(Text.c_str(), Text.Length());

Form1->Memo1->Lines->Add("Принимаем данные...");

}

if(MS->Size==Size_1) // если файл принят

{

Receive=false; // останавливаем режим передачи

MS->Position=0;

Form1->ServerSocket1->Socket->Connections[0]

->SendText("end");

Form1->Memo1->Lines->Add("Файл принят!");

if(Form1->SaveDialog1->Execute())

{

MS->SaveToFile(Form1->SaveDialog1->FileName);

Form1->Memo1->Lines->Add("Файл сохранен...");

}

MS->Clear(); // освобождаем поток

Size_1 = 0;

}

}

34. На ПЭВМ1 в обработчике события OnClientRead компонента ClientSocket1 удалить или отметить как комментарий написанный ранее программный код и разместить следующий программный код:

AnsiString Rtext ; // текст, который посылает клиент

Rtext = ServerSocket1->Socket->Connections[0]

->ReceiveText() ;

if(Receive==true) // если мы в режиме передачи файла, то

{

Write_1(Rtext); // записываем его в поток

}

else // если нет , то

{

// пишем все что принимаем

Memo1->Lines->Add("Приняли текст :" + Rtext);

if(Rtext.SubString(0, Rtext.Pos("#")-1)=="file")

// Если это строка типа

// file#filename#filesize#, то

{

// удаляем слово "file"

Rtext.Delete(1, Rtext.Pos("#"));

// удаляем имя файла

Rtext.Delete(1, Rtext.Pos("#"));

// Определяем размер файла

Size_1 = StrToInt(Rtext.SubString(0,

Rtext.Pos("#")-1)) ;

// Удаляем последний разделитель

Rtext.Delete(1, Rtext.Pos("#"));

// Выводим размер файла

Memo1->Lines->Add("Размер файла: " +

IntToStr(Size_1) + " байт" );

// устанавл. режим приёма файла

Receive = true;

}

}

35. На ПЭВМ2 в обработчике события OnClick компонента Button3 разместить следующий программный код:

void *P; // указатель на файл

int Size_2=0; // размер передаваемого файла

if(OpenDialog1->Execute())

{

// выбираем файл

MS->LoadFromFile(OpenDialog1->FileName);

Memo1->Lines->Add("Файл загружен в поток...");

}

Form1->ClientSocket1->Socket

->SendText("file#" + OpenDialog1->FileName + "#" +

IntToStr( MS->Size ) + "#");

// отправляем заголовок

Memo1->Lines->Add("Отправлен заголовок");

MS->Position=0;//Устанавливаем поток в начальную позицию;

P=MS->Memory; // присваиваем указателю поток файла;

// отправляем буфер клиенту;

Size_2=Form1->ClientSocket1->Socket->SendBuf(P, MS->Size);

Memo1->Lines->Add("Отправлено: " + IntToStr(Size_2) +

" из " + IntToStr(MS->Size));

36. На ПЭВМ2 в модуле формы (после имеющегося кода) разместить следующий программный код:

void Write_1(AnsiString Text)

{

if(MS->Size < Size_1) // если идет прием

{

MS->Write(Text.c_str(), Text.Length());

Form1->Memo1->Lines->Add("Принимаем данные...");

}

if(MS->Size==Size_1) // если файл принят

{

Receive=false; // останавливаем режим передачи

MS->Position=0;

Form1->ClientSocket1->Socket->SendText("end");

Form1->Memo1->Lines->Add("Файл принят!");

if(Form1->SaveDialog1->Execute())

{

MS->SaveToFile(Form1->SaveDialog1->FileName);

Form1->Memo1->Lines->Add("Файл сохранен...");

}

MS->Clear() ; // освобождаем поток

Size_1 = 0 ;

}

}

37. На ПЭВМ2 в обработчике события OnRead компонента ClientSocket1 удалить или отметить как комментарий написанный ранее программный код и разместить следующий программный код:

AnsiString Rtext ; // текст, который посылает сервер

Rtext = ClientSocket1->Socket->ReceiveText() ;

if(Receive==true) // если мы в режиме передачи файла, то

{

Write_1(Rtext); // записываем его в поток

}

else // если нет , то

{

// пишем все что принимаем

Memo1->Lines->Add("Приняли текст :" + Rtext);

if(Rtext.SubString(0, Rtext.Pos("#")-1) == "file" )

// Если это строка типа

// file#filename#filesize#, то

{

// удаляем слово "file";

Rtext.Delete(1, Rtext.Pos("#"));

// Удаляем имя файла;

Rtext.Delete(1, Rtext.Pos("#"));

// Определяем размер файла

Size_1=StrToInt(Rtext.SubString(0,

Rtext.Pos("#")-1));

// Удаляем последний разделитель

Rtext.Delete(1, Rtext.Pos("#"));

// Выводим размер файла

Memo1->Lines->Add("Размер файла: " +

IntToStr( Size_1 ) + " байт");

// Устанавл. режим приёма файла

Receive = true;

}

}

Указания п. 38 выполнить на каждой из ПЭВМ, входящих в состав рабочего места.

38. Откомпилировать и выполнить разработанное ПО;

39. На ПЭВМ1 в окне экранной формы нажать кнопку «ЗАПУСК СЕРВЕРА». В текстовом поле Memo1 экранной формы должен появиться текст «Создан сервер.»;

40. На ПЭВМ2 в окне экранной формы нажать кнопку «ПОДКЛЮЧИТЬСЯ К СЕРВЕРУ». В текстовом поле Memo1 экранной формы должен появиться текст «Произведено подключение к серверу.»;

41. На ПЭВМ1 в окне экранной формы нажать кнопку «ПЕРЕДАТЬ ФАЙЛ». Это приведет к появлению окна на рис. 4.8. Выбрать файл, имеющий наименование «Transmit_file.txt» и нажать кнопку «Открыть»;

Рис. 4.8

42. На ПЭВМ2 сохранить принятый файл на жестком диске под именем «Recieved_file.txt»;

43. На ПЭВМ1 открыть файл «Transmit_file.txt» с помощью текстового редактора «блокнот». На ПЭВМ2 открыть файл «Recieved_file.txt» с помощью текстового редактора «блокнот»;

44. Сравнить тексты открытых файлов. Текст в файле «Transmit_file.txt» должен совпадать с текстом в файле «Recieved_file.txt»;

45. Повторить действия п. 41-44, используя ПЭВМ1 вместо ПЭВМ2 (ПЭВМ2 вместо ПЭВМ1).

КОНТРОЛЬНЫЕ ВОПРОСЫ

1. Изложите принципы организации передачи данных в сетях на основе протокола TCP/IP.

2. Для каких целей используется протокол UDP?

3. Какие типы адресов используются в сетях на основе протокола TCP/IP ?

4. Какой формат имеет IP адрес компьютера (устройства) в сетях на основе протокола TCP/IP ?

5. В чем заключается взаимодействие между программами по схеме «клиент/сервер»?

6. Приведите последовательность действий в программной среде C++Builder 6, необходимую для создания ПО, реализующего функции клиента.

7. Приведите последовательность действий в программной среде C++Builder 6, необходимую для создания ПО, реализующего функции сервера.

ЛИТЕРАТУРА

1. Олифер В. Г., Олифер Н. А. Компьютерные сети. Принципы, технологии, протоколы – СПб.: Питер, 2006. – 958 с.

2. Гук М. Аппаратные интерфейсы ПК. – СПб.: Питер, 2002. – 528 с.

3. Архангельский А. Я. Программирование в C++ Builder 6 – М.: Издательство Бином, 2003. – 1152 с.

4.http://devoid.com.ua/c-builder/cppbuilder-network-programming/peredacha-failov-v-c-builder-cherez-socket.html (электронный ресурс)

5. Архангельский А. Я. C++ Builder 6. Справочное пособие. Книга 2. Классы и компоненты – М.: Бином-Пресс, 2002. – 528 с.