- •57 Програмне забезпечення мереж еом. Частина 3. Відання 2. Програмування інтерфейсу «WinSocket»
- •Лабораторна робота № 1. Основні теоретичні положення (інтерфейс windows sockets)
- •1.1. Сокети, датаграми й канали зв'язку
- •1.1.1. Ініціалізація додатка й завершення його роботи
- •1.1.2. Створення й ініціалізація сокету
- •1.3. Індивідуальні завдання на роботу №1
- •Лабораторна робота № 2. Створення каналу зв'язку
- •2.1. Сторона сервера
- •2.3. Передача й прийом даних
- •2.2. Сторона клієнта
- •2.4. Додаток ServerSocket
- •2.5. Додаток ClientSocket
- •2.6. Індивідуальні завдання на роботу №2
- •Лабораторна робота № 3. Датаграммный протокол
- •3.1. Додаток ServerDSocket
- •3.2. Додаток ClientDSocket
- •3.3. Індивідуальні завдання на роботу №3
2.1. Сторона сервера
Розглянемо процедуру створення каналу зв'язку з боку сервера.
Насамперед необхідно перемкнути сокет у режим прийому для виконання очікування з'єднання із клієнтом за допомогою функції listen:
int listen(SOCKET sock, int backlog);
Через параметр sock функції необхідно передати дескриптор сокету, що буде використаний для створення каналу. Параметр backlog задає максимальний розмір черги для очікування з'єднання (можна вказувати значення від 1 до 5). Черга містить запити на установку з'єднань для кожної пари значень (адреса IP, порт). Нижче наведений список можливих кодів помилок для функції listen.
Код помилки Опис
WSANOTINITIALISED Перед використанням функції необхідно викликати функцію WSAStartup
WSAENETDOWN Збій у мережі
WSAEADDRINUSE Зазначена адреса вже використається
WSAEINPROGRESS Виконується функція, що блокує, інтерфейсу Windows Sockets
WSAEINVAL Сокет ще не був прив'язаний до адреси або вже перебуває в підключеному стані
WSAEISCONN Сокет уже перебуває в підключеному стані
WSAEMFILE Недостатньо дескрипторів файлів
WSAENOBUFS Немає місця для розміщення буфера
WSAENOTSOCK Зазначений у параметрі дескриптор не є сокетом
WSAEOPNOTSUPP Функція listen не працює із сокетом зазначеного типу
Нижче наведений приклад виклику функції listen:
if(listen(srv_socket, 1) == SOCKET_ERROR)
{
closesocket(srv_socket);
MessageBox(NULL, "listen Error", "Error", MВ_ОК);
return;
}
Далі необхідно виконати очікування з'єднання двома різними способами.
Перший спосіб полягає в циклічному виклику функції accept доти, поки не буде встановлене з'єднання. Потім можна буде приступати до обміну даними.
Функція accept має наступний прототип:
SOCKET accept(SOCKET sock, struct sockaddr FAR *addr, int FAR *addrlen);
Через параметр sock необхідно вказати дескриптор сокету, що перебуває в режимі прийому для виконання очікування.
Параметр addr повинен містити адреса буфера, у який буде записана адреса вузла, що підключився до сервера. Розмір цього буфера необхідно вказати в змінної типу int, адреса якої передається через параметр addrlen.
Якщо очікування з'єднання в циклі не викликає ентузіазму, можна запропонувати більше зручний спосіб, заснований на використанні розширення програмного інтерфейсу Windows Socket, призначеного для виконання асинхронних операцій.
Нижче наведений список можливих кодів помилок для функції accept.
Код помилки Опис
WSANOTINITIALISED Перед використанням функції необхідно викликати функцію WSAStanup
WSAENETDOWN Збій у мережі
WSAEFAULT Значення параметра addrlen менше розміру-структури адреси
WSAEINTR Робота функції була скасована за допомогою функції WSACancelBlockingCall
WSAEINPROGRESS Виконується функція, що блокує, інтерфейсу Windows Sockets
WSAEINVAL Перед викликом функції accept не була викликана функція listen
WSAEMFILE Немає доступних дескрипторів
WSAENOBUFS Установлено занадто багато з'єднань
WSAENOTSOCK Зазначений у параметрі дескриптор не є сокетом
WSAEOPNOTSUPP Даний тип сокету не можна використати при виклику функцій, орієнтованих на роботу з каналом зв'язку
WSAEWOULDBLOCK Сокет відзначений як що не блокує й у цей час немає каналів зв'язку, які потрібно встановлювати
Замість того щоб очікувати з'єднання, викликаючи в циклі функцію accept, додаток може викликати один раз функцію WSAAsyncSelect, указавши їй, що при одержанні запиту на установку з'єднання функція вікна додатка повинна одержати повідомлення
define WSA_ACCEPT (WM_USER+1)
int rc = WSAAsyncSelect(srv_socket, m_hWnd, WSA_ACCEPT, FD_ACCEPT);
if(rc == SOCKET_ERROR )
{
MessageBox("WSAAsyncSelect (Accept) Error", "Error", MB_OK);
return;
}
У цьому випадку очікування з'єднання виконується для сокету srv_socket. Останній параметр функції має значення FD_ACCEPT. Це означає, що при спробі створення каналу зв'язку функція вікна з ідентифікатором m_hWnd одержить повідомлення WSA_ACCEPT, певне в додатку.
Оброблювач цього повідомлення може виглядати, наприклад, у такий спосіб:
LRESULT CServerSocketDlg::OnWSAAccept( WPARAM wPararn, LPARAM lParam)
{
// При помилці скасовуємо надходження повідомлень
// у головне вікно додатка
if(WSAGETSELECTERROR(lParam) != 0)
{
MessageBox("accept Error","Error", MB_OK);
WSAAsyncSelect(srv_socket, m_hWnd, 0, 0);
return 1;
}
// Визначаємо розмір адреси сокету
css_len = sizeof(clientAddr);
// Дозволяємо установку з'єднання
clientSocket = accept(srv_socket, (LPSOCKADDR)&clientAddr, (int FAR *)&css_len);
if(clientSocket == INVALID_SOCKET)
{
MessageBox("Accept Error, invalid socket", "Error", MB_OK);
return 1;
}
AfxMessageBox("Client connect to server");
// Якщо на даному сокете починається передача даних від
// клієнта, у головне вікно додатка надійде
// повідомлення WSA_NETEVENT.
// Це ж повідомлення надійде при розриві з'єднання
int rc = WSAAsyncSelect(clientSocket, m_hWnd, WSA_NETEVENT, FD_READ | FD_CLOSE);
if(rc > 0)
{
MessageBox("WSAAsyncSelect Error", "Error", MB_OK);
return 1;
}
return 0L;
}
У цьому випадку оброблювач повідомлення спочатку викликає функцію accept, що виконує створення каналу передачі даних. Після цього функція WSAAsyncSelect викликається ще один раз для того, щоб установити асинхронну обробку прийому даних від вилученого клієнта, а також обробку ситуації розриву каналу зв'язку.
