W a s m

У першій частині, присвяченій основам іспользованіясокетовMSWindowsв ассемблерних програмах, ми говорили про те, що таке сокети, як вони створюються і які параметри при цьому еадаются. Тоді ж побіжно було сказано про НЕ орієнтований на з'єднання протокол UDP, який не гарантує доставку пакетів, а також черговість їх надходження до пункту призначення. У навчальному прикладі тоді використовувався наш улюблений протокол TCP. І все було у нас добре, але в кінці залишився ряд невирішених питань, зокрема, як організувати взаємний обмін між декількома комп'ютерами в мережі, як передати що-небудь відразу багатьом комп'ютерам і т.д.

Взагалі кажучи, прочитання першої частини для розуміння нинішньої зовсім не обов'язково, хоча по ходу справи я буду постійно на неї посилатися. Такі справи. Ха-ха.

Отже, ставимо завдання: є локальна мережа, скажімо, з десятка комп'ютерів, потрібно організувати обмін повідомленнями між двома будь-якими з них, і (за бажанням) між одним і всіма іншими.

Чую, чую хор підказок, що мовляв, використовуй вбудовані можливості Windows, типу:

net send 192.168.0.4 Женя шле тобі привіт!

net send Node4 Чекаю відповіді!

На це є всього два заперечення. Перше, хіба мало, що може наша операційна система або інші готові програми, ми ж хочемо навчитися писати свої програми, чи не так? А друге, не факт, що повідомлення йде від людини до людини. У загальному випадку, оператор може нічого і не знати. А то і не повинен нічого знати.

Для мене найголовнішим в постановці цієї задачі було забезпечити можливість передачі чого-небудь всім комп'ютерам мережі відразу. Уявіть, що ми написали якусь програму. Хто сказав - троян? Ні ні та ні! Ніяких троянів. Просто маленьку (дуже) бухгалтерську програму, наприклад. Яка змогла таки через деякий час оселитися на багатьох комп'ютерах нашої локальної мережі. І ось приходить призначений час, пора звести сальдо з бульдо, підвести, так би мовити, підсумок за квартал. Треба зробити все швидко і бажано одночасно. Як це зробити в рамках того матеріалу, що ми вивчили в першій частині, залишалося неясним.

Схема взаємодії мережевих протоколів.

TCP - T ransmission C ontrol P rotocol

ICMP - I nternet C ontrol M essage P rotocol (протоколобменауправляющімісообщеніямі)

Загалом, якщо малюнок нічим Вам не допоміг, не біда. Важливо зрозуміти одне, що TCP - протокол транспортного рівня, що забезпечує надійне транспортування даних між прикладними процесами, шляхом установки логічного з'єднання (виділено мною). А UDP - немає. І ще. Десь там, на прикладному рівні, в одному з порожніх прямокутників і буде перебувати наш додаток.

На цьому закінчимо вступну частину і перейдемо до розгляду того, як цим користуватися, з самого початку.

Для демонстрації всього матеріалу, як зазвичай, використовується навчальний приклад, який можна завантажити <здесь>. Пропускаємо загальну для всіх Windows додатків частина і описуємо тільки те, що стосується роботи сокетів. Спочатку необхідно ініціалізувати Windows Sockets DLL за допомогою функції WSAStartup (). яка поверне нуль в разі успішного виконання, або, в іншому випадку, один з кодів помилки. Потім при ініціалізації головного вікна програми відкриваємо сокет для прийому Повідомлень:

І якщо немає помилки, треба зберегти для подальшого використання отриманий дескриптор сокета:

Після цього, як зазвичай, треба вказати Windows посилати повідомлення заданому вікна від відкритого нами сокета:

де hSocket - дескриптор сокета
hWnd - дескриптор вікна, процедурі якого будуть надсилатися повідомлення
WM_SOCKET - повідомлення, нами ж певне в секції .const
FD_READ - маска, що задає питання, що цікавлять нас події, в даному випадку це готовність даних від сокета для читання.

або, що більш правильно, використовуйте:

Після цього наш додаток також буде запускатися, створюватися головне вікно, йому від Windows буде надіслано повідомлення WM_CREATE з усіма наслідками, що випливають ... Тільки його вікна не буде видно ні на робочому столі, ні на панелі завдань. Якщо це те, чого ви хотіли, я радий. У будь-якому випадку, продовжуємо.

Для цього перетворимо номер порту в мережевий порядок байт за допомогою спеціальної функції АPI:

Невеликий ліричний відступ, необов'язкове для розуміння сенсу цієї статті.

Номери портів для наших сокетов обговорювалися в кінці першої частини. Важко дати рекомендації з приводу того, якими вони повинні бути. Єдине, що можна сказати, це те, якими вони не можуть бути. Нерозумно намагатися використовувати номери портів, визначені для широко поширених служб, таких як:

через протоколTCP. 20, 21 - ftp; 23 - telnet; 25 - smtp; 80 - http; 139 - NetBIOS session service;

через протоколUDP. 53 - DNS; 137, 138 - NetBIOS; 161 - SNMP;

Звичайно, в складі API є спеціальна функція getservbyport (). яка по заданому номеру порту повертає ім'я відповідного йому сервісу. Вірніше, сама функція повертає покажчик на структуру, всередині якої є покажчик на це ім'я.

Викликати її можна так:

Зверніть увагу на те, що повідомляє Win32 Programmer'sReference з приводу getservbyport:

". повертає покажчик на структуру, яка розподілена Windows Sockets. Додаток ніколи не повинно намагатися змінювати цю структуру або будь-який з її компонентів. Крім того, тільки одна копія цієї структури розподілена дляпотока, так що додаток повинен скопіювати будь-яку інформацію, яка йому потрібна, перед будь-яким іншим викликом функції Windows Sockets ".

А ось і сама структура:

Є в API, так би мовити, і "парна" функція: getservbyname (). яка по імені сервісу повертає інформацію про номер використовуваного порту.

На жаль, практичної користі з цих функцій для нас витягти не вдасться. Так що, знайте, що вони є і забудьте про них.

На цьому підготовчу роботу по створенню та налагодженню приймає сокета з використанням датаграмм можна вважати закінченою. Немає необхідності встановлювати сокет в стан cлушанія порту функцією invoke listen. як ми це робили для сокета типу SOCK_STREAM в першій частині. Тепер в процедурі головного вікна нашого застосування ми можемо додати код, який буде виконуватися при надходженні повідомлення WM_SOCKET від сокета:

Тепер про те, як відкрити сокет для передачі повідомлень. Ось всі необхідні дії програми:

Коли справа доходить до передачі даних, досить зробити cледует:

Значення параметрів при виклику цієї функції APIследующіе:

Якщо при виконанні функції sendto () не виникло помилок, то вона повертає число переданих байт, інакше на виході маємо в eaxзначеніе SOCKET_ERROR.

Ось, власне, і все. У момент закриття програми необхідно закрити сокети і звільнити ресурси Sockets DLL, робиться це просто:

Для мультіпотокових додатків після WSACleanup завершуються операції з сокетами для всіх потоків.

Найважчим в цій статті було для мене вирішити, як найкраще проілюструвати використання Windows Sockets API. Один підхід ви, напевно, вже побачили, коли в єдиному додатку одночасно використовувався і сокет на прийом, і сокет на передачу повідомлень. Не менш привабливим здається й інший спосіб, коли код для одного і іншого чітко розділений, аж то того, що існує в різних додатках. Зрештою, я реалізував ще й цей спосіб, який може виявитися для розуміння початківцями дещо простіше. У другому <архиве> лежать папки:

\ SocSocDR - тестова програма, тільки приймальня частина

\ SocSocDW - відповідно, лише передає частину

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

Безетогофункціяsend () видасть SOCKET_ERROR!

Наостанок можна відзначити деякі загальні проблеми, що виникають при роботі з сокетами. Щоб обробити віконне повідомлення, що інформує про те, що змінилося стан сокета, ми, як завжди, використовували прямі повідомлення від Windows головного вікна програми. Є й інший підхід, коли створюють окремі вікна для кожного сокета.

Взагалі кажучи, централізована обробка повідомлень головним вікном - це, як здається, більш простий для розуміння метод, який, тим не менш, на практиці може додати клопоту. Якщо програмою використовується більше ніж один сокет в один і той же час, потрібно зберігати список дескрипторів сокетів. При появі повідомлення від сокетов, головна віконна процедура в списку шукає інформацію, пов'язану з цим дескриптором сокету і відправляє повідомлення про зміну стану далі в призначену для цього процедуру. Яка вже тим чи іншим способом реагує, щось там робить. Цей підхід змушує обробку мережевих завдань інтегрувати в ядро ​​програми, що ускладнює створення бібліотек втратити зв'язок із мережею. Кожен раз, коли використовуються ці мережеві функції, в головний віконний обробник додатки потрібно додавати додатковий код.

У другому методі обробки повідомлень для їх отримання додаток створює приховане вікно. Воно служить для відділення головної віконної процедури додатки від обробки мережевих повідомлень. Цей підхід може спростити головне додаток і полегшити використання наявного мережного коду в інших програмах. Негативною стороною такого підходу є надмірне використання Windows - user пам'яті, тому що для кожного створеного вікна резервується досить великий його обсяг.

Який спосіб вибрати - вирішуйте самі. І ще одне. На час експериментів, можливо, доведеться відключити ваш персональний firewall. Так, наприклад, Outpost Pro 2.1.275 у режимі навчання реагував на спробу передачі в сокет, але, коли передача вручну дозволялася, дані все одно не доходили. Ось вам і UDP. Хоча справа може бути і не в цьому. Проблем з моїм ZoneAlarmPro 5.0.590 у такій самій ситуації не було.