Класи CAsyncSocket та CSocket теорія та приклад найпростішого сервера (частина 1)

Клас CAsyncSocket призначений для роботи із сокетами Windows. Клас є "обгорткою" для більш простої та зручної, об'єктно орієнтованої роботи з функціями Socket API.

Мінімальні дії для роботи з класом:

  1. Створити об'єкт класу викликавши конструктор;
  2. Викликати метод об'єкта Create;
  3. Викликати метод Listen (для сервера) чи Connect (для клієнта);
  4. Реалізувати передачу даних залежно від завдання.
Ініціалізація сокетів Windows.

якщо є необхідність перевіряти версію встановленої на комп'ютері бібліотеки, тоді у ф-цію AfxSocketInit необхідно передати покажчик на структуру WSADATA, в яку буде записана вся інформація про версії і т.д.

wVersion - версія специфікації Windows Sockets DLL, яка буде викликана для роботи;wHighVersion - найпізніша версія специфікації з якою дана DLL підтримує роботу, найчастіше має значення що і wVersion (за MSDN-у, для моєї ОС wVersion = 257 а wHighVersion = 514) ;szDescription - рядок який містить опис який виробник вказує для DLL (наприклад "WinSock 2.0")szSystemStatus - рядок містить інформацію про стан або конфігурацію, що отримується з DLL ( наприклад "Running");iMaxSockets - позитивне ціле число, що вказує, яка максимальна кількість сокетів, потенційно, може бути відкрита цим процесом. Значення може мати різні значення в залежності від реалізації Windows Sockets, а також від установок обладнання. Windows Sockets може надавати для роботи пул сокетів для всіх процесів системи або обмежену кількість сокетів для кожного процесу. iMaxSockets не гарантує, що таку кількість сокетів ви зможете відкрити (наприклад через запускінших додатків). Так що це значення слід розглядати як теоретично максимальну кількість сокетів, яку ви зможете відкрити в цьому процесі, в моїй ОС під час запуску змінна мала значення 32767.iMaxUdpDg - позитивне ціле число яке вказує на максимальний розмір в байтах пакета для протоколу UDT (протокол передачі датаграм). Якщо реалізація бібліотеки не накладає обмеження на розмір пакету UDP, змінна має значення 0. У багатьох реалізаціях сокетів Берклі розмір датаграми для протоколу UDP має розмір 8192 байт (при цьому датаграма при необхідності розбивається на частини). Windows Sockets визначає розмір датаграми залежно від розміру буфера для збирання пакетів. Мінімальний розмір 512 байт. Не дивлячись на розмір iMaxUdpDg недоцільно відправляти датаграми розмір яких більший за MTU (Maximum Transmission Unit максимальна одиниця передачі) для мережі. Windows Socket Api не надає можливості для визначення MTU, але воно не повинно бути менше 512 байт. (На моєму комп'ютері значення 65467).lpVendorInfo - покажчик на структуру специфікації виробника. (У моєму випадку покажчик не було встановлено).

Функція Create створює сокет та прикріплює його (attach)

Функція Listen викликає очікування надходження запитів на з'єднання

nConnectionBacklog - позитивне число від 1 до 5 визначає максимальну довжину черги запитів, що очікують з'єднання.

Функція Accept приймає з'єднання, тобто. вибирає перший у черзі сокет на з'єднання, створює новий сокет і приєднує його до rConnectedSocket

Функція Detach від'єднує хендл сокету об'єкта класу CAsyncSocket з m_hSocket та встановлює m_hSocket у NULL.

FD_READ – читання; FD_WRITE - запис; FD_OOB -отримання даних поза смугою; FD_ACCEPT - з'єднання; FD_CONNECT - результати з'єднання; FD_CLOSE – закриття сокету.

Функція GetLastError повертає код помилки для останньої невдалої операції в треді, в якому викликається.

Список кодів помилок дуже великий і наводити його немає сенсу. для кожної функції є деяка множина яка можна і потрібно обробляти, до того ж навіть при найглибшій обробці всіх помилок, для своєї програми ви скористаєтеся максимом 30% цього списку. Якщо все ж таки він необхідний скористайтеся MSDN.

Аналогічна функція GetSockNameEx, крім старих протоколів, підтримує ще й роботу з відносно новим протоколом IPv6.

Фукція Send надсилає дані на з'єднаний сокет

lpBuf - покажчик на ділянку пам'яті, в якому містяться дані для відправки; nBufLen - розмір в байтах даних, що відправляються; nFlags - комбінація MSG_DONTROUTE, MSG_OOB разом з іншими налаштуваннями сокету, визначає шлях яким буде зроблено виклик. MSG_DONTROUTE - вказує на те, що немає причин для маршрутизації даних (у Windows Sockets даний прапор може ігноруватися). MSG_OOB - надсилати керуючу інформацію окремо (тільки для SOCK_STREAM).

Праметри передані функції аналогічні Send додалися тільки два параметри, що вказують куди відправити дані. Функція SendToEx працює аналогічно до SendTo, але підтримує роботу з протоколом IPv6.

Функція ShutDown забороняє надсилання та/або прийом даних сокетом.

nHow - прапор, який вказує, які операції повинні бути недоступні. 0-отримання; 1-відправлення; 2-обидва та отримання та відправка.

nSocketType - вказує тип сокета за замовчуванням SOCK_STREAM, або може бути передано значення SOCK_DGRAM. lEvent - бітова маска, що містить комбінацію типівповідомлень які цікавлять програму. FD_READ - читання; FD_WRITE - запис; FD_OOB - отримання даних поза смугою; FD_ACCEPT - з'єднання; FD_CONNECT - результати з'єднання; FD_CLOSE – закриття сокету.

Функції, що починаються з On, викликаються при відповідній події, тобто. при події відправки (Send) викликається функція OnSend тощо. наводити їх список не буду. І так короткий курс теорії закінчено, переходимо до практики.

Почнемо з класу спадкоємця CAsyncSocket, який слухатиме порт і прийматиме з'єднання клієнтів. Об'єкт цього класу буде єдиним кожного порту який наш сервер буде слухати, тобто. приймати з'єднання (наприклад, для WEB сервера, за замовчуванням, це порт 80). Назвемо цей клас CListenSocket.

CListenSocket(); virtual void OnAccept(int nErrorCode);