Каркас простого TCP-сервера с одним соединением, работающим на прием данных.
#include "winsock2.h" DWORD WINAPI Connection(LPVOID); DWORD WINAPI Reciever(LPVOID); SOCKADDR_IN serv_ad; SOCKADDR_IN cl_ad; SOCKET serv_sock; char s[255]; HANDLE hThread[2]; DWORD WINAPI Connection(LPVOID) { int len = sizeof(cl_ad); do srv_sock = accept(serv_sock,(LPSOCKADDR)&cl_ad, (int FAR *)&len); while (srv_sock == INVALID_SOCKET); hThread[1] = CreateThread(NULL,0,Reciever,NULL,0,NULL); MessageDlg("Connect OK", mtInformation, TMsgDlgButtons() << mbOK, 0); int code; ExitThread(code); // Если соединений будет больше то //завершать поток не надо } //--------------------------------------------------------- DWORD WINAPI Reciever(LPVOID) { while(1) { int rv = recv(srv_sock,s,255,0); // Теперь принятые //данные в буфере s. if (rv == SOCKET_ERROR) MessageDlg(IntToStr(rv), mtError, TMsgDlgButtons() << mbOK, 0); else; // здесь вы обрабатываете поступившие данные и //управляете потоком приема } } int WinMain (void) { if (WSAStartup(MAKEWORD(2,0),&LPWS)!=0) { MessageDlg(IntToStr(rs), mtError, TMsgDlgButtons() << mbOK, 0); serv_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if (serv_sock ==INVALID_SOCKET) MessageDlg(“Error Sock”, mtError,TMsgDlgButtons() << mbOK, 0); serv_ad.sin_family = AF_INET; serv_ad.sin_port = htons(PORT); serv_ad.sin_addr.s_addr = INADDR_ANY; if (bind(serv_sock, (PSOCKADDR)&serv_ad, sizeof(serv_ad)) == SOCKET_ERROR) MessageDlg(IntToStr(svz), mtError,TMsgDlgButtons() << mbOK, 0); int tst = listen(serv_sock,5); hThread[0]=CreateThread(NULL,0,Connection, NULL,0,NULL); } |
Каркас простого TCP-клиента с одним соединением, работающим на передачу данных, использующих асинхронную передачу данных.
#define WM_SOCKET WM_USER+1 ……………………… // инициализация сокета и перевод его в асинхронный режим // приема передачи данных void __fastcall TForm1::FormCreate(TObject *Sender) { // Создание сервера // Создаем сокет serv_sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if (serv_sock ==INVALID_SOCKET) MessageDlg(IntToStr(serv_sock), mtError, TMsgDlgButtons() << mbOK, 0); // Принадлежность адреса к семейству интернет адресов serv_ad.sin_family = AF_INET; // Указываем порт serv_ad.sin_port = htons(4554); // Тип адреса любой serv_ad.sin_addr.s_addr = INADDR_ANY; // Связываем сокет с адресом if (bind(serv_sock, (PSOCKADDR)&serv_ad, sizeof(serv_ad))==SOCKET_ERROR) MessageDlg("Ошибка привязки структуры к сокету!!!", mtError, TMsgDlgButtons() << mbOK, 0); // Задаем режим передачи – асинхронный и указываем в //качестве функции обработчика сообщений - RecieveData WSAAsyncSelect(serv_sock, static_cast<HWND>(Form1->Handle), WM_SOCKET,FD_ACCEPT | FD_READ | FD_WRITE); Application->OnMessage = RecieveData; } …………………………………… void __fastcall TForm1::RecieveData(TMsg & Msg, bool &handled) // как только пришло сообщение о работе с сокетом, // обрабатываем его { if (Msg.message == WM_SOCKET) { switch (WSAGETSELECTEVENT(Msg.lParam)) { case FD_READ: { // Прием данных из сокета int rv=recvfrom(serv_sock,s,255,0, (PSOCKADDR)&sFrom,&len); if(rv == SOCKET_ERROR) { // Если пришел пустой пакет значит конец // файла, закрываем файл } else { if (FileFull) { s[rv] = 0; FileName=CreateFile(s,GENERIC_WRITE, FILE_SHARE_WRITE,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL); FileFull = false; } else { DWORD* lBlock = new DWORD; if (0==rv) { if (!FileFull) { CloseHandle(FileName); FileFull = true; break; } } WriteFile(FileName,s,rv,lBlock,NULL); } } } default: // TO DO } } |
|
Каркас простого TCP-клиента с одним соединением, работающим на передачу данных.
#include "winsock2.h" int Sender(char Buf[4]); SOCKADDR_IN dest_sin; SOCKET clnt_sock; //--------------------------------------------------------- int Sender(char Buf[4]) { int Rez = send(clnt_sock,Buf,4,0); if (Rez == SOCKET_ERROR) return -1; return 0; } int WinMain (void) { PHOSTENT phe; if (WSAStartup(MAKEWORD(2,0),&LPWS)!=0) { MessageDlg(IntToStr(rs), mtError, TMsgDlgButtons() << mbOK, 0); clnt_sock = socket(AF_INET, SOCK_STREAM, 0); dest_sin.sin_family = AF_INET; phe = gethostbyname(“server”); memcpy((char FAR *)&(dest_sin.sin_addr), phe->h_addr, phe->h_length); dest_sin.sin_port = htons(1024); if (connect(clnt_sock, (PSOCKADDR)&dest_sin, sizeof(dest_sin))== SOCKET_ERROR) MessageDlg("Connect Failed", mtError, TMsgDlgButtons() << mbOK, 0); Sender(“TEST”); } |
Каркас UDP-сервера в основном похож на каркас TCP-сервера. Его отличительная особенность – не нужно устанавливать опция сокета SO_REUSEADDR и обращаться к системным вызовам accept и listen, поскольку UDP – это пртокол, не требующий логического соединения.
|
При использовании протокола негарантированной доставки UDP необходимо создать сокет, осуществить его привязку к адресу с помощью функции bind и начинать прием или передачу данных с помощью описанных выше функций recvfrom и sendto. Структура соединения по протоколу UDP приведена ниже.
5. Рабочее задание и указание к его выполнению.
В данной лабораторной работе необходимо разработать программы для передачи данных в сети с использованием стека протоколов TCP/IP. Варианты заданий выбираются исходя из таблиц, приведенных ниже. По номеру варианта, полученного у преподавателя, вы выбираете из таблицы вид транспортного протокола, тип приема/передачи и номер задания из списка.
Список заданий:
1) Переслать состояние сервера клиенту. Сервер поддерживает одновременное соединение с более чем одним клиентом. В качестве информации о сервере необходимо передавать имена и адреса клиентов, подсоединенных в текущий момент, общее кол-во соединений, количество байт информации, переданной от сервера клиентам на текущий момент, объем информации, полученной клиентом от сервера на текущий момент, время работы программы-сервера с момента запуска, кол-во свободных каналов для соединения с клиентами, версия используемой библиотеки winsock, список поддерживаемых протоколов и т.д. Необходимо передать не менее пяти пунктов из списка.
2) Терминал для пересылки символов. На экране два окна. Одно для передаваемых данных, второе для принимаемых. Передача осуществляется по нажатию клавиши немедленно. Сервер принимает запрос на соединения только с одним клиентом.
|
3) Терминал для пересылки символов. Одно для передаваемых данных, второе для принимаемых. Передача осуществляется по нажатию клавиши немедленно. На стороне клиента окно для передачи данных, на стороне сервера окно для каждого соединения с клиентом, содержащее полученную информацию. При установлении соединения сервер создает новое окно, зоголовком которого является имя или адрес клиента. Сервер принимает запрос на соединения с более чем одним клиентом.
4) Терминал для пересылки символьных строк. По окончанию ввода строки символов и нажатию клавиши «Enter» происходит передача строки символов от клиента серверу. На стороне сервера – окно для приема данных, на стороне клиента – окно для передачи символьных строк и окно с информацией о состоянии каждой передачи (пакет принят сервером, связь разорвана, сервер не отвечает и т.д.)
5) Эхо-протокол. Передаётся тестовый пакет. Исходный текст генерируется у клиента, передаётся на сервер, отображается на мониторе сервера, возвращается клиенту и отображается на мониторе клиента. На стороне сервера окно для приема данных. При каждой передаче данных от клиента к серверу, при выводе на экран, к пакету принимаемых данных добавляется информация об адресе клиента. На стороне клиента должна присутствовать возможность генерации тестового пакета автоматически и вручную.
6) Переслать файл от клиента к серверу. На стороне клиента должен быть диалог выбора файла для отправки. Формат файла – любой. На сервере – окно с информацией о полученных файлах (размер, время создания, имя клиента отославшего файл). Кол-во соединений неограниченно.
7) Построить примитивный FTP-сервер. Сервер должен реагировать на запросы клиента и предоставлять следующие возможности:
Ø получение списка файлов в текущей директории (текущей считается директория, из которой запущена программа-сервер);
Ø получение списка файлов заданной директории или сообщение об отсутствии заданной директории или файлов внутри нее;
Ø переслать запрошенный клиентом файл от сервера клиенту.
Формат управляющего пакета:
Управляющий пакет состоит из 4-х байтов. Первый байт - код команды, второй, третий - операнд, четвертый - резерв:
Код команды | Псевдоним | Операнд | Комментарии | Резерв |
List | Имя директории на сервере | Передает клиенту список файлов указанной директории, если операнд пустой – директория текущая. | Если резерв равен 00000001, то следующие пакеты будут содержать значения операнда, до тех пор пока резерв не станет равен 00000000 | |
scopy | Имя файла | Осуществляет передачу файла, заданного полем операнд, клиенту | В резерве содержится маркер продолжения, если он равен 00000001, то следующие пакеты данных – значение операнда. Конец – 00000000. | |
Определяется студентом | ||||
… | ||||
… | ||||
Формат данных: данные пересылаются пакетами по 32 байта.
Т.е. если полученное кол-во байтов равно 4, то пакет управляющий, если 32, то информационный. Пакет с данными должен всегда быть равным 32 байта, если пакет меньше, то его размер должен быть увеличен до 32-х байтов. 32-ой байт пакета данных – позиция конца данных в пакете. Например, если в пакете данных полезных байтов информации – 20, то пакет содержит следующую информацию:
{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}{I}NNNNNNNNNNN{20}, где {I} – байт содержащий полезную информацию, N – мусор, {20} позиция конца полезной информации относительно начала пакета.
8) Написать программу-клиент к варианту 7.
9) Переслать копию рабочего стола ОС Windows от сервера клиенту в виде BMP файла.
10) Запустить указанный exe файл на сервере. От клиента сервер получает пакет с полным именем исполнимого файла (путь + имя + расширение). Сервер уведомляет клиента о выполнении задачи или об отсутствии исполнимого файла на стороне сервера и разрывает соединение с клиентом. Количество соединений неограниченно.
11) Выключить компьютер на стороне клиента используя API-функции ОС и socket.
12) Синхронизировать системные часы на клиентах и сервере, используя широковещательную передачу данных. Сервер считывает системное время и посылает всем компьютерам в данной сети. Компьютеры, на которых запущена программа-клиент изменяют системную дату и время, используя информацию полученную от сервера. В случае ошибки выдать соответствующее сообщение.
13) Сгенерировать сообщение-задание и отослать его от клиента к серверу. Сервер должен предоставлять список доступных заданий по запросу клиента. Клиент выбирает номер задания из списка предоставленного сервером и назначает время выполнения каждого из заданий. Например, сервер по запросу клиента предоставляет следующую информацию:
1 – выключить компьютер;
2 – запустить программу проверки дисков на наличие ошибок;
3 – запустить антивирус;
4 – остановить работу программы сервера.
Клиент генерирует следующее сообщение:
11.01.04 12:00 [3]
Сервер получив сообщение от клиента обрабатывает его содержимое и выполняет предписанные действия, информируя клиента о выполнении. Количество соединений сервера с клиентом не ограничено.
Формат запроса списка заданий – 4-х байтовое сообщение «list»
Формат сообщения задания: - 20-ти байтовое сообщение содержащее дату, время и номер задания из списка предоставленного сервером.
За одну передачу клиент может зарегистрировать только одно задание от клиента. На клиенте должна имеется возможность редактирования списка заданий. Задания предоставляемые сервером клиенту должны быть отсортированы по номеру.
14) Сервер слежения за состоянием компьютеров в сети. Используя широковещательную передачу данных каждые 3 минуты проверять о нахождении зарегистрированных компьютеров в сети. В случае отключения компьютера сервер выводит соответствующую информацию. При регистрации нового компьютера в сети сервер делает необходимую запись и по запросу выдает их пользователю (локальному). Регистрация происходит путем передачи пакета с данными «reg» клиентом к серверу.
Таблицы вариантов.
Протокол TCP
С использованием синхронной передачи данных | |||||||||||
Вариант № | |||||||||||
Сложность | *** | * | ** | ** | ** | ** | *** | *** | ** | * | * |
Пункт задания |
С использованием асинхронной передачи данных | |||||||||||
Вариант № | |||||||||||
Сложность | *** | * | ** | ** | ** | ** | *** | *** | ** | * | * |
Пункт задания |
Протокол UDP
С использованием синхронной передачи данных | |||||||||
Вариант № | |||||||||
Сложность | *** | * | ** | *** | * | ** | ** | ** | ** |
Пункт задания |
С использованием асинхронной передачи данных | |||||||||
Вариант № | |||||||||
Сложность | * | *** | ** | *** | * | ** | ** | ** | ** |
Пункт задания |
* - легкая задача
** - задача средней сложности
*** - трудная задача
6. Содержание отчёта.
- алгоритмы программ;
- листинги программ с комментариями;
- описание программ;
- данные контрольного примера;
Вопросы для самопроверки.
1) Стек протоколов TCP/IP. Его уровни и входящие в них протоколы.
2) Транспортные протоколы TCP и UDP. Их различия и задачи применения.
3) Функции IP протокола. Формат IP пакета.
4) Протокол UDP. Формат UDP сообщения.
5) Два способа передачи данных в сетях. Их преимущества и недостатки.
6) Что такое «сокет»? Что такое интерфейс «Windows Sockets».
7) С помощью каких функций происходит инициализация приложения и завершение его работы в интерфейсе Windows Sockets. Опишите параметры этих функций.
8) С помощью каких функций происходит создание, инициализация и удаление сокетов. Опишите параметры этих функций.
9) Параметры сокетов. Какие два формата адресов можно использовать в параметре сокета. Средства Windows Sockets для конвертирования из одного формата в другой. Средства перевода доменных имён в IP адреса.
10) В каких случаях необходимо создание канала связи. С помощью каких функций реализуется. Охарактеризуйте параметры.
11) Функции для приёма и передачи данных. Способы широковещательной передачи данных.