КР№2
.docxМинистерство образования Республики Беларусь
Учреждение образования
«Белорусский государственный университет информатики и
радиоэлектроники»
Кафедра экономической информатики
КОНТРОЛЬНАЯ РАБОТА №2
по дисциплине: «Компьютерные сети»
на тему: «Программирование протоколов сетевого и транспортного уровней. Создание последовательного сервера без установления логического соединения UPD»
Вариант 1
Выполнила студентка: Быкович Е.И.
Группа 792351
Минск 2020
Индивидуальное задание
Разработать приложение, реализующее архитектуру «клиент-сервер». Необходимо реализовать последовательный сервер без установления логического соединения UPD. Логику взаимодействия клиента и сервера реализовать следующим образом: Клиент вводит с клавиатуры строку символов и посылает ее серверу. Признак окончания ввода строки – нажатие клавиши «Ввод». Сервер, получив эту строку, должен определить длину введенной строки, и, если эта длина кратна 3, то удаляются все числа, которые делятся на 3. Результаты преобразований этой строки возвращаются назад клиенту.
Нам необходимо написать две программы серверную и клиентскую.
В серверной программе инициализируем WinSock API, используя функцию WSAStartup. Создаем сокет, использующий протокол TCP, при помощи функции socket. Устанавливаем сокету адрес и порт, используя функцию bind. Далее ожидаем установки соединения с клиентом, для чего используем функцию listen. После прихода с клиента предложения о соединении, принимаем его, используя функцию accept. И начинаем принимать данные с клиента, используя функцию recv. Принятые данные обрабатываем, исходя из условия задачи, и отсылаем результат обработки, используя функцию send. В конце программы закрываем сокет, при помощи функции closesocket, и прекращаем работу WinSock API, используя функцию WSACleanup.
В клиентской программе инициализируем WinSock API, используя функцию WSAStartup. Создаем сокет, использующий протокол TCP, при помощи функции socket. Устанавливаем соединение с сервером, используя функцию connect. Считываем данные с потока входа, при помощи функции std::cin.getline, и отсылаем их на сервер, используя функцию send. Получаем результат с сервера, используя функцию recv, и выводим его на экран, посредством функции std::cout. В конце программы закрываем сокет, при помощи функции closesocket, и прекращаем работу WinSock API, используя функцию WSACleanup.
Вышеописанная работа произведена в отдельной функции с именем ThreadFunc. Она вызывается в отдельном потоке после установки соединения с клиентом, используя функцию CreateThread.
#include<stdio.h>
#include<iostream>
#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
DWORD WINAPI ThreadFunc(LPVOID client_socket) {
SOCKET *s2=((SOCKET *) client_socket);
char buf[100];
char buf1[100];
char *testStr = "0369";
// send(s2,"Welcome new client!\n",sizeof("Welcome new client!\n"),0);
while(recv(*s2,buf,sizeof(buf),0) != 0) {
int k, j=0;
k=strlen(buf);
if(k%3==0) {
for(int i=0; i < k; i++) {
if (strchr(testStr, buf[i]) == 0) {
buf1[j++] = buf[i];
}
}
buf1[j]='\0';
strcpy(buf,buf1);
}
std::cout<<buf<<std::endl;
send(*s2,buf,strlen(buf),0);
}
closesocket(*s2);
return 0;
}
int numcl=0;
void print() {
if (numcl) printf("%d client connected\n",numcl);
else printf("No clients connected\n"); }
void main() {
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) { return; }
SOCKET s=socket(AF_INET,SOCK_STREAM,0);
sockaddr_in local_addr;
local_addr.sin_family=AF_INET;
local_addr.sin_port=htons(1280);
local_addr.sin_addr.s_addr=0;
bind(s,(sockaddr *) &local_addr,sizeof(local_addr));
int c=listen(s,5);
std::cout<<"Server receive ready"<<std::endl;
std::cout<<std::endl;
// извлекаем сообщение из очереди
SOCKET client_socket; // сокет для клиента
sockaddr_in client_addr; // адрес клиента(заполняется системой)
int client_addr_size=sizeof(client_addr);
// цикл извлечения запросов на подключение из очереди
while((client_socket=accept(s,(sockaddr *)&client_addr, &client_addr_size))) {
numcl++;
print();
// Вызов нового потока для обслуживания клиента
CreateThread(NULL,NULL,ThreadFunc,&client_socket,NULL,NULL);
}
}
#include <winsock2.h>
#include <iostream>
#include <stdlib.h>
#pragma comment(lib,"Ws2_32.lib")
int main() {
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
WSAStartup(wVersionRequested,&wsaData);
struct sockaddr_in peer;
peer.sin_family=AF_INET;
peer.sin_port=htons(1280);
// т.к. клиент и сервер на одном компьютере,
// пишем адрес 127.0.0.1
peer.sin_addr.s_addr=inet_addr("127.0.0.1");
SOCKET s=socket(AF_INET,SOCK_STREAM,0);
connect(s,(struct sockaddr*) &peer,sizeof(peer));
char buf[255],b[255];
std::cout<<"Enter string."<<std::endl;
std::cin>>buf;
std::cin.get();
send(s,buf,strlen(buf) + 1,0);
if (recv(s,b,sizeof(b),0)!=0) {
std::cout<<b<<std::endl;
std::cin.get();
}
shutdown(s, SD_SEND);
WSACleanup();
return 0;
}
Контрольные вопросы
-
Что содержит UDP-сообщение помимо посылаемых данных?
В стеке протоколов TCP/IP UDP обеспечивает основной механизм, используемый прикладными программами для передачи датаграмм другим приложениям. UDP предоставляет протокольные порты, используемые для различения нескольких процессов, выполняющихся на одном компьютере. Помимо посылаемых данных каждое UDP-сообщение содержит номер порта-приемника и номер поpта-отпpавителя, делая возможным для программ UDP на машине-получателе доставлять сообщение соответствующему реципиенту, а для получателя посылать ответ соответствующему отправителю.
-
Что называется дейтаграммой?
Единица данных протокола UDP называется UDP-дейтаграммой, или пользовательской дейтаграммой. Каждая дейтаграмма переносит отдельное пользовательское сообщение. Это приводит к естественному ограничению: длина дейтаграммы UDP не может превышать длины поля данных протокола IP, которое, в свою очередь, ограничено размером кадра технологии нижнего уровня. Поэтому если UDP-буфер переполняется, то данные приложения отбрасываются. Первый 64 бита дейтаграммы представляют собой UDP-заголовок, остальные биты — данные сообщения.
-
Какие возможности не предоставляет UDP (в отличие от TCP)?
Разница между протоколами TCP и UDP – в так называемой «гарантии доставки». TCP требует отклика от клиента, которому доставлен пакет данных, подтверждения доставки, и для этого ему необходимо установленное заранее соединение. Также протокол TCP считается надежным, тогда как UDP получил даже именование «протокол ненадежных датаграмм». TCP исключает потери данных, дублирование и перемешивание пакетов, задержки. UDP все это допускает, и соединение для работы ему не требуется. Процессы, которым данные передаются по UDP, должны обходиться полученным, даже и с потерями. TCP контролирует загруженность соединения, UDP не контролирует ничего, кроме целостности полученных датаграмм.
С другой стороны, благодаря такой не избирательности и бесконтрольности, UDP доставляет пакеты данных (датаграммы) гораздо быстрее, потому для приложений, которые рассчитаны на широкую пропускную способность и быстрый обмен, UDP можно считать оптимальным протоколом. К таковым относятся сетевые и браузерные игры, а также программы просмотра потокового видео и приложения для видеосвязи (или голосовой): от потери пакета, полной или частичной, ничего не меняется, повторять запрос не обязательно, зато загрузка происходит намного быстрее. Протокол TCP, как более надежный, с успехом применяется даже в почтовых программах, позволяя контролировать не только трафик, но и длину сообщения и скорость обмена трафиком.
TCP — ориентированный на соединение протокол, что означает необходимость «рукопожатия» для установки соединения между двумя хостами. Как только соединение установлено, пользователи могут отправлять данные в обоих направлениях.
-
Надёжность — TCP управляет подтверждением, повторной передачей и тайм-аутом сообщений. Производятся многочисленные попытки доставить сообщение. Если оно потеряется на пути, сервер вновь запросит потерянную часть. В TCP нет ни пропавших данных, ни (в случае многочисленных тайм-аутов) разорванных соединений.
-
Упорядоченность — если два сообщения последовательно отправлены, первое сообщение достигнет приложения-получателя первым. Если участки данных прибывают в неверном порядке, TCP отправляет неупорядоченные данные в буфер до тех пор, пока все данные не могут быть упорядочены и переданы приложению.
-
Тяжеловесность — TCP необходимо три пакета для установки сокет-соединения перед тем, как отправить данные. TCP следит за надёжностью и перегрузками.
-
Потоковость — данные читаются как поток байтов, не передается никаких особых обозначений для границ сообщения или сегментов.
UDP — более простой, основанный на сообщениях протокол без установления соединения. Протоколы такого типа не устанавливают выделенного соединения между двумя хостами. Связь достигается путём передачи информации в одном направлении от источника к получателю без проверки готовности или состояния получателя. В приложениях для голосовой связи через интернет-протокол (Voice over IP, TCP/IP) UDP имеет преимущество над TCP, в котором любое «рукопожатие» помешало бы хорошей голосовой связи. В VoIP считается, что конечные пользователи в реальном времени предоставят любое необходимое подтверждение о получении сообщения.
-
Ненадёжный — когда сообщение посылается, неизвестно, достигнет ли оно своего назначения — оно может потеряться по пути. Нет таких понятий, как подтверждение, повторная передача, тайм-аут.
-
Неупорядоченность — если два сообщения отправлены одному получателю, то порядок их достижения цели не может быть предугадан.
-
Легковесность — никакого упорядочивания сообщений, никакого отслеживания соединений и т. д. Это небольшой транспортный уровень, разработанный на IP.
-
Датаграммы — пакеты посылаются по отдельности и проверяются на целостность только если они прибыли. Пакеты имеют определенные границы, которые соблюдаются после получения, то есть операция чтения на сокете-получателе выдаст сообщение таким, каким оно было изначально послано.
-
Нет контроля перегрузок — UDP сам по себе не избегает перегрузок. Для приложений с большой пропускной способностью возможно вызвать коллапс перегрузок, если только они не реализуют меры контроля на прикладном уровне.
-
Чем функции sendto() и recvfrom() отличаются от функций send() и recv()?
Функции sendto() и recvfrom() очень похожи на send и recv - разница лишь в том, что sendto и recvfrom требуют явного указания адреса узла, принимаемого или передаваемого данные. Вызов recvfrom не требует предварительного задания адреса передающего узла - функция принимает все пакеты, приходящие на заданный UDP-порт со всех IP-адресов и портов. Напротив, отвечать отправителю следует на тот же самый порт откуда пришло сообщение. Поскольку функция recvfrom заносит IP-адрес и номер порта клиента после получения от него сообщения, программисту фактически ничего не нужно делать - только передать sendto тот же самый указатель на структуру sockaddr, который был ранее передан функции recvfrem, получившей сообщение от клиента.
-
Что происходит, если размер буфера, переданный в функцию recvfrom (), слишком мал для приема всей дейтаграммы целиком?
Если в буфере, переданном функции recv или recvfrom, недостаточно места для получения дейтаграммы, эти функции завершаются с ошибкой. При этом в буфер помещается та часть дейтаграммы, которая может в нем поместиться, а оставшаяся часть дейтаграммы теряется.
-
Приведите примеры сетевых приложений, использующих UDP.
Наиболее известными сервисами, основанными на UDP, является служба доменных имен BIND и распределенная файловая система NFS.
Из этих правил есть исключения, в особенности для существующих приложений. Например, TFTP использует UDP для передачи большого количества данных. Для TFTP был выбран UDP, поскольку, во-первых, его реализация проще в отношении кода начальной загрузки (800 строк кода С для UDP в сравнении с 4500 строками для TCP, например в [128]), а во-вторых, TFTP используется только для начальной загрузки систем в локальной сети, а не для передачи большого количества данных через глобальные сети. Однако при этом требуется, чтобы в TFTP были предусмотрены такие свойства, как собственное поле порядкового номера (для подтверждений), тайм-аут и возможность повторной передачи.
NFS (Network File System — сетевая файловая система) является другим исключением из правила: она также использует UDP для передачи большого количества данных (хотя некоторые могут возразить, что в действительности это приложение типа «запрос-ответ», использующее запросы и ответы больших размеров). Отчасти это можно объяснить исторически сложившимися обстоятельствами: в середине 80-х, когда была разработана эта система, реализации UDP были быстрее, чем TCP, и система NFS использовалась только в локальных сетях, где потеря пакетов, как правило, происходит на несколько порядков реже, чем в глобальных сетях. Но как только в начале 90-х NFS начала использоваться в глобальных сетях, а реализации TCP стали обгонять UDP в отношении производительности при передаче большого количества данных, была разработана версия 3 системы NFS для поддержки TCP. Теперь большинство производителей предоставляют NFS как для и TCP, так и для UDP. Аналогичные причины (большая скорость по сравнению с TCP в начале 80-х плюс преобладание локальных сетей над глобальными) привели к тому, что в Apollo NCS (предшественник DCE RPC) сначала использовали UDP, а не TCP, хотя современные реализации поддерживают и UDP, и TCP.
-
В каких случаях применение UDP протокола может быть предпочтительнее, чем TCP?
Хорошим примером того, когда UDP может быть предпочтительнее TCP, является приложение, которое работает лучше с меньшими задержками, например онлайн-игры, видеочаты или голосовые передачи. Пакеты могут быть утеряны, но с меньшими общими задержками для снижения качества, на самом деле не наблюдается значительной потери качества.
В онлайн-играх трафик UDP позволяет продолжить игру, даже если соединение на мгновение потеряно или если по какой-либо причине некоторые пакеты отброшены. Если бы происходило исправление ошибок, соединение потерпело бы потерю времени, так как пакеты пытаются повторно войти туда, где они остановились, чтобы компенсировать ошибки, но это не нужно в живых видеоиграх. То же самое верно для прямой трансляции.
Однако причина, по которой UDP не так велик, когда дело доходит до передачи файлов, заключается в том, что вам нужен весь файл, чтобы правильно его использовать. Как TCP, так и UDP находятся на уровне 4 модели OSI и работают с такими сервисами, как TFTP, RTSP и DNS.