Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ППуКМ / Labs 1-7 / Лабораторна робота №3

.doc
Скачиваний:
15
Добавлен:
18.03.2016
Размер:
68.61 Кб
Скачать

Лабораторна робота № 4

На тему:

СОКЕТИ WINDOWS. ПРОТОКОЛИ, ЩО НЕ ВИМАГАЮТЬ З'ЄДНАННЯ

Принцип дії таких протоколів інший, ніж в протоколів із встановленням з’єднання, тому що в них використовуються інші методи відправлення та прийому даних. Обговоримо спочатку одержувача (або сервер), тому що не потребуючий з'єднання приймач мало відрізняється від серверів, що вимагають з'єднання.

Приймач

Процес одержання даних від сокета, що не потребує з'єднання, простий. Спочатку створюють сокет функцією sockett. Потім виконують прив'язку сокета до інтерфейсу, через який будуть приймати дані. Різниця в тому, що не можна викликати listen або accept, замість цього потрібно просто очікувати прийому вхідних даних. Оскільки в цьому випадку з'єднання немає, приймаючий сокет може одержувати дейтаграмми від будь-якої машини в мережі. Найпростіша функція прийому - recvform.

Функція recvform

Приймає дейтаграми по сокету й записує адресу джерела.

int recvfrom(

SOCKET s,

char* buf,

int len,

int flags,

struct sockaddr* from,

int* fromlen

);

Параметри:

s - визначає сокет для прийому даних.

buf - символьний буфер призначений для отриманих даних.

len - вказує число прийнятих байт або розмір буфера buf.

flags – вказує тип шляху доставки даних.

from - структура sockaddr для даного протоколу слухаючого сокета. Після повернення виклику буде містити адреса робочої станції, що відправляє дані.

fromlen - адреса розміру структури.

При успішному виконанні функція recv повертає кількість прийнятих байт, інакше - помилку SOCKET_ERROR.

Відправник

Функція sendto

Відправляє дані по вказаній адресі.

int sendto(

SOCKET s,

const char* buf,

int len,

int flags,

const struct sockaddr* to,

int tolen

);

Параметри:

s - визначає сокет для відправлення даних.

buf - указує на символьний буфер, що містить дані для відправлення.

len - задає число символів, що відправляють із буфера.

flags – вказує тип шляху доставки даних.

to – вказівник на структуру sockaddr з адресою приймаючої робочої станції.

tolen - розмір вказівника to.

При успішному виконанні функція sendto поверне кількість переданих байт, інакше - помилку SOCKET_ERROR.

Звільнення ресурсів сокета

Оскільки з'єднання не встановлюється, його формального розриву або коректного закриття не потрібно. Після припинення відправлення або одержання даних відправником або одержувачем просто викликається функція closesocket описувачем необхідного сокета, у результаті чого звільняються всі виділені йому ресурси.

Приклад

Тепер розглянемо реальний код, що виконує відправлення й прийом даних по протоколі. У лістингу 4-1 наведений код приймача. Прийом дейтаграмм простий. Спочатку необхідно створити сокет, потім прив'язати його до локальної адреси. Потім для читання вхідних даних залишається тільки виконати виклики recvfrom. Ми використовуєм recvfrom, тому що нас не цікавлять фрагментарні повідомлення, протокол UDP не підтримує їхню передачу. Фактично, стек TCP/IP намагається зібрати велике повідомлення з отриманих фрагментів. Якщо один або кілька фрагментів відсутні або порушений порядок їхнього проходження, стек відкидає все повідомлення.

У лістингу 4-2 наведений код відправника, що не вимагає з'єднання. Обов'язкові параметри - IP-адреса й порт вилученого одержувача. Спочатку створюються сокет, потім дані відправляються отримувачеві функцією sendto.

Лістинг 4-1. Приймач, що не вимагає встановлення з'єднання

#include "winsock2.h"

#include "stdio.h"

#include "stdlib.h"

#define PORT 5556 // Порт прослуховування клієнтів

#define BUFLEN 4096

char chRecvBuf[BUFLEN]; char chSendBuf[BUFLEN];

char chAcknowl[]="Your message received.";

int iLen;

int saLen;

// Функція: main

//

// Опис:

// Головний потік керування. Ініціалізує Winsock, обробляє аргументи

// командної стрічки, створює сокет, зв’язує його з локальним інтерфейсом

// і портом, читає дейтаграмми.

int main()

{

WSADATA Wsadata;

SOCKET sReceiver;

sockaddr_in saLocal,saSender;

// Підключення бібліотеки Winsock

WSAStartup(MAKEWORD(2,2),&Wsadata);

// Створення сокету

sReceiver = socket(AF_INET,SOCK_DGRAM,0);

// Зв’язування сонету з локальною адресою

saLocal.sin_family=AF_INET;

saLocal.sin_port=htons((short)PORT);

saLocal.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

bind(sReceiver,(SOCKADDR*) &saLocal,sizeof(saLocal));

// Обробка пакетів надісланих клієнтами

while(1)

{

// Читання дейтаграмми

saLen=sizeof(saSender);

iLen = recvfrom(sReceiver,chRecvBuf,BUFLEN,0,(sockaddr*) &saSender,&saLen);

if(iLen==SOCKET_ERROR)

printf("recvfrom() failed \n");

else

{

chRecvBuf[iLen]='\0';

printf("IP: %s send me: %s\n",inet_ntoa(saSender.sin_addr),chRecvBuf);

// Відсилання підтвердження прийому даних від відправника

// по адресі saSender

strcpy(chSendBuf,chRecvBuf);

iLen=sendto(sReceiver,chSendBuf,strlen(chSendBuf),0,

(sockaddr*) &saSender,sizeof(saSender));

}

}

closesocket(sReceiver);

WSACleanup();

return 0;

}

Лістинг 4-2. Відправник, що не вимагає встановлення з'єднання

#include "winsock2.h"

#include "stdio.h"

#include "stdlib.h"

#include "conio.h"

#define PORT 5556

#define BUFLEN 64

#define STR_IP_RECV "127.0.0.1"

char chSendBuf[BUFLEN];

char chRecvBuf[BUFLEN];

int iLen;

// Функція: main

//

// Опис:

// Головний потік виконання. Ініціалізує Winsock, обробляє аргументи

// командного рядка, створює сокет, при необхідності підключається по вилученому

// IP-адресі, потім відправляє дейтаграмму одержувачеві.

int main()

{

WSADATA Wsadata;

SOCKET sSender;

sockaddr_in saRecipient;

// Підключення бібліотеки Winsock

WSAStartup(MAKEWORD(2,2),&Wsadata);

// Створення сокета

sSender = socket(AF_INET,SOCK_DGRAM,0);

// Задання IP-адреси або імені вузла приймача

saRecipient.sin_family=AF_INET;

saRecipient.sin_port=htons((short)PORT);

saRecipient.sin_addr.S_un.S_addr=inet_addr(STR_IP_RECV);

printf("Send to IP: %s \nWrite message and press enter:\n",STR_IP_RECV);

while(1)

{

// Читання повідомлення із клавіатури

gets(chSendBuf);

// Передача повідомлень на сервер

iLen=sendto(sSender,chSendBuf,strlen(chSendBuf),0,

(SOCKADDR*) &saRecipient,sizeof(saRecipient));

if(iLen==SOCKET_ERROR)

printf("sendto() failed \n");

else

{

// Прийом повідомлення від сервера

sockaddr_in saReciver;

int iLenReciver=sizeof(saReciver);

int iLenRecv=recvfrom(sSender,chRecvBuf,BUFLEN,0,

(sockaddr*) &saReciver, &iLenReciver);

if (iLenRecv==SOCKET_ERROR)

printf("recvfrom() failed \n");

else

{

// Вивід прийнятого від сервера повідомлення на екран

chRecvBuf[iLenRecv]='\0';

printf("Server: %s \n",chRecvBuf);

}

}

}

getch();

closesocket(sSender);

WSACleanup();

return 0;

}

Варіанти завдань

варіанту

Режими обміну

Встановлення

з’єднання

1

S1  R2, S1  SR3  R2

-

2

S1  SR2  R3

-

3

SR1  SR2  SR1

-

4

S1  R2  S3

-

5

R1  SR2  SR3  SR2

-

6

S1  R2

-

7

SR1  SR2  SR3  SR1

-

8

S1  R2, S1  R3

-

9

SR1  R2, SR1  SR3  SR1

-

10

SR1  SR2, SR1  SR3, SR3  SR1, SR2  SR1

-

11

S1  R2, S1  SR3  R2

+

12

S1  SR2  R3

+

13

SR1  SR2  SR1

+

14

S1  R2  S3

+

15

R1  SR2  SR3  SR2

+

16

S1  R2

+

17

SR1  SR2  SR3  SR1

+

18

S1  R2, S1  R3

+

19

SR1  R2, SR1  SR3  SR1

+

20

SR1  SR2, SR1  SR3, SR3  SR1, SR2  SR1

+

S – sender

R – receiver

SR – sender/receiver

Завдання можуть змінюватись і доповнюватись викладачем.