network programming for microsoft windows

68
Моей любимой жене, с благодарностю за терпение и понимание. — Э. Дж. Саманте — Дж. О.

Upload: pancariza

Post on 26-Nov-2014

381 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Network Programming for Microsoft Windows

Моей любимой жене,

с благодарностю за терпение и понимание.

— Э. Дж.

Саманте

— Дж. О.

Page 2: Network Programming for Microsoft Windows

NetworkProgrammingforWindows®Microsoft

®

Anthony JonesJim Ohlund

Page 3: Network Programming for Microsoft Windows

Программированиев сетях

Windows®

Э. ДжонсДж. Оланд

Microsoft®

М АС Т Е Р - К Л АС С

Москва • Санкт-Петербург • Харьков • Минск2001

Page 4: Network Programming for Microsoft Windows

УДК 004.43

ББК 32.973.26–018

Д50

Джонс Э., Оланд Дж.

Д50 Программирование в сетях Microsoft Windows. Мастер-класс. / Пер. с англ.

— Спб.: Питер; М.: Издательско-торговый дом «Русская Редакция», 2001. — 608 стр.:

ил.

ISBN 5–ХХХХ–ХХХХ—X

ISBN 5–7502–0148–1

Книга знакомит читателя с многообразием сетевых функций ОС семейства

Windows. Обсуждается разработка сетевых приложений на платформе Win32

с использованием интерфейсов программирования NetBIOS и Winsock, а так-

же распространенных протоколов. На конкретных примерах рассмотрены кли-

ент-серверная модель; установка соединения и передача данных; регистрация

и разрешение имен, в том числе применительно к Windows 2000 и Active Direc-

tory; широковещание в сети; АТМ; QoS и удаленный доступ. В приложениях со-

держится справочник команд NetBIOS (с указанием входных и выходных па-

раметров), сведения о новых функциях IP Helper, а также справочник кодов

ошибок Winsock.

Адресована как профессиональным программистам, так и новичкам, для ко-

торых станет удобным справочником и исчерпывающим пособием по исполь-

зованию сетевых функций Windows.

Состоит из 15 глав, трех приложений и предметного указателя; прилагае-

мый компакт-диск содержит примеры программ.

УДК 004.43

ББК 32.973.26-018

Подготовлено к изданию по лицензионному договору с Microsoft Corporation, Редмонд,

Вашингтон, США.

Intel — охраняемый товарный знак компании Intel Corporation. Active Directory, ActiveX,

Authenticode, BackOffice, BizTalk, JScript, Microsoft, Microsoft Press, MSDN, MSN, NetMeeting,

Outlook, Visual Basic, Win32, Windows и Windows NT являются товарными знаками или

охраняемыми товарными знаками корпорации Microsoft в США и/или других странах. Все

другие товарные знаки являются собственностью соответствующих фирм.

Все названия компаний, организаций и продуктов, а также имена лиц и события, ис-

пользуемые в примерах, вымышлены и не имеют никакого отношения к реальным компа-

ниям, организациям, продуктам, событиям и лицам, если особо не указано иное.

ISBN 0–7356–0560–2 (англ.)

ISBN 5–7502–ХХХХ—Х

ISBN 5–7502–0148–1

© Оригинальное издание на английском

языке, Microsoft Corporation, 2000

© Перевод на русский язык, Microsoft

Corporation, 2001

Page 5: Network Programming for Microsoft Windows

Оглавление

Введение XII

Ч А С Т Ь I. УСТАРЕВШИЕ СЕТЕВЫЕ API 1

ГЛАВА 1. Интерфейс NetBIOS 2Интерфейс Microsoft NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

Номера LANA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

Имена NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

Особенности NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8Основы программирования NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

Синхронный и асинхронный вызов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11Типичные процедуры NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

Сервер сеансов: модель асинхронного обратного вызова . . . . . . . . . . . . . . . . 19

Сервер сеансов: модель асинхронных событий . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

Клиент сеанса NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30Дейтаграммные операции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34Дополнительные команды NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

Проверка состояния адаптера (команда NCBASTAT) . . . . . . . . . . . . . . . . . . . . . . . 49

Команда поиска имени (NCBFINDNAME) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

Сопоставление протоколов номерам LANA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51Рекомендации по выбору платформ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

Платформа Windows CE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

Платформа Windows 9x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

Для любых платформ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

ГЛАВА 2. Перенаправитель 54Универсальные правила именования . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55Поставщик нескольких UNC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55Компоненты сетевого доступа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56Перенаправитель . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57Протокол SMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57Безопасность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Дескрипторы безопасности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Маркеры доступа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61Сетевая безопасность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

Реквизиты сеанса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61Пример . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

ГЛАВА 3. Почтовые ящики 64Подробности внедрения почтовых ящиков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

Имена почтовых ящиков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

Размеры сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

Компиляция приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Коды ошибок . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Page 6: Network Programming for Microsoft Windows

VI Оглавление

Общие сведения об архитектуре клиент-сервер . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Сервер почтовых ящиков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Клиент почтовых ящиков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70Дополнительные API-функции почтовых ящиков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72Платформа и производительность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

Правила именования «8.3» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

Неспособность отменить блокирующие запросы ввода-вывода . . . . . . . . 74

Утечки памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

ГЛАВА 4. Именованные каналы 78Детали реализации именованных каналов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

Правила именования каналов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

Режимы побайтовый и сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

Компиляция приложений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

Коды ошибок . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80Простой сервер и клиент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

Детали реализации сервера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

Усовершенствованный сервер каналов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

Детали реализации клиента . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95Другие API-вызовы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98Платформа и производительность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

Ч А С Т Ь II. ИНТЕРФЕЙС ПРИКЛАДНОГОПРОГРАММИРОВАНИЯ WINSOCK 103

ГЛАВА 5. Сетевые протоколы 104Характеристики протоколов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

Протокол, ориентированный на передачу сообщений . . . . . . . . . . . . . . . . . 104

Обмен данными, с соединением и без него . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

Надежность и порядок доставки сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106Корректное завершение работы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

Широковещание данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

Многоадресное вещание . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

Качество обслуживания . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

Фрагментарные сообщения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

Маршрутизация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

Другие характеристики . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109Поддерживаемые протоколы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

Сетевые протоколы, поддерживаемые Win32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

Сетевые протоколы в Windows CE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112Информация о протоколе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112Сокеты Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

Простые сокеты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118Информация о платформах . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

Winsock и модель OSI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119Выбор соответствующего протокола . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

Page 7: Network Programming for Microsoft Windows

Оглавление VII

ГЛАВА 6. Семейства адресов и разрешение имен 121Протокол IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

Протокол TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

Протокол UDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122Адресация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

Порядок байт . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

Создание сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

Разрешение имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125Инфракрасные сокеты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

Адресация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

Разрешение имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

Нумерация IrDA-устройств . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

Опрос IAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

Создание сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

Параметры сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133Протоколы IPX/SPX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

Адресация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

Создание сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

Разрешение имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137Протоколы NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

Адресация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

Создание сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139Протокол AppleTalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

Адресация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

Создание сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148Протокол ATM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Адресация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

Создание сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

Привязка сокета к SAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154

Разрешение имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155Дополнительные функции Winsock 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

ГЛАВА 7. Основы Winsock 157Инициализация Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157Проверка и обработка ошибок . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159Протоколы с установлением соединения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

Серверные API-функции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

API-функции клиента . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

Передача данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

Потоковые протоколы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

Завершение сеанса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

Пример . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176Протоколы, не требующие соединения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

Приемник . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

Отправитель . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

Протоколы, ориентированные на передачу сообщений . . . . . . . . . . . . . . . 188

Освобождение ресурсов сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

Пример . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

Page 8: Network Programming for Microsoft Windows

VIII Оглавление

Дополнительные функции API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

Функция getpeername . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

Функция getsockname . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

Функция WSADuplicateSocket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

Функция TransmitFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199Для платформы Windows CE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200Другие семейства адресов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

Протокол AppleTalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

Инфракрасные сокеты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202

Интерфейс с NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202

Протокол IPX/SPX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203

Протокол ATM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

ГЛАВА 8. Ввод-вывод в Winsock 205Режимы работы сокетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206

Блокирующий режим . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206

Неблокирующий режим . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208Модели ввода-вывода сокетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

Модель select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

Модель WSAAsyncSelect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

Модель WSAEventSelect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217

Модель перекрытого ввода-вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

Модель портов завершения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234Сравнение моделей ввода-вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243

Клиент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243

Сервер . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243

ГЛАВА 9. Параметры сокета и команды управлениявводом-выводом 245Параметры сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

Уровень SOL_SOCKET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

Уровень параметров SOL_APPLETALK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255

Уровень параметров SOL_IRLMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258

Уровень параметров IPPROTO_IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262

Уровень параметров IPPROTO_TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

Уровень параметров NSPROTO_IPX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268Функции Ioctlsocket и WSAIoctl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

Стандартные ioctl-команды . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273

Другие ioctl-команды . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

Ioctl-команды Secure Socket Layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282

Ioctl-команды для ATM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285

ГЛАВА 10. Регистрация и разрешение имен 286Введение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286Модели пространства имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287Перечень пространств имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287Регистрация службы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289

Page 9: Network Programming for Microsoft Windows

Оглавление IX

Определение класса службы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289

Регистрация службы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293Запрос к службе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299

Создание запроса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301

Запрос к DNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307

ГЛАВА 11. Многоадресная рассылка 308Семантика многоадресной рассылки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308

Свойства многоадресной рассылки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311Многоадресная рассылка в сетях IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311

Протокол IGMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312

Листовые узлы IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313

Реализация IP-рассылки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314Многоадресная рассылка в сетях ATM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314

Листовые узлы ATM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315

Корневые узлы ATM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315Многоадресная рассылка с использованием Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . 316

Рассылка средствами Winsock 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316

Рассылка средствами Winsock 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323

Общие параметры Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340

Ограничение многоадресной рассылки при удаленном доступе . . . . . 342Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342

ГЛАВА 12. Качество обслуживания 343Введение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343

Протокол RSVP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344

Сетевые компоненты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344

Компоненты приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346

Компоненты политики безопасности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347QoS и Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348

Структуры QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349

Функции, вызывающие QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352Завершение QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356

Объекты, относящиеся к поставщику . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356Программирование QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365

RSVP и типы сокетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366

Уведомления QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368

Шаблоны QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371Примеры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373

Одноадресный TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373

Одноадресный UDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394

Многоадресный UDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395ATM и QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397

ГЛАВА 13. Простые сокеты 398Создание простого сокета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398Протокол ICMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399

Пример Ping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401

Page 10: Network Programming for Microsoft Windows

X Оглавление

Программа Traceroute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411Протокол IGMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412Использование IP_HDRINCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424

ГЛАВА 14. Интерфейс Winsock 2 SPI 425Основы SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426

Соглашения SPI об именах . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426

Соответствие функций Winsock 2 API и SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426Поставщики транспортной службы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427

Функция WSPStartup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428

Описатели сокетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433

Поддержка модели ввода-вывода Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435

Модель select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

Расширенные функции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446

Установка поставщиков транспортной службы . . . . . . . . . . . . . . . . . . . . . . . . . 447Поставщики службы пространства имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453

Установка поставщика пространства имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453

Реализация пространства имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455

Пример . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461Отладочные функции отслеживания Winsock 2 SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467

ГЛАВА 15. Элемент управления Winsock 468Свойства . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468Методы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470События . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471Пример (UDP-приложение) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472

Пересылка UDP-сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476

Прием UDP-сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477

Получение информации от элемента Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . 478

Запуск UDP-приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478

Состояние UDP-сокетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479Пример (TCP-приложение) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480TCP-сервер . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487

TCP-клиент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489

Получение информации о состоянии элемента

управления Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490

Запуск TCP-приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490

Состояние TCP-сокетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491Ограничения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491Типичные ошибки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493

Ошибка Local address in use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493

Ошибка Invalid Operation at Current State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493Элемент управления Windows CE Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494

Пример . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494

Проблема с элементом управления

VBCE Winsock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499

Page 11: Network Programming for Microsoft Windows

Оглавление XI

Ч А С Т Ь III. СЛУЖБА УДАЛЕННОГОДОСТУПА (RAS) 500

ГЛАВА 16. Клиент службы RAS 501Компиляция и компоновка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502Структуры данных и вопросы совместимости платформ . . . . . . . . . . . . . . . . . . . . . . 503Обновление DUN 1.3 и Windows 95 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503Функция RasDial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503

Синхронный режим . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506

Асинхронный режим . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507

Уведомление о состоянии . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512

Завершение соединения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513Телефонный справочник . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514

Добавление записей в телефонный справочник . . . . . . . . . . . . . . . . . . . . . . . . . 522

Переименование записи телефонного справочника . . . . . . . . . . . . . . . . . . . 525

Удаление записей из телефонного справочника . . . . . . . . . . . . . . . . . . . . . . . . 525

Перечисление записей телефонного справочника . . . . . . . . . . . . . . . . . . . . . 526

Управление реквизитами пользователя . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527

Многоканальные подзаписи телефонного справочника . . . . . . . . . . . . . . . 529Управление соединением . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534

Приложение A. Перечень команд NetBIOS 535

Приложение В. Вспомогательные функции IP 549Возможности утилиты Ipconfig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549

Освобождение и обновление IP-адресов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553

Изменение IP-адреса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554Возможности утилиты Netstat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554

Получение таблицы TCP-соединений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555

Получение таблицы прослушиваемых портов UDP . . . . . . . . . . . . . . . . . . . . . 556

Получение статистики о протоколе IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557Возможности утилиты Route . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561

Получение таблицы маршрутов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562

Добавление маршрута . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564

Удаление маршрута . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565Утилита ARP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565

Добавление записи ARP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567

Удаление записи ARP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567

Приложение C. Коды ошибок Winsock 568

От авторов 576

Предметный указатель 577

Page 12: Network Programming for Microsoft Windows

Введение

Перед вами книга, посвященная сетевым функциям Windows 9х, NT 4, 2000

и CE. Она предназначена в первую очередь опытным программистам и спе-

циалистам по сетям. Впрочем, для начинающих она может послужить полез-

ным справочным пособием и даже вводным курсом по сетевым функциям.

О чем эта книгаВ книге три части, посвященные работе в сети с применением NetBIOS и пе-

ренаправителя Windows, Winsock и RAS соответственно.

В главе 1 рассматривается NetBIOS. По нашему опыту работы в команде

поддержки разработчиков Microsoft мы знаем, что многие компании все еще

используют эту технологию. Между тем, до сих пор нет адекватного руковод-

ства по написанию приложений NetBIOS для платформ Win32. В главе 1 так-

же приводятся методы написания надежных и переносимых приложений (с

учетом, что многие разработчики используют NetBIOS именно для связи с

устаревшими системами).

Главы 2–4 посвящены перенаправителю Windows, почтовым ящикам и

именованным каналам. Как вы знаете, почтовые ящики и именованные ка-

налы основаны на перенаправителе. Мы решили посвятить перенаправите-

лю целую главу, чтобы предоставить читателю базовую информацию о том,

как три эти технологии соотносятся друг с другом. Почтовые ящики — это

ненадежный однонаправленный ориентированный на сообщения интер-

фейс прикладного программирования, не зависимый от доступных в систе-

ме протоколов. Именованные каналы обладают более широкими возможно-

стями, обеспечивая надежную двустороннюю дейтаграммную или поточную

передачу данных. Эти каналы используют средства безопасности Windows

NT за счет перенаправителя, на что не способен ни один другой сетевой API-

интерфейс.

Вторая часть книги посвящена API-интерфейсу Winsock. Глава 5 — это

введение в Winsock, где рассказывается о наиболее распространенных про-

токолах Winsock. Все приложения Winsock должны создавать сокет для осу-

ществления связи. В этой главе мы приводим основную информацию о воз-

можностях каждого протокола, а в главе 6 — подробное описание, как со-

здать сокет и разрешить имя для каждого типа протокола.

В главе 7 — самое интересное. Здесь мы представляем базовую модель про-

граммирования клиент-сервер и описываем большинство функций Winsock,

которые относятся к установлению и приему связи, передаче данных и т. п.

Далее, в главе 8 рассказывается о методах ввода-вывода в Winsock. Так как глава

7 задумывалась как введение в указанную тему, в ней обсуждаются только про-

стейшие методы ввода-вывода. В главе 8, напротив, эти методы описаны под-

Page 13: Network Programming for Microsoft Windows

ГЛАВА 9 Введение XIII

робно. Если вы новичок в работе с Winsock, то главы 5–7 помогут вам овла-

деть основами использования этого API-интерфейса.

Остальные главы этой части книги посвящены особым аспектам и воз-

можностям Winsock. Параметры сокетов и команды управления вводом-вы-

водом рассмотрены в главе 9. Именно здесь вы найдете описание

большинства команд, влияющих на работу сокета или даже протокола. На-

деемся, эта глава будет полезна, как в учебных, так и в справочных целях.

В главе 10 рассмотрена регистрация и разрешение имен служб в адреса

базового протокола в Winsock 2. Это независимый от протокола метод. Рас-

пространение Windows 2000 и Active Directory придает данной главе особую

значимость.

Глава 11 посвящена связи «точка — много точек», включая многоадресное

IP- вещание и ATM. В главе 12 описана захватывающая технология — Quality

of Service (QoS), позволяющая гарантировать выделение пропускной способ-

ности сети для приложений. В главе 13 рассказывается о простых IP-соке-

тах: мы рассматриваем, как приложения Winsock могут использовать их для

работы с протоколами ICMP и IGMP, а также другие аспекты программиро-

вания при помощи простых сокетов.

В главе 14 описан интерфейс поставщика службы для Winsock — средства,

при помощи которого программист может задать уровень между Winsock и

поставщиками служб более низких уровней (например, TCP/IP) для управ-

ления работой сокета и протокола, регистрацией и разрешением имен. Этот

сложный инструмент позволяет расширить функциональность Winsock.

И наконец, в главе 15 обсуждается элемент управления Microsoft Visual

Basic для Winsock. Мы решили включить эту главу в книгу, так как убедились,

что многие разработчики до сих пор полагаются на Visual Basic и этот эле-

мент. Функциональность элемента Winsock ограничена и не позволяет ис-

пользовать дополнительные новые свойства Winsock, но он незаменим для

тех, кому требуется простая и легкая в использовании сетевая связь в Visual

Basic.

Часть III посвящена клиентскому серверу удаленного доступа (Remote

Access Server, RAS). Мы решили включить в книгу главу о RAS из-за популяр-

ности Интернета и широкого распространения коммутируемого доступа к

нему. Возможность коммутируемого доступа в сетевом приложении очень

полезна, так как упрощает работу пользователя с программой. То есть конеч-

ному пользователю не придется думать, как установить соединение, чтобы

работать с сетевым приложением.

В конце книги — три приложения. Приложение А — справочник по ко-

мандам NetBIOS, который, по нашему мнению, для программистов бесценен.

В нем перечислены параметры ввода и вывода для каждой команды. В при-

ложении B описаны новые вспомогательные функции IP, выдающие полез-

ную информацию о сетевой конфигурации текущего компьютера. Приложе-

ние C — справочник по кодам ошибок Winsock с подробным описанием от-

дельных ошибок и возможных причин их возникновения.

Page 14: Network Programming for Microsoft Windows

XIV ВведениеОСТЬ

Мы надеемся, что наша работа станет для вас ценным учебным и справоч-

ным пособием. Думаем, что это наиболее полная книга о сетевом програм-

мировании для Windows.

Как пользоваться прилагаемымкомпакт-дискомВ тексте книги мы часто приводим примеры программ, иллюстрирующие ра-

боту с обсуждаемыми сетевыми API-интерфейсами. Эти примеры записаны на

прилагаемый компакт-диск. Для их установки вставьте компакт-диск в диско-

вод, и программа Autorun запустит программу установки. Программу установ-

ки можно также инициировать вручную, запустив файл PressCD.exe из корне-

вого каталога компакт-диска. Вы вправе установить образцы кода на компь-

ютер или работать с ними прямо с компакт-диска (из папки Examples\Chap-

ters\Chapter XX).

ПРИМЕЧАНИЕ Для работы с компакт-диском необходима 32-битная

ОС Windows.

Наряду с примерами программ в состав компакт-диска ыключена послед-

няя версия Microsoft Platform SDK. Мы сделали это, потому что многие из

наших примеров рассчитаны на современные заголовочные файлы и биб-

лиотеки, которые появились только после Windows 2000 Beta 3.

ПоддержкаАвторы приложили все усилия, чтобы обеспечить точность содержания кни-

ги и прилагаемого к ней компакт-диска. Издательство Microsoft Press публи-

кует постоянно обновляемый список исправлений и дополнений к своим

книгам по адресу http://mspress.microsoft.com/support/.

Многие определения функций и таблицы в книге адаптированы или пе-

реизданы с разрешения и при активном участии группы документирования

Microsoft Platform SDK. Часть материала основана на предварительно разра-

ботанной документации и может претерпеть изменения. Информацию, об-

новления и исправления ошибок по последней версии SDK см. на Web-

узле MSDN по адресу: http://msdn.microsoft.com/developer/sdk/platform.asp.

Если все же у вас возникнут вопросы или вы захотите поделиться свои-

ми предложениями или комментариями, обращайтесь в издательство Mic-

rosoft Press по одному из этих адресов:

[email protected]

Microsoft Press

Attn: Network Programming for Microsoft Windows Editor

One Microsoft Way

Redmond, WA 98052-6399

Page 15: Network Programming for Microsoft Windows

Ч А С Т Ь I

УСТАРЕВШИЕСЕТЕВЫЕ API

Первая часть издания посвящена сетевому интерфейсу NetBIOS, перенапра-

вителю и типам использующих его сетевых соединений. Хотя в книге в ос-

новном обсуждается программирование средствами Winsock, мы включили

в нее часть I, так как устаревшие сетевые API имеют некоторые преимуще-

ства перед Winsock.

В главе 1 рассматривается интерфейс NetBIOS, который, как и Winsock,

является независимым от протокола сетевым API. NetBIOS обеспечивает

асинхронные вызовы, а также совместимость со старыми операционными

системами типа OS/2, DOS и др. В главе 2 обсуждается перенаправитель, с

которым связаны две следующие темы: почтовые ящики (глава 3) и имено-

ванные каналы (глава 4). Перенаправитель обеспечивает независимый от

транспорта ввод-вывод файлов. Почтовые ящики — это простой интерфейс,

который помимо прочего поддерживает широковещание и однонаправлен-

ное взаимодействие между компьютерами под управлением Windows. Нако-

нец, именованные каналы дают возможность использовать двусторонний ка-

нал связи, который поддерживает функции безопасности Windows.

Page 16: Network Programming for Microsoft Windows

Г Л А В А 1

Интерфейс NetBIOS

Network Basic Input/Output System (NetBIOS) — стандартный интерфейс

прикладного программирования (application programming interface, API),

разработанный Sytek Corporation для IBM в 1983 г. NetBIOS определяет про-

граммный интерфейс для сетевой связи, но не обусловливает физический

способ передачи данных по сети. В 1985 г. IBM предприняла попытку сфор-

мировать цельный протокол — создала NetBIOS Extended User Interface (Net-

BEUI), интегрированный с интерфейсом NetBIOS. Программный интерфейс

NetBIOS вскоре приобрел такую популярность, что поставщики ПО начали

реализовать его для других протоколов, таких как TCP/IP и IPX/SPX. В на-

стоящее время NetBIOS используют платформы и приложения во всем мире,

включая многие компоненты Windows NT, Windows 2000, Windows 95 и

Windows 98.

ПРИМЕЧАНИЕ Windows CE не дает возможности использовать Net-

BIOS API, хотя поддерживает транспортный протокол TCP/IP, имена

NetBIOS и механизм их разрешения.

В Win32 интерфейс NetBIOS обеспечивает обратную совместимость со

старыми приложениями. В этой главе обсуждаются главные принципы про-

граммирования с помощью NetBIOS, начиная с имен NetBIOS и номеров

LANA. Мы рассмотрим основные услуги, предлагаемые NetBIOS, включая те,

что обеспечивают связь с установлением соединения или без такового (дей-

таграммные). В каждом разделе будет приведен простой клиент-серверный

пример. Завершит главу обзор типичных ошибок. В приложении A вы най-

дете список команд NetBIOS с обязательными параметрами и кратким опи-

санием.

Сетевая модель OSIМодель Open Systems Interconnect (OSI) обеспечивает высокоуровне-

вое представление сетевых систем. Ее семь уровней полностью опи-

сывают фундаментальные сетевые концепции: от приложения до спо-

соба физической передачи данных. Вот эти уровни:

L прикладной — предоставляет пользовательский интерфейс для

передачи данных между программами;

L представительский — форматирует данные;

L сеансовый — управляет связью между двумя узлами;

Page 17: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 3

L транспортный — обеспечивает передачу данных (надежную или

ненадежную);

L сетевой — поддерживает механизм адресации между узлами и

маршрутизацию пакетов данных;

L канальный — управляет взаимодействием между узлами на физи-

ческом уровне; отвечает за группировку данных, передаваемых по

физическому носителю;

L физический — физический носитель, ответственный за переда-

чу данных в виде электрических сигналов.

В этой модели NetBIOS относится к сеансовому и транспортному

уровням.

Интерфейс Microsoft NetBIOSКак уже упоминалось, существуют реализации NetBIOS API для разных сете-

вых протоколов, что делает интерфейс независимым от протокола. Иначе

говоря, если вы разработали приложение согласно спецификации NetBIOS,

оно может использовать протоколы TCP/IP, NetBEUI или даже IPX/SPX. Эта

полезная особенность позволяет корректно написанному приложению Net-

BIOS выполняться почти на любом компьютере, независимо от физической

сети. Однако есть несколько нюансов. Чтобы два приложения NetBIOS мог-

ли связаться друг с другом по сети, они должны выполняться на рабочих

станциях, имеющих по крайней мере один общий транспортный протокол.

Например, если на компьютере Джона установлен только TCP/IP, а на ком-

пьютере Мэри — только NetBEUI, приложения NetBIOS на компьютере Джо-

на не смогут связаться с приложениями на компьютере Мэри.

Кроме того, только определенные протоколы реализуют интерфейс Net-

BIOS. Например, Microsoft TCP/IP и NetBEUI делают это по умолчанию, а IPX/

SPX — нет. Поэтому Microsoft предлагает реализующую этот интерфейс вер-

сию IPX/SPX, что следует учесть при проектировании сети. При установке

протоколов обычно видно, поддерживает ли версия протокола IPX/SPX воз-

можности NetBIOS. Например, вместе с Windows 2000 поставляется NWLink

IPX/SPX/NetBIOS Compatible Transport Protocol — то, что этот протокол под-

держивает NetBIOS, прямо вытекает из его названия. В Windows 95 и Win-

dows 98 в окне свойств протокола IPX/SPX есть флажок, с помощью которо-

го включается поддержка NetBIOS для IPX/SPX.

Важно, что NetBEUI — немаршрутизируемый протокол. Если между кли-

ентом и сервером есть маршрутизатор, приложения на этих компьютерах не

смогут связаться. Маршрутизатор будет отбрасывать пакеты по мере их при-

ема. TCP/IP и IPX/SPX — маршрутизируемые протоколы и не имеют такого

ограничения. Так что если вы твердо запланировали использовать NetBIOS,

задействуйте в сети по крайней мере один из маршрутизируемых транспор-

тных протоколов. Характеристики протоколов и рекомендации по их выбо-

ру мы приводим в главе 6.

Page 18: Network Programming for Microsoft Windows

4 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

Номера LANAКакое отношение имеют транспортные протоколы к NetBIOS с точки зре-

ния программирования? Ключ к пониманию NetBIOS — номера сетевых

адаптеров (LAN Adapter, LANA). В первоначальных реализациях NetBIOS

каждому физическому сетевому адаптеру присваивалось уникальное значе-

ние — номер LANA. В Win32 это стало проблематичным, так как рабочая

станция может иметь и множество сетевых протоколов, и множество плат

сетевого интерфейса.

Номер LANA соответствует уникальным сочетаниям сетевого адаптера с

транспортным протоколом. Так, если рабочая станция имеет две сетевых

платы и два поддерживающих NetBIOS транспорта (например, TCP/IP и

NetBEUI), будет присвоено четыре номера LANA. Номера могут соответство-

вать сочетаниям адаптера с протоколом примерно следующим образом:

L 0 — «TCP/IP — сетевой адаптер 1»;

L 1 — «NetBEUI — сетевой адаптер 1»;

L 2 — «TCP/IP — сетевой адаптер 2»;

L 3 — «NetBEUI — сетевой адаптер 2».

Номера LANA лежат в диапазоне от 0 до 9, и операционная система на-

значает их без какого-либо определенного порядка. Кроме LANA 0, который

имеет особый смысл — это номер «по умолчанию». Когда появился интер-

фейс NetBIOS, большинство операционных систем поддерживало един-

ственный номер LANA и многие приложения были жестко запрограммиро-

ваны на работу только с LANA 0. Для обратной совместимости вы можете

вручную назначить LANA 0 конкретному протоколу.

В Windows 95 и Windows 98 можно открыть диалоговое окно свойств се-

тевого протокола с помощью значка Network в Control Panel. Выберите вклад-

ку Configuration в диалоговом окне Network, затем из списка компонентов —

сетевой протокол и щелкните кнопку Properties. Вкладка Advanced диалогово-

го окна свойств для каждого протокола, поддерживающего NetBIOS, содержит

флажок Set This Protocol To Be The Default Protocol. Пометка флажка пере-

страивает привязки протоколов так, чтобы протоколу по умолчанию был

назначен LANA 0. Этот флажок можно пометить только для одного прото-

кола. Поскольку Windows 95 и Windows 98 поддерживают Plug-and-Play, не

требуется явно задавать приоритет протоколов.

Windows NT 4 допускает большую гибкость в установке NetBIOS. На вклад-

ке Services диалогового окна Network выберите NetBIOS Interface из списка

Network Services и щелкните кнопку Properties. В диалоговом окне NetBIOS

Configuration вы можете явно назначить номера LANA всем сочетаниям се-

тевого интерфейса с транспортным протоколом. В этом диалоговом окне

сетевой интерфейс определяется именем его драйвера. Впрочем, имена про-

токолов не всегда говорят сами за себя. На рис. 1-1 показано диалоговое окно

NetBIOS Configuration. Оно свидетельствует: на компьютере установлено два

сетевых адаптера и три транспортных протокола — TCP/IP (NetBT), NetBEUI

(Nbf) и IPX/SPX (NwlnkNb). Щелкнув кнопку Edit, вы можете вручную назна-

чить номера LANA для отдельных протоколов.

Page 19: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 5

Рис. 1-1. Диалоговое окно NetBIOS Configuration

Windows 2000 также позволяет напрямую назначать номера LANA. В Cont-

rol Panel щелкните значок Network And Dial-up Connections. Далее выберите

в меню Advanced команду Advanced Settings и в открывшемся диалоговом

окне настройте параметры на вкладке LANA numbers.

При разработке устойчивого приложения NetBIOS всегда пишется код,

который может обрабатывать соединения на любом номере LANA. Предпо-

ложим, Мэри пишет серверное приложение NetBIOS, которое слушает кли-

ентов на LANA 2. На компьютере Мэри LANA 2 соответствует протоколу TCP/

IP. Далее Джон решает написать клиентское приложение для связи с серве-

ром Мэри, так что его приложение будет связываться через LANA 2 на его

рабочей станции; однако, LANA 2 на компьютере Джона соответствует Net-

BEUI. Приложения не смогут связаться друг с другом, хотя им доступны про-

токолы TCP/IP и NetBEUI. Чтобы устранить это несоответствие, серверное

приложение Мэри должно слушать клиентские соединения на каждом дос-

тупном номере LANA на рабочей станции Мэри. Аналогично, клиентское

приложение Джона должно пытаться связаться на каждом номере LANA, до-

ступном на его компьютере. Так Мэри и Джон смогут гарантировать успех

связи их приложений. Конечно, наличие кода, который может обрабатывать

соединения на любом номере LANA не означает, что этот код будет работать,

если у двух компьютеров не найдется ни одного общего протокола.

Имена NetBIOSТеперь перейдем к именам NetBIOS. Процесс — или, если угодно, приложе-

ние — регистрирует имя на каждом номере LANA, с которым ему требуется

связаться. Имя NetBIOS имеет длину 16 символов; 16-й символ зарезерви-

рован для специальных целей. При добавлении имени в таблицу имен, вы

должны очистить буфер имен. В среде Win32 каждый процесс имеет табли-

цу имен NetBIOS для каждого доступного номера LANA. Добавление имени

для LANA 0 означает, что приложение доступно только клиентам, соединяю-

щимся на этом LANA 0. Максимально к каждому номеру LANA могут быть

добавлены 254 имени, они пронумерованы от 1 до 254 (0 и 255 зарезерви-

Page 20: Network Programming for Microsoft Windows

6 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

рованы для системы). Впрочем, каждая ОС задает максимальный номер по

умолчанию, меньший 254. Вы вправе его изменить при переопределении

каждого номера LANA.

Есть два типа имен NetBIOS: уникальное и групповое. Никакой другой

процесс в сети не может зарегистрировать уже имеющееся уникальное имя:

будет выдана ошибка дублирования имени. Как вам, наверное, известно, име-

на компьютеров в сетях Microsoft — имена NetBIOS. Когда компьютер загру-

жается, он регистрирует свое имя на локальном сервере Windows Internet

Naming Server (WINS), который сообщает об ошибке, если другой компью-

тер уже использует то же имя. Сервер WINS поддерживает список всех заре-

гистрированных имен NetBIOS.

Вместе с именем могут храниться и сведения о протоколе. Например, в

сетях TCP/IP WINS запоминает IP-адрес компьютера, зарегистрировавшего

имя NetBIOS. Если сеть сконфигурирована без сервера WINS, компьютеры

проверяют, нет ли в сети такого же имени, путем широковещательной рас-

сылки сообщения. Если никакой другой компьютер не оспаривает сообще-

ние, сеть позволяет отправителю использовать заявленное имя.

Групповые имена используются, чтобы отправлять или, наоборот, полу-

чать данные, предназначенные для множества получателей. Имя группы не

обязательно должно быть уникальным. Групповые имена используются для

многоадресной рассылки.

16-й символ в именах NetBIOS определяет большинство сетевых служб

Microsoft. Имена служб и групп для WINS-совместимых компьютеров сервер

WINS регистрирует напрямую, а для регистрации имен других компьютеров

применяется широковещание по локальной подсети. Чтобы получить ин-

формацию о зарегистрированных на локальном (или удаленном) компью-

тере именах NetBIOS, используйте утилиту Nbtstat. В табл. 1-1 приведены све-

дения о зарегистрированных именах NetBIOS, которые команда Nbtstat –n

выдала для пользователя Davemac, вошедшего в компьютер, конфигуриро-

ванный как основной контроллер домена и работающий под управлением

Windows NT Server вместе с Internet Information Server.

Табл. 1-1. Таблица имен NetBIOS

Имя 16-й байт Тип имени Служба

DAVEMAC1 <00> Уникальное Имя службы рабочей станции

DAVEMAC1 <20> Уникальное Имя службы сервера

DAVEMACD <00> Групповое Имя домена

DAVEMACD <1C> Групповое Имя контроллера домена

DAVEMACD <1B> Уникальное Имя координатора сети

DAVEMAC1 <03> Уникальное Имя отправителя

Inet~Services <1C> Групповое Групповое имя Internet Information

Server

IS~DAVEMAC1 <00> Уникальное Уникальное имя Internet Information

Server

DAVEMAC1+++++++ <BF> Уникальное имя сетевого монитора

Page 21: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 7

Утилита Nbtstat устанавливается вместе с протоколом TCP/IP. Она может

также опрашивать таблиц имен на удаленных компьютерах, используя пара-

метр –a с именем удаленного компьютера или параметр –A с его IP-адресом.

Перечислим стандартные значения 16-го байта, добавляемые в конец уни-

кальных NetBIOS-имен компьютеров разными сетевыми службами Microsoft:

L <00> — имя службы рабочей станции (NetBIOS-имя компьютера);

L <03> — имя службы сообщений, используемое при получении и отправ-

ке сообщений; зарегистрировано сервером WINS для службы сообщений

на клиенте WINS и обычно добавляется в конец имени компьютера и во-

шедшего в систему пользователя;

L <1B> — имя координатора сети (master browser) домена; определяет ос-

новной контроллер домена и указывает, каких клиентов и других обозре-

вателей использовать для контакта с координатором сети домена;

L <06> — серверная служба удаленного доступа (RAS);

L <1F> — служба сетевого динамического обмена данными (Network Dy-

namic Data Exchange, NetDDE);

L <20> — имя службы на сервере, используемое для предоставления точек

подключения к общим файлам;

L <21> — клиент RAS;

L <BE> — агент сетевого монитора;

L <BF> — утилита Network Monitor (Сетевой монитор).

А теперь перечислим заданные по умолчанию символы 16-го байта, до-

бавляемые в конец обычно используемых групповых имен NetBIOS.

L <1C> — групповое имя домена, содержащее список определенных адре-

сов компьютеров, которые его зарегистрировали. Контроллер домена это

имя регистрирует. WINS обрабатывает его как доменную группу: каждый

член группы должен индивидуально обновить свое имя или будет исклю-

чен. Доменная группа ограничена 25 именами. Если в результате репли-

кации статическое 1C-имя конфликтует с динамическим 1C-именем на

другом сервере WINS, для соответствующих участников добавляется ком-

бинированная запись, которая помечается как статическая. Если запись

статическая, члены группы не должны обновлять свои IP-адреса.

L <1D> — имя координатора сети (master browser), используемое клиента-

ми для обращения к нему. В подсети может быть лишь один координатор.

Серверы WINS возвращают положительный ответ на регистрацию име-

ни домена, но не сохраняют это имя в своих базах данных. Если компью-

тер посылает запрос на имя домена серверу WINS, тот возвращает отри-

цательный ответ. Если компьютер, сделавший запрос, сконфигурирован

как h- или m-узел, он затем выполняет широковещательную рассылку зап-

роса имени, чтобы разрешить его. Тип узла определяет способ разреше-

ния имени клиентом. Клиенты, сконфигурированные для разрешения в

режиме b-узла, выполняют широковещательную рассылку пакетов для

оповещения о себе и разрешения имен NetBIOS. При разрешении в ре-

Page 22: Network Programming for Microsoft Windows

8 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

жиме p-узла связь с сервером WINS осуществляется в стиле «точка — точ-

ка». При разрешении имен в режиме m-узла (смешанном) сначала задей-

ствуется режим b-узла, а затем при необходимости — режим p-узла. Пос-

ледний метод разрешения — h-узел (гибридный). В этом режиме снача-

ла применяется регистрация и разрешение в режиме p-узла, а в случае

неудачи — в режиме b-узла. По умолчанию в Windows используется ре-

жим h-узла.

L <1E> — обычное групповое имя. Обозреватели могут выполнять широко-

вещательную рассылку для данного имени и слушать на нем, чтобы выб-

рать координатора сети. Эти широковещательные рассылки эффективны

лишь в локальной подсети и не ретранслируются маршрутизаторами.

L <20> — имя Интернет-группы. Регистрируется серверами WINS, чтобы

идентифицировать группы компьютеров в административных целях. На-

пример, можно зарегистрировать групповое имя «printersg» для иденти-

фикации административной группы серверов печати.

L _MSBROWSE_ — добавляется в конец имени домена вместо 16-го симво-

ла. Это имя широковещательно рассылается по локальной подсети, что-

бы сообщить о домене другим ее координаторам.

Такое количество спецификаторов может казаться чрезмерным: скорее

всего, вам не потребуется использовать их в именах NetBIOS, но все же при-

мите их к сведению. Во избежание случайных коллизий между именами

NetBIOS не используйте спецификаторы уникальных имен. Еще более осто-

рожно отнеситесь к групповым именам: если ваше имя будет противоречить

существующему групповому имени, ошибка выдана не будет, и вы начнете

получать данные, предназначенные для кого-то другого.

Особенности NetBIOSNetBIOS предлагает и требующие логического соединения службы, и служ-

бы без установления соединения (дейтаграммные). Первые позволяют двум

объектам устанавливать сеанс или виртуальный канал между ними. Сеанс —

двусторонний коммуникационный поток, по которому объекты обменива-

ются сообщениями. Требующие сеанса службы гарантируют доставку любых

данных между двумя конечными точками. Сервер обычно регистрирует себя

под определенным известным именем, и клиенты ищут это имя, чтобы свя-

заться с сервером. Применительно к NetBIOS, процесс сервера добавляет его

имя в таблицу имен для каждого номера LANA, с которым требуется связь.

Клиенты на других компьютерах преобразуют имя службы в имя компьюте-

ра и затем запрашивают соединение у серверного процесса. Как видите, для

установления такой цепочки необходимо предварительно выполнить опре-

деленные действия, поэтому инициализация соединения связана с некото-

рыми издержками. При установлении сеанса гарантируется доставка паке-

тов и их порядок, хотя связь и основана на сообщениях. То есть если под-

ключенный клиент направит команду чтения, сервер вернет только один

пакет данных в потоке, даже если клиент обеспечил буфер для приема не-

скольких пакетов.

Page 23: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 9

При использовании служб, не требующих логического соединения (дей-

таграммных), сервер регистрируется под конкретным именем, и клиент про-

сто собирает данные и посылает их в сеть, не устанавливая заранее никако-

го соединения. Клиент направляет данные на NetBIOS-имя серверного про-

цесса. Дейтаграммные службы эффективнее, поскольку не тратят время и

ресурсы на установление соединения.

С другой стороны, дейтаграммные службы не дают гарантий доставки и

порядка сообщений. Например, клиент отправляет тысячи байтов данных на

сервер, который два дня назад был остановлен из-за отказа. Отправитель ни-

когда не получит никаких уведомлений об ошибке, если только не ожидает

ответа от сервера (если в течение достаточно длительного периода време-

ни нет отклика, то можно понять, что что-то не так).

Основы программирования NetBIOSТеперь обсудим API-интерфейс NetBIOS. Он элементарен, поскольку содержит

только одну функцию:

UCHAR Netbios(PNCB pNCB);

Все объявления функций, константы и т. п. для NetBIOS определены в за-

головочном файле. Единственная библиотека, необходимая для компонов-

ки приложений NetBIOS — Netapi32.lib. Наиболее важная особенность этой

функции — параметр pNCB, который является указателем на блок сетевого

управления (network control block, NCB). Это — указатель на структуру NCB,

содержащую всю информацию, требуемую функции Netbios для выполнения

команды NetBIOS. Определяется эта структура так:

typedef struct _NCB

{

UCHAR ncb_command;

UCHAR ncb_retcode;

UCHAR ncb_lsn;

UCHAR ncb_num;

PUCHAR ncb_buffer;

WORD ncb_length;

UCHAR ncb_callname[NCBNAMSZ];

UCHAR ncb_name[NCBNAMSZ];

UCHAR ncb_rto;

UCHAR ncb_sto;

void (*ncb_post) (struct _NCB *);

UCHAR ncb_lana_num;

UCHAR ncb_cmd_cplt;

UCHAR ncb_reserve[10];

HANDLE ncb_event;

} * PNCB, NCB;

Не все члены структуры будут использоваться в каждом вызове NetBIOS;

некоторые из полей данных являются выходными параметрами (другими

словами, задаются по возвращении из вызова Netbios). Один важный совет:

Page 24: Network Programming for Microsoft Windows

10 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

всегда обнуляйте структуру NCB до вызова Netbios. В следующем списке опи-

сано назначение каждого поля.

L ncb_command — указывает выполняемую команду NetBIOS. Многие ко-

манды могут выполняться синхронно или асинхронно поразрядным ло-

гическим сложением флага ASYNCH (0x80) и команды.

L ncb_retcode — определяет код возврата для данной операции. Функция

присваивает этому полю значение NRC_PENDING, когда происходит асин-

хронная операция.

L ncb_lsn — определяет номер локального сеанса, уникально идентифици-

рующий его в текущем окружении. Функция возвращает новый номер се-

анса после успешной команды NCBCALL или NCBLISTEN.

L ncb_num — указывает номер локального сетевого имени. Новый номер воз-

вращается для каждого вызова команды NCBADDNAME или NCBADDGRNAME.

Используйте корректный номер со всеми дейтаграммными командами.

L ncb_buffer — указывает на буфер данных. Для команд, которые отправ-

ляют данные, этот буфер содержит отправляемые данные; для команд,

которые получают данные, — данные, возвращаемые функцией Netbios.

Для других команд, типа NCBENUM, буфер будет предопределенной струк-

турой LANA_ENUM.

L ncb_length — указывает длину буфера в байтах. Для команд приема Netbios

присваивает этому полю значение, равное количеству полученных байтов.

Если буфер недостаточно велик, Netbios возвращает ошибку NRC_BUFLEN.

L ncb_callname — указывает имя удаленного приложения.

L ncb_name — указывает имя, под которым известно приложение.

L ncb_rto — указывает время ожидания (тайм-аут) для операций приема.

Значение определено в 500-миллисекундных единицах (0 — означает

нулевое время ожидания) и задано для команд NCBCALL и NCBLISTEN, что

влияет на последующие команды NCBRECV.

L ncb_sto — указывает время ожидания для операций отправки. Значение

определяется в 500-миллисекундных единицах (0 — означает нулевое

время ожидания) и задано для команд NCBCALL и NCBLISTEN, что влияет

на последующие команды NCBSEND и NCBCHAINSEND.

L ncb_post — указывает адрес процедуры, которую надо вызвать по завер-

шении асинхронной команды. Функция определена как

void CALLBACK PostRoutine(PNCB pncb);

где pncb указывает на блок сетевого управления завершенной команды.

L ncb_lana_num — указывает номер LANA для выполнения команды.

L ncb_cmd_cplt — определяет код возврата для операции. Netbios присва-

ивает этому полю значение NRC_PENDING, когда происходит асинхрон-

ная операция.

L ncb_reserve — зарезервировано, должно быть равно 0.

Page 25: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 11

L ncb_event — указывает описатель объекта события Windows в свободном

(nonsignaled) состоянии. Когда асинхронная команда завершается, собы-

тие переходит в занятое (signaled) состояние. Следует использовать толь-

ко ручной сброс событий. Это поле должно быть равно 0, если в поле

ncb_command не задан флаг ASYNCH или если значение ноля ncb_post от-

лично от 0. Иначе Netbios возвращает ошибку NRC_ILLCMD.

Синхронный и асинхронный вызовВы можете вызвать функцию Netbios синхронно или асинхронно. Все коман-

ды NetBIOS синхронны — это означает, что вызов Netbios блокируется, пока

команда не завершит работу. При вызове команды NCBLISTEN запрос к Netbios

не возвращается, пока клиент не установит соединение или не произойдет

ошибка.

Для асинхронного вызова выполните логическую операцию OR над ко-

мандой NetBIOS и флагом ASYNCH. При использовании флага ASYNCH необ-

ходимо определить вызываемую после выполнения команды процедуру в

поле ncb_post, либо описатель события в поле ncb_event. Когда асинхронная

команда выполнена, Netbios возвращает значение NRC_GOODRET (0x00), но

полю ncb_cmd_cplt присваивается значение NRC_PENDING (0xFF). Кроме

того, функция Netbios задает полю ncb_cmd_cplt структуры NCB значение

NRC_PENDING, пока команда не завершится. По завершении команды полю

ncb_cmd_cplt присваивается значение, возвращенное командой. После сво-

его завершения Netbios также присваивает полю ncb_retcode свой код воз-

врата.

Типичные процедуры NetBIOSВ этом разделе мы исследуем типичное серверное приложение NetBIOS. Сна-

чала изучим сервер, так как его конструкция диктует действия клиента. По-

скольку большинство серверов предназначено для обслуживания нескольких

клиентов одновременно, асинхронная модель NetBIOS подойдет лучше все-

го. Мы обсудим примеры серверов, использующих как асинхронные проце-

дуры обратного вызова, так и модель событий. Однако для начала предста-

вим исходный текст, который реализует некоторые обычные функции, не-

обходимые большинству прикладных программ NetBIOS. Листинг 1-1 взят

из файла Nbcommon.c, который вы найдете на прилагаемом компакт-диске

в папке \Examples\Chapter01\Common. Функции из этого файла используют-

ся во многих примерах книги.

Листинг 1-1. Типичные процедуры NetBIOS (Nbcommon.c)

// Nbcommon.c

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

см. след. стр.

Page 26: Network Programming for Microsoft Windows

12 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

#include "nbcommon.h"

//

// Перечисляются все номера LANA

//

int LanaEnum(LANA_ENUM *lenum)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBENUM;

ncb.ncb_buffer = (PUCHAR)lenum;

ncb.ncb_length = sizeof(LANA_ENUM);

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBENUM: %d\n", ncb.ncb_retcode);

return ncb.ncb_retcode;

}

return NRC_GOODRET;

}

//

// Сброс всех сведений о LANA, перечисленных в структуре LANA_ENUM,

// а также настройка среды NetBIOS (максимальное количество сеансов,

// максимальный размер таблицы имен),и использование первого NetBIOS-имени.

//

int ResetAll(LANA_ENUM *lenum, UCHAR ucMaxSession,

UCHAR ucMaxName, BOOL bFirstName)

{

NCB ncb;

int i;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBRESET;

ncb.ncb_callname[0] = ucMaxSession;

ncb.ncb_callname[2] = ucMaxName;

ncb.ncb_callname[3] = (UCHAR)bFirstName;

for(i = 0; i < lenum->length; i++)

{

ncb.ncb_lana_num = lenum->lana[i];

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBRESET[%d]: %d\n",

ncb.ncb_lana_num, ncb.ncb_retcode);

return ncb.ncb_retcode;

}

}

Листинг 1-1. (продолжение)

Page 27: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 13

return NRC_GOODRET;

}

//

// Добавление указанного имени данному LANA. Возвращает номер

// для зарегистрированного имени.

//

int AddName(int lana, char *name, int *num)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBADDNAME;

ncb.ncb_lana_num = lana;

memset(ncb.ncb_name, ' ', NCBNAMSZ);

strncpy(ncb.ncb_name, name, strlen(name));

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBADDNAME[lana=%d;name=%s]: %d\n",

lana, name, ncb.ncb_retcode);

return ncb.ncb_retcode;

}

*num = ncb.ncb_num;

return NRC_GOODRET;

}

//

// Добавление указанного группового имени NetBIOS данному LANA

// Возвращение номера добавленного имени.

//

int AddGroupName(int lana, char *name, int *num)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBADDGRNAME;

ncb.ncb_lana_num = lana;

memset(ncb.ncb_name, ' ', NCBNAMSZ);

strncpy(ncb.ncb_name, name, strlen(name));

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBADDGRNAME[lana=%d;name=%s]: %d\n",

lana, name, ncb.ncb_retcode);

return ncb.ncb_retcode;

}

*num = ncb.ncb_num;

Листинг 1-1. (продолжение)

см. след. стр.

Page 28: Network Programming for Microsoft Windows

14 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

return NRC_GOODRET;

}

//

// Удаление данного имени NetBIOS из таблицы имен,

// связанной с номером LANA

//

int DelName(int lana, char *name)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBDELNAME;

ncb.ncb_lana_num = lana;

memset(ncb.ncb_name, ' ', NCBNAMSZ);

strncpy(ncb.ncb_name, name, strlen(name));

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBADDNAME[lana=%d;name=%s]: %d\n",

lana, name, ncb.ncb_retcode);

return ncb.ncb_retcode;

}

return NRC_GOODRET;

}

//

// Отправка len байт из буфера данных по указанному сеансу (lsn)

// и номеру lana

//

int Send(int lana, int lsn, char *data, DWORD len)

{

NCB ncb;

int retcode;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBSEND;

ncb.ncb_buffer = (PUCHAR)data;

ncb.ncb_length = len;

ncb.ncb_lana_num = lana;

ncb.ncb_lsn = lsn;

retcode = Netbios(&ncb);

return retcode;

}

//

// Прием не более len байт в буфер данных по указанному сеансу

Листинг 1-1. (продолжение)

Page 29: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 15

// (lsn) и номеру lana

//

int Recv(int lana, int lsn, char *buffer, DWORD *len)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBRECV;

ncb.ncb_buffer = (PUCHAR)buffer;

ncb.ncb_length = *len;

ncb.ncb_lana_num = lana;

ncb.ncb_lsn = lsn;

if (Netbios(&ncb) != NRC_GOODRET)

{

*len = -1;

return ncb.ncb_retcode;

}

*len = ncb.ncb_length;

return NRC_GOODRET;

}

//

// Прекращение указанного сеанса на данном номере lana

//

int Hangup(int lana, int lsn)

{

NCB ncb;

int retcode;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBHANGUP;

ncb.ncb_lsn = lsn;

ncb.ncb_lana_num = lana;

retcode = Netbios(&ncb);

return retcode;

}

//

// Отмена данной асинхронной команды, указанной в параметре-структуре NCB

//

int Cancel(PNCB pncb)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

Листинг 1-1. (продолжение)

см. след. стр.

Page 30: Network Programming for Microsoft Windows

16 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

ncb.ncb_command = NCBCANCEL;

ncb.ncb_buffer = (PUCHAR)pncb;

ncb.ncb_lana_num = pncb->ncb_lana_num;

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: NetBIOS: NCBCANCEL: %d\n", ncb.ncb_retcode);

return ncb.ncb_retcode;

}

return NRC_GOODRET;

}

//

// Форматирование указанного имени NetBIOS, чтобы оно было пригодно для печати.

// Непечатаемые символы заменяются точками.

// Буфер outname содержит возвращенную строку, длина которой - минимум

// NCBNAMSZ + 1 символов.

//

int FormatNetbiosName(char *nbname, char *outname)

{

int i;

strncpy(outname, nbname, NCBNAMSZ);

outname[NCBNAMSZ - 1] = '\0';

for(i = 0; i < NCBNAMSZ - 1; i++)

{

// Если символ непечатаемый, он заменяется точкой.

//

if (!((outname[i] >= 32) && (outname[i] <= 126)))

outname[i] = '.';

}

return NRC_GOODRET;

}

Первая из типичных процедур, приведенных в файле Nbcommon.c —

LanaEnum, самая распространенная: ее используют почти все приложения

NetBIOS. Эта функция перечисляет доступные номера LANA в данной систе-

ме. Функция обнуляет структуру NCB, присваивает полю ncb_command зна-

чение NCBENUM, полю ncb_buffer — структуру LANA_ENUM и полю ncb_length —

значение размера структуры LANA_ENUM. При правильной инициализации

структуры NCB единственное действие, которое должна предпринять функ-

ция LanaEnum, чтобы вызвать команду NCBENUM — вызвать функцию Netbios.

Как видите, выполнить команду NetBIOS несложно. В случае синхронных ко-

манд возвращаемое Netbios значение сообщит, успешно ли выполнена эта

команда. Константа NRC_GOODRET всегда соответствует успеху.

В случае успешного вызова NetBIOS в предоставленную структуру LA-

NA_ENUM будут записаны количество номеров LANA на текущем компьюте-

ре, а также фактические номера LANA. Структура LANA_ENUM определена

следующим образом:

Листинг 1-1. (продолжение)

Page 31: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 17

typedef struct LANA_ENUM

{

UCHAR length;

UCHAR lana[MAX_LANA + 1];

} LANA_ENUM, *PLANA_ENUM;

Поле length указывает, сколько номеров LANA имеет локальный компьютер,

поле lana — массив фактических номеров LANA, значение length — сколько

элементов массива lana будет заполнено номерами LANA.

Следующая функция — ResetAll, также используется во всех приложениях

NetBIOS. Хорошо написанная программа NetBIOS должна обнулить каждый

номер LANA, который планирует применить. Как только вы получаете струк-

туру LANA_ENUM с номерами LANA от LanaEnum, можете сбросить их, вызвав

команду NCBRESET для каждого номера LANA в структуре. Это именно то, что

делает ResetAll; первый параметр функции — структура LANA_ENUM. Для сбро-

са требуется, только чтобы функция присвоила полю ncb_command значение

NCBRESET, а полю ncb_lana_num — номер LANA, который требуется сбросить.

Хотя некоторые платформы, типа Windows 95, не требуют инициализировать

каждый используемый номер LANA, лучше все-таки это делать. Windows NT

требует инициализировать каждый номер LANA до его использования, иначе

любые другие запросы к Netbios вернут ошибку 52 (NRC_ENVNOTDEF).

Кроме того, при сбросе номера LANA вы можете задать определенные

параметры среды NetBIOS через символьные поля ncb_callname. Другие па-

раметры ResetAll соответствуют этим параметрам окружения. Функция ис-

пользует параметр ucMaxSession, чтобы присвоить значение нулевому сим-

волу ncb_callname, который задает максимальное количество сеансов. Обыч-

но операционная система задает значение по умолчанию меньше максиму-

ма. Например, в Windows NT 4 по умолчанию допустимо 64 параллельных

сеанса. ResetAll присваивает символу 2 поля ncb_callname (определяющему

максимальное число имен NetBIOS, которые могут быть добавлены к каждо-

му номеру LANA) значение параметра ucMaxName. Опять же, ОС определя-

ет стандартный максимум. Наконец, ResetAll присваивает символу 3, исполь-

зуемому для клиентов NetBIOS, значение своего параметра bFirstName. При-

сваивая этому параметру TRUE, клиент использует имя компьютера как имя

его процесса NetBIOS. В результате клиент может соединяться с сервером и

отправлять данные, не принимая никаких входящих соединений. Этот пара-

метр ускоряет инициализацию (добавление имени NetBIOS в локальную таб-

лицу требует времени).

Операцию добавления имени в локальную таблицу имен выполняет функ-

ция AddName. Параметры: добавляемое имя и номер LANA, к которому оно

добавляется. Помните, что таблица имен у каждого LANA своя, и если вы хо-

тите, чтобы ваше приложение обслуживало соединения на любом доступном

номере LANA, добавьте имя процесса к каждому LANA. Команда для добавле-

ния уникального имени — NCBADDNAME. Другие обязательные поля — номер

LANA, для которого добавляется имя, и добавляемое имя, которое должно быть

скопировано в поле ncb_name. AddName сначала заполняет буфер ncb_name

пробелами и предполагает, что параметр name указывает на строку с симво-

Page 32: Network Programming for Microsoft Windows

18 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

лом /0 в конце. После успешного добавления имени Netbios возвращает в поле

ncb_num номер добавленного имени NetBIOS. Это значение используется для

дейтаграмм (подробно мы обсудим их далее), чтобы идентифицировать ис-

ходный процесс NetBIOS. Наиболее типичная ошибка, с которой сталкивают-

ся при добавлении уникального имени — NRC_DUPNAME, происходит, когда

имя уже используется другим процессом в сети.

AddGroupName работает так же, как AddName, за одним исключением:

AddGroupName запускает команду NCBADDGRNAME и никогда не вызывает

ошибку NRC_DUPNAME.

Функция DelName удаляет имя NetBIOS из таблицы имен. Ей требуются

только номер LANA, для которого вы хотите удалить имя, и само имя.

Следующие две функции в листинге 1-1 — Send и Recv, используются для

отправки и получения данных в сеансе связи. Эти функции почти идентич-

ны за исключением значения поля ncb_command: ему присваивается NCBSEND,

либо NCBRECV. Обязательные параметры команды: номер LANA, по которому

будут отправлены данные, и номер сеанса. Успешная команда NCBCALL или

NCBLISTEN возвращает номер сеанса. Клиенты используют команду NCBCALL

для соединения с известной службой, а серверы — команду NCBLISTEN, что-

бы ждать входящих клиентских соединений. Когда какая-либо из этих команд

успешно выполняется, интерфейс NetBIOS устанавливает сеанс с уникальным

целым идентификатором.

Send и Recv также требуют параметров, которые проецируются в поля

ncb_buffer (буфера) и ncb_length (длины). При отправке данных поле ncb_buffer

указывает на содержащий эти данные буфер. Поле длины задает количество

отправляемых символов в буфере. При получении данных поле буфера ука-

зывает на блок памяти, в который копируются входящие данные. Поле дли-

ны содержит размер блока памяти. Когда функция Netbios завершает рабо-

ту, она записывает в поле длины количество успешно полученных байтов.

Важный аспект отправки данных через сеанс: вызов функции Send не

осуществим, пока получатель не вызовет функцию Recv. То есть если отпра-

витель выдает большое количество данных, а получатель не читает их, ис-

пользуются значительные ресурсы для локальной буферизации данных.

Поэтому лучше вызывать немного команд NCBSEND или NCBCHAINSEND од-

новременно. Для решения этой проблемы используйте Netbios-команды

NCBSENDNA и NCBCHAINSENDNA. В этом случае отправлять данные можно

без подтверждения получателя.

Последние две функции в конце листинга 1-1 — Hangup и Cancel, предназ-

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

команды. Вызов команды NetBIOS NCBHANGUP позволит корректно завершить

сеанс. При этом все невыполненные запросы на получение данных заверша-

ются и возвращают ошибку закрытого сеанса — NRC_SCLOSED (0x0A). Если

какие-либо команды отправки данных не выполнены, команда завершения

связи блокируется вплоть до их выполнения. Эта задержка происходит не-

зависимо от того, передает ли команда данные или ожидает, когда удален-

ная сторона запросит прием данных.

Page 33: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 19

Сервер сеансов: модель асинхронного обратного вызоваЗаймемся сервером, который будет слушать входящие клиентские соедине-

ния. Это простой эхо-сервер, отправляющий обратно любые данные, полу-

ченные от клиента. Листинг 1-2 содержит код сервера, использующего асин-

хронные функции обратного вызова. Код взят из файла Cbnbsvr.c, на прила-

гаемом компакт-диске он находится в папке /Examples/Chapter01/Server. В

функции main сначала перечисляются доступные номера LANA с помощью

LanaEnum, а затем — сбрасывается каждый номер LANA с помощью ResetAll.

Помните, что эти два шага обычно требуются от всех приложений NetBIOS.

Листинг 1-2. Сервер асинхронного обратного вызова (Cbnbsvr.c)

// Cbnbsvr.c

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include "..\Common\nbcommon.h"

#define MAX_BUFFER 2048

#define SERVER_NAME "TEST-SERVER-1"

DWORD WINAPI ClientThread(PVOID lpParam);

//

// Функция: ListenCallback

//

// Описание:

// Эта функция вызывается, когда завершается асинхронное прослушивание.

// Если не происходит никакой ошибки, создает поток, чтобы работать клиентом.

// Также асинхронно дается команда слушать другие клиентские соединения.

//

void CALLBACK ListenCallback(PNCB pncb)

{

HANDLE hThread;

DWORD dwThreadId;

if (pncb->ncb_retcode != NRC_GOODRET)

{

printf("ERROR: ListenCallback: %d\n", pncb->ncb_retcode);

return;

}

Listen(pncb->ncb_lana_num, SERVER_NAME);

hThread = CreateThread(NULL, 0, ClientThread, (PVOID)pncb, 0,

&dwThreadId);

if (hThread == NULL)

см. след. стр.

Page 34: Network Programming for Microsoft Windows

20 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

{

printf("ERROR: CreateThread: %d\n", GetLastError());

return;

}

CloseHandle(hThread);

return;

}

//

// Функция: ClientThread

//

// Описание:

// Клиентский поток блокирует получение данных от клиентов и

// просто посылает их назад. Это непрерывный цикл, выполняющийся

// пока не будет закрыт сеанс или не произойдет ошибка. Если

// чтение или запись дают ошибку NRC_SCLOSED, сеанс

// корректно завершается и происходит выход из цикла.

//

DWORD WINAPI ClientThread(PVOID lpParam)

{

PNCB pncb = (PNCB)lpParam;

NCB ncb;

char szRecvBuff[MAX_BUFFER];

DWORD dwBufferLen = MAX_BUFFER,

dwRetVal = NRC_GOODRET;

char szClientName[NCBNAMSZ+1];

FormatNetbiosName(pncb->ncb_callname, szClientName);

while (1)

{

dwBufferLen = MAX_BUFFER;

dwRetVal = Recv(pncb->ncb_lana_num, pncb->ncb_lsn,

szRecvBuff, &dwBufferLen);

if (dwRetVal != NRC_GOODRET)

break;

szRecvBuff[dwBufferLen] = 0;

printf("READ [LANA=%d]: '%s'\n", pncb->ncb_lana_num,

szRecvBuff);

dwRetVal = Send(pncb->ncb_lana_num, pncb->ncb_lsn,

szRecvBuff, dwBufferLen);

if (dwRetVal != NRC_GOODRET)

break;

}

printf("Client '%s' on LANA %d disconnected\n", szClientName,

pncb->ncb_lana_num);

Листинг 1-2. (продолжение)

Page 35: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 21

if (dwRetVal != NRC_SCLOSED)

{

// Возникает какая-то другая ошибка; соединение разрывается

//

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBHANGUP;

ncb.ncb_lsn = pncb->ncb_lsn;

ncb.ncb_lana_num = pncb->ncb_lana_num;

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBHANGUP: %d\n", ncb.ncb_retcode);

dwRetVal = ncb.ncb_retcode;

}

GlobalFree(pncb);

return dwRetVal;

}

GlobalFree(pncb);

return NRC_GOODRET;

}

//

// Функция: Listen

//

// Описание:

// Инициируется асинхронное прослушивание с помощью функции обратного вызова.

// Создается структура NCB для использования обратным вызовом (поскольку она

// должна быть видима глобально).

//

int Listen(int lana, char *name)

{

PNCB pncb = NULL;

pncb = (PNCB)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(NCB));

pncb->ncb_command = NCBLISTEN | ASYNCH;

pncb->ncb_lana_num = lana;

pncb->ncb_post = ListenCallback;

//

// Это имя, с которым клиенты будут соединяться

//

memset(pncb->ncb_name, ' ', NCBNAMSZ);

strncpy(pncb->ncb_name, name, strlen(name));

//

// '*' означает, что мы примем клиентское соединение от любого клиента.

// Задавая здесь конкретное имя, мы разрешаем соединение только с

// указанным клиентом.

//

memset(pncb->ncb_callname, ' ', NCBNAMSZ);

см. след. стр.

Листинг 1-2. (продолжение)

Page 36: Network Programming for Microsoft Windows

22 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

pncb->ncb_callname[0] = '*';

if (Netbios(pncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBLISTEN: %d\n", pncb->ncb_retcode);

return pncb->ncb_retcode;

}

return NRC_GOODRET;

}

//

// Функция: main

//

// Описание:

// Инициализирует интерфейс NetBIOS, выделяет некоторые ресурсы, добавляет

// имя сервера к каждому номеру LANA и дает асинхронную команду NCBLISTEN на

// каждый номер LANA с соответствующим обратным вызовом. Затем ждет входящих

// клиентских соединений, порождая рабочий поток, чтобы

// работать с ними. Главный поток просто ждет, пока серверные

// потоки работают с клиентскими запросами. Вы навряд ли будете делать это в

// настоящем приложении: этот пример приведен только для иллюстрации.

//

int main(int argc, char **argv)

{

LANA_ENUM lenum;

int i,

num;

// Перечисляются и инициализируются все номера LANA

//

if (LanaEnum(&lenum) != NRC_GOODRET)

return 1;

if (ResetAll(&lenum, 254, 254, FALSE) != NRC_GOODRET)

return 1;

//

// Каждому номеру LANA добавляется имя сервера и дается команда слушать

//

for(i = 0; i < lenum.length; i++)

{

AddName(lenum.lana[i], SERVER_NAME, &num);

Listen(lenum.lana[i], SERVER_NAME);

}

while (1)

{

Sleep(5000);

}

}

Листинг 1-2. (продолжение)

Page 37: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 23

Далее функция main добавляет имя вашего процесса к каждому номеру

LANA, на котором вы хотите принимать соединения. Сервер добавляет имя

своего процесса — TEST-SERVER-1, к каждому номеру LANA. Это имя (допол-

ненное пробелами, конечно) клиенты будут использовать для соединения с

сервером. При попытке установить или принять соединение важен каждый

символ в имени NetBIOS. Большинство проблем, с которыми сталкиваются

при программировании клиентов и серверов NetBIOS, связаны с несоответ-

ствием имен. Будьте последовательны, дополняя имена пробелами или ка-

ким-либо другим символом. Пробелы — наиболее популярные символы-за-

полнители, так как их удобно перечислять и распечатывать.

Последний и наиболее важный шаг для сервера — асинхронно выдать ряд

команд NCBLISTEN. Функция Listen сначала выделяет структуру NCB. При ис-

пользовании асинхронных вызовов NetBIOS, переданная вами структура

NCB должна сохраняться с момента вызова до его завершения. Для этого тре-

буется динамически выделять каждую структуру NCB перед выдачей коман-

ды или поддерживать глобальный пул структур NCB, чтобы использовать его

в асинхронных запросах. Для команды NCBLISTEN задайте номер LANA, к ко-

торому должен обращаться вызов. Заметьте, что код в листинге 1-1 выпол-

няет логическую операцию OR над командами NCBLISTEN и ASYNCH. При

указании команды ASYNCH поле ncb_post или ncb_event не должно равнять-

ся 0, иначе вызов Netbios даст ошибку NRC_ILLCMD.

В листинге 1-2 функция Listen присваивает полю ncb_post функцию обрат-

ного вызова ListenCallback. Затем функция Listen присваивает полю ncb_name

имя процесса сервера. С этим именем будут соединяться клиенты. Функция

также записывает в первый символ поля ncb_callname астериск (*). Это оз-

начает, что сервер примет соединение от любого клиента. С другой сторо-

ны, вы можете поместить в поле ncb_callname конкретное имя — тогда толь-

ко зарегистрированный под этим именем клиент сможет соединиться с сер-

вером. Наконец, функция Listen обращается к Netbios. Запрос завершается

немедленно, и функция Netbios до завершения команды присваивает полю

ncb_cmd_cplt переданной структуры NCB значение NRC_PENDING (0xFF).

После того как main инициализируется и даст команду NCBLISTEN каж-

дому номеру LANA, поток main переходит в бесконечный цикл.

ПРИМЕЧАНИЕ Так как этот сервер — только пример, схема его рабо-

ты очень проста. При разработке собственных серверов NetBIOS вы

можете написать другую обработку в главном цикле или выдать в цик-

ле main синхронную команду NCBLISTEN одному из LANA.

Функция обратного вызова выполняется, только когда входящее соедине-

ние принято на номере LANA. Когда команда NCBLISTEN принимает соеди-

нение, она вызывает эту функцию в поле ncb_post с исходной структурой

NCB в качестве параметра. Полю ncb_retcode присваивается значение кода

возврата. Всегда проверяйте это значение, чтобы увидеть, последовало ли

клиентское соединение. В случае успешного соединения поле ncb_retcode

будет равно NRC_GOODRET (0x00).

Page 38: Network Programming for Microsoft Windows

24 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

Если соединение успешно, асинхронно выдайте другую команду NCBLISTEN

тому же самому номеру LANA. Это необходимо потому, что как только исход-

ное прослушивание завершится успехом, сервер прекратит слушать клиентс-

кие соединения на этом LANA, пока не будет дана другая команда NCBLISTEN.

Таким образом, чтобы упростить доступ к вашим серверам, вызовите не-

сколько команд NCBLISTEN для одного LANA — тогда будет можно одновре-

менно принимать соединения от множества клиентов. Наконец, функция об-

ратного вызова создает поток, который будет обслуживать клиента. В нашем

примере данный поток просто работает в цикле и вызывает команду блоки-

рующего чтения (NCBRECV), а затем — блокирующей передачи (NCBSEND).

В примере реализован эхо-сервер, читающий сообщения клиентов и отправ-

ляющий их обратно. Клиентский поток входит в цикл, пока клиент не пре-

рвет соединение, после чего клиентский поток дает команду NCBHANGUP,

чтобы закрыть соединение со своей стороны. С этого момента клиентский

поток освобождает структуру NCB и завершается.

Для сеансов данные буферизируются нижележащими протоколами, так

что наличие невыполненных запросов на прием необязательно. После того,

как дана команда приема, функция Netbios немедленно передает доступные

данные в предоставленный буфер и вызов возвращается. Если доступных

данных нет, вызов приема блокируется, пока не появятся доступные данные

или не прервется сеанс. То же верно для команды отправления: если сетевой

стек способен отправить данные немедленно по проводу или буферизовать

их в стеке для дальнейшей передачи, вызов возвращается немедленно. Если

у системы нет буферного пространства, чтобы немедленно отправить дан-

ные, запрос на отправку блокируется, пока буфер не освободится.

Для решения этой проблемы можно задействовать команду ASYNCH при

передаче и приеме. Буфер, предоставленный для асинхронной передачи и

приема, должен быть виден за пределами вызывающей процедуры. Еще один

способ обойти блокирование заключается в использовании полей ncb_sto и

ncb_rto. Поле ncb_sto задает тайм-аут отправления. Указывая ненулевое зна-

чение в 500-миллисекундных единицах, вы можете задать максимальную

продолжительность блокирования отправки перед возвратом. Если время

команды истекает, данные не посылаются. То же верно для времени ожида-

ния приема: если данные не получены за указанное время, вызов заверша-

ется без передачи данных в буфер.

Сервер сеансов: модель асинхронных событийВ листинге 1-3 приведен код эхо-сервера, отличный от кода в листинге 1-2.

Здесь в качестве механизма оповещения о завершении используются собы-

тия Win32. Модель событий похожа на модель обратного вызова, единствен-

ное отличие: в модели обратного вызова система выполняет ваш код, когда

асинхронная операция завершается, а в модели событий — приложение дол-

жно убедиться в завершении операции, проверяя состояние события. По-

скольку речь идет о стандартных событиях Win32, вы можете использовать

любую из доступных процедур синхронизации, например WaitForSingleEvent

или WaitForMultipleEvents. Модель событий более эффективна, так как застав-

Page 39: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 25

ляет программиста структурировать программу, чтобы сознательно прове-

рять завершение.

Наш сервер модели событий начинает работу с того же, что и сервер об-

ратного вызова.

1. Перечисляет номера LANA.

2. Сбрасывает все номера LANA.

3. Добавляет имя сервера к каждому номеру LANA.

4. Инициирует прослушивание на каждом LANA.

Единственное различие — нужно отслеживать все невыполненные коман-

ды прослушивания, чтобы непременно сопоставить завершение события с

соответствующими блоками NCB, инициализирующими конкретную коман-

ду. Код в листинге 1-3 выделяет массив структур NCB, размер которого со-

ответствует количеству номеров LANA (поскольку требуется выполнять ко-

манду NCBLISTEN для каждого номера). Дополнительно код создает событие

для каждой структуры NCB, чтобы оповещать о завершении команды. Функ-

ция Listen использует одну из структур NCB из массива в качестве параметра.

Листинг 1-3. Сервер на основе асинхронных событий (Evnbsvr.c)

// Evnbsvr.c

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include "..\Common\nbcommon.h"

#define MAX_SESSIONS 254

#define MAX_NAMES 254

#define MAX_BUFFER 2048

#define SERVER_NAME "TEST-SERVER-1"

NCB *g_Clients=NULL; // Global NCB structure for clients

//

// Функция: ClientThread

//

// Описание:

// Этот поток берет структуру NCB из сеанса соединения

// и ждет входящих данных, которые затем посылает обратно

// клиентам, пока сеанс не будет закрыт.

//

DWORD WINAPI ClientThread(PVOID lpParam)

{

PNCB pncb = (PNCB)lpParam;

NCB ncb;

char szRecvBuff[MAX_BUFFER],см. след. стр.

Page 40: Network Programming for Microsoft Windows

26 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

szClientName[NCBNAMSZ + 1];

DWORD dwBufferLen = MAX_BUFFER,

dwRetVal = NRC_GOODRET;

// Отправка и прием сообщений, пока сеанс не будет закрыт

//

FormatNetbiosName(pncb->ncb_callname, szClientName);

while (1)

{

dwBufferLen = MAX_BUFFER;

dwRetVal = Recv(pncb->ncb_lana_num, pncb->ncb_lsn,

szRecvBuff, &dwBufferLen);

if (dwRetVal != NRC_GOODRET)

break;

szRecvBuff[dwBufferLen] = 0;

printf("READ [LANA=%d]: '%s'\n", pncb->ncb_lana_num,

szRecvBuff);

dwRetVal = Send(pncb->ncb_lana_num, pncb->ncb_lsn,

szRecvBuff, dwBufferLen);

if (dwRetVal != NRC_GOODRET)

break;

}

printf("Client '%s' on LANA %d disconnected\n", szClientName,

pncb->ncb_lana_num);

//

// Если в ходе чтения или записи выдается ошибка NRC_SCLOSED,

// то все в порядке; иначе возникла некоторая другая ошибка, так что

// соединение разрывается с этой стороны.

//

if (dwRetVal != NRC_SCLOSED)

{

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBHANGUP;

ncb.ncb_lsn = pncb->ncb_lsn;

ncb.ncb_lana_num = pncb->ncb_lana_num;

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBHANGUP: %d\n",

ncb.ncb_retcode);

GlobalFree(pncb);

dwRetVal = ncb.ncb_retcode;

}

}

// Передаваемая структура NCB выделяется динамически, поэтому

// ее следует вначале удалить

//

Листинг 1-3. (продолжение)

Page 41: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 27

GlobalFree(pncb);

return NRC_GOODRET;

}

//

// Функция: Listen

//

// Описание:

// Дается команда асинхронно слушать на указанном LANA.

// В переданной структуре NCB полю ncb_event уже

// присвоено значение действительного описателя события Windows.

//

int Listen(PNCB pncb, int lana, char *name)

{

pncb->ncb_command = NCBLISTEN | ASYNCH;

pncb->ncb_lana_num = lana;

//

// Это имя, с которым будут соединяться клиенты

//

memset(pncb->ncb_name, ' ', NCBNAMSZ);

strncpy(pncb->ncb_name, name, strlen(name));

//

// '*' означает, что мы примем клиентское соединение от любого клиента.

// Задавая здесь конкретное имя, мы разрешаем соединение только с

// указанным клиентом.

//

memset(pncb->ncb_callname, ' ', NCBNAMSZ);

pncb->ncb_callname[0] = '*';

if (Netbios(pncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBLISTEN: %d\n", pncb->ncb_retcode);

return pncb->ncb_retcode;

}

return NRC_GOODRET;

}

//

// Функция: main

//

// Описание:

// Инициализирует интерфейс NetBIOS, выделяет некоторые ресурсы, и

// дает асинхронную команду слушать каждому LANA, используя события. Ждет

// пока событие не сработает, а затем обрабатывает клиентское соединение.

//

int main(int argc, char **argv)

{

PNCB pncb=NULL;

см. след. стр.

Листинг 1-3. (продолжение)

Page 42: Network Programming for Microsoft Windows

28 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

HANDLE hArray[64],

hThread;

DWORD dwHandleCount=0,

dwRet,

dwThreadId;

int i,

num;

LANA_ENUM lenum;

// Перечисление и сброс всех номеров LANA

//

if (LanaEnum(&lenum) != NRC_GOODRET)

return 1;

if (ResetAll(&lenum, (UCHAR)MAX_SESSIONS, (UCHAR)MAX_NAMES,

FALSE) != NRC_GOODRET)

return 1;

//

// Выделение массива структур NCB (по одной для каждого номера LANA)

//

g_Clients = (PNCB)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,

sizeof(NCB) * lenum.length);

//

// Создание событий, добавление имени сервера каждому номеру LANA и начало

// асинхронного прослушивания на каждом LANA.

//

for(i = 0; i < lenum.length; i++)

{

hArray[i] = g_Clients[i].ncb_event = CreateEvent(NULL, TRUE,

FALSE, NULL);

AddName(lenum.lana[i], SERVER_NAME, &num);

Listen(&g_Clients[i], lenum.lana[i], SERVER_NAME);

}

while (1)

{

// Ожидание подключения клиента

//

dwRet = WaitForMultipleObjects(lenum.length, hArray, FALSE,

INFINITE);

if (dwRet == WAIT_FAILED)

{

printf("ERROR: WaitForMultipleObjects: %d\n",

GetLastError());

break;

}

// Проверка всех структур NCB для определения, достигла ли успеха более

// чем одна структура. Если поле ncb_cmd_plt не содержит значение

// NRC_PENDING, значит существует клиент, необходимо создать поток и

// выделить ему новую структуру NCB.

Листинг 1-3. (продолжение)

Page 43: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 29

// Нам нужно многократно использовать исходную структуру

// NCB для других клиентских соединений.

//

for(i = 0; i < lenum.length; i++)

{

if (g_Clients[i].ncb_cmd_cplt != NRC_PENDING)

{

pncb = (PNCB)GlobalAlloc(GMEM_FIXED, sizeof(NCB));

memcpy(pncb, &g_Clients[i], sizeof(NCB));

pncb->ncb_event = 0;

hThread = CreateThread(NULL, 0, ClientThread,

(LPVOID)pncb, 0, &dwThreadId);

CloseHandle(hThread);

//

// Описатель сбрасывается, асинхронно начинается еще одно

// прослушивание ResetEvent(hArray[i]);

//

Listen(&g_Clients[i], lenum.lana[i], SERVER_NAME);

}

}

}

// Очистка

//

for(i = 0; i < lenum.length; i++)

{

DelName(lenum.lana[i], SERVER_NAME);

CloseHandle(hArray[i]);

}

GlobalFree(g_Clients);

return 0;

}

Первый цикл функции main получает доступные номера LANA и при этом

добавляет имя сервера и отдает команду NCBLISTEN для каждого LANA, а так-

же формирует массив описателей событий. Затем вызывается функция Wait-

ForMultipleObjects, которая блокируется, пока по меньшей мере один из опи-

сателей не перейдет в занятое состояние. Тогда WaitForMultipleObjects завер-

шается, и код порождает поток для чтения входящих сообщений и отправ-

ки их обратно клиенту. Код копирует занятую структуру NCB, чтобы передать

ее в клиентский поток. Это позволяет многократно использовать исходную

структуру NCB для асинхронного вызова других команд NCBLISTEN, что мож-

но сделать путем сброса события и повторного вызова функции Listen для

этой структуры. Не обязательно копировать всю структуру — на самом деле

вам нужны только локальный номер сеанса (ncb_lsn) и номер LANA

(ncb_lana_num). Впрочем, структура NCB — удобный контейнер для хране-

ния обоих значений, чтобы потом передать их в один параметр потока. Кли-

Листинг 1-3. (продолжение)

Page 44: Network Programming for Microsoft Windows

30 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

ентский поток, используемый моделью событий, тот же, что и для модели

обратного вызова, за исключением оператора GlobalFree.

Асинхронные стратегии сервера

При использовании обоих видов серверов существует вероятность, что кли-

енту будет отказано в обслуживании. По завершении команды NCBLISTEN

происходит небольшая задержка, которая длится вплоть до вызова функции

обратного вызова или пока событие не будет занято. Рассмотренные нами

серверы не отдают асинхронно еще одну команду NCBLISTEN ранее, чем че-

рез несколько операторов. Например, если сервер обслуживал клиента на

номере LANA 2 и еще один клиент попытается подключиться прежде, чем

сервер отдаст следующую команду NCBLISTEN на том же номере LANA, кли-

ент получит ошибку NRC_NOCALL (0x14). Это означает, что для данного име-

ни еще не была асинхронно вызвана команда NCBLISTEN. Чтобы избежать та-

кой ситуации, сервер может асинхронно отдавать несколько команд NCBLISTEN

на каждом LANA.

Как видите, использовать асинхронные команды достаточно просто. Флаг

ASYNCH может применяться почти к любой команде NetBIOS. Помните толь-

ко, что структура NCB, которую вы передаете Netbios, должна быть видима

глобально.

Клиент сеанса NetBIOSКлиент NetBIOS напоминает асинхронный сервер событий. Листинг 1-4 со-

держит пример кода для клиента. Клиент выполняет уже знакомые нам стан-

дартные шаги инициализации имени: добавляет свое имя к таблице имен каж-

дого номера LANA и затем дает асинхронную команду соединения. Цикл main

ждет, пока одно из событий не будет занято. В это время в цикле проверяется

поле ncb_cmd_cplt каждой структуры NCB, соответствующей отданным коман-

дам подключения, по одной для каждого номера LANA. Если поле ncb_cmd_cplt

равно NRC_PENDING — код отменяет асинхронную команду; если команда за-

вершается (соединение установлено) и данная NCB не соответствует опове-

щенной (определяется по значению, возвращаемому WaitForMultipleObjects) —

соединение разрывается. Когда сервер слушает на каждом номере LANA на

своей стороне и клиент пытается соединиться на каждом из его номеров

LANA, может быть установлено несколько соединений. В этом случае код про-

сто закрывает лишние соединения командой NCBHANGUP — нужна связь толь-

ко по одному каналу. Попытки соединения с каждым номером LANA с обеих

сторон практически гарантированно успешны.

Листинг 1-4. Клиент на основе асинхронных событий (Nbclient.c)

// Nbclient.c

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

Page 45: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 31

#include "..\Common\nbcommon.h"

#define MAX_SESSIONS 254

#define MAX_NAMES 254

#define MAX_BUFFER 1024

char szServerName[NCBNAMSZ];

//

// Функция: Connect

//

// Описание:

// Установка асинхронного соединения с сервером на данном LANA.

// В переданной структуре NCB полю ncb_event уже присвоено значение

// действительного описателя события Windows. Просто

// заполните пробелы и сделайте вызов.

//

int Connect(PNCB pncb, int lana, char *server, char *client)

{

pncb->ncb_command = NCBCALL | ASYNCH;

pncb->ncb_lana_num = lana;

memset(pncb->ncb_name, ' ', NCBNAMSZ);

strncpy(pncb->ncb_name, client, strlen(client));

memset(pncb->ncb_callname, ' ', NCBNAMSZ);

strncpy(pncb->ncb_callname, server, strlen(server));

if (Netbios(pncb) != NRC_GOODRET)

{

printf("ERROR: Netbios: NCBCONNECT: %d\n",

pncb->ncb_retcode);

return pncb->ncb_retcode;

}

return NRC_GOODRET;

}

//

// Функция: main

//

// Описание:

// Инициализирует интерфейс NetBIOS, распределяет некоторые ресурсы

// (описатели событий, буфер отправки и т. п.) и дает команду

// NCBCALL для каждого номера LANA на указанном сервере. Когда соединение

// создано, отменяет или разрывает любые неудавшиеся

// соединения. Затем посылает/получает данные. Наконец, выполняет очистку.

//

Листинг 1-4. (продолжение)

см. след. стр.

Page 46: Network Programming for Microsoft Windows

32 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

int main(int argc, char **argv)

{

HANDLE *hArray;

NCB *pncb;

char szSendBuff[MAX_BUFFER];

DWORD dwBufferLen,

dwRet,

dwIndex,

dwNum;

LANA_ENUM lenum;

int i;

if (argc != 3)

{

printf("usage: nbclient CLIENT-NAME SERVER-NAME\n");

return 1;

}

// Перечисление и сброс всех номеров LANA

//

if (LanaEnum(&lenum) != NRC_GOODRET)

return 1;

if (ResetAll(&lenum, (UCHAR)MAX_SESSIONS, (UCHAR)MAX_NAMES,

FALSE) != NRC_GOODRET)

return 1;

strcpy(szServerName, argv[2]);

//

// Выделение массива описателей для использования асинхронных событий.

// Выделение массива структур NCB. Нам нужен один описатель

// и одна структура NCB для каждого номера LANA.

//

hArray = (HANDLE *)GlobalAlloc(GMEM_FIXED,

sizeof(HANDLE) * lenum.length);

pncb = (NCB *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,

sizeof(NCB) * lenum.length);

//

// Создание события и присвоение его соответствующей структуре NCB,

// начало асинхронного соединения (NCBCALL).

// Не забудьте добавить имя клиента к каждому номеру

// LANA, по которому он хочет соединиться.

//

for(i = 0; i < lenum.length; i++)

{

hArray[i] = CreateEvent(NULL, TRUE, FALSE, NULL);

pncb[i].ncb_event = hArray[i];

AddName(lenum.lana[i], argv[1], &dwNum);

Connect(&pncb[i], lenum.lana[i], szServerName, argv[1]);

}

// Ожидание успеха по меньшей мере одного соединения

Листинг 1-4. (продолжение)

Page 47: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 33

//

dwIndex = WaitForMultipleObjects(lenum.length, hArray, FALSE,

INFINITE);

if (dwIndex == WAIT_FAILED)

{

printf("ERROR: WaitForMultipleObjects: %d\n",

GetLastError());

}

else

{

// Если успешно более чем одно соединение, лишние

// соединения разрываются. Мы будем использовать соединение, возвращенное

// WaitForMultipleObjects, иначе если оно еще не установлено,

// отменим его.

//

for(i = 0; i < lenum.length; i++)

{

if (i != dwIndex)

{

if (pncb[i].ncb_cmd_cplt == NRC_PENDING)

Cancel(&pncb[i]);

else

Hangup(pncb[i].ncb_lana_num, pncb[i].ncb_lsn);

}

}

printf("Connected on LANA: %d\n", pncb[dwIndex].ncb_lana_num);

//

// Отправка и прием сообщений

//

for(i = 0; i < 20; i++)

{

wsprintf(szSendBuff, "Test message %03d", i);

dwRet = Send(pncb[dwIndex].ncb_lana_num,

pncb[dwIndex].ncb_lsn, szSendBuff,

strlen(szSendBuff));

if (dwRet != NRC_GOODRET)

break;

dwBufferLen = MAX_BUFFER;

dwRet = Recv(pncb[dwIndex].ncb_lana_num,

pncb[dwIndex].ncb_lsn, szSendBuff, &dwBufferLen);

if (dwRet != NRC_GOODRET)

break;

szSendBuff[dwBufferLen] = 0;

printf("Read: '%s'\n", szSendBuff);

}

Hangup(pncb[dwIndex].ncb_lana_num, pncb[dwIndex].ncb_lsn);

}

// Очистка

Листинг 1-4. (продолжение)

см. след. стр.

Page 48: Network Programming for Microsoft Windows

34 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

//

for(i = 0; i < lenum.length; i++)

{

DelName(lenum.lana[i], argv[1]);

CloseHandle(hArray[i]);

}

GlobalFree(hArray);

GlobalFree(pncb);

return 0;

}

Дейтаграммные операцииДейтаграмма — это способ связи без установления логического соединения.

Отправитель просто направляет каждый пакет по указанному имени NetBIOS.

Целостность данных и порядок доставки пакетов не гарантируются.

Есть три способа отправить дейтаграмму. Первый — направить дейтаг-

рамму на определенное (уникальное или групповое) имя. Это означает, что

получить эту дейтаграмму может только процесс, зарегистрировавший имя

приемника. Второй способ — отправить дейтаграмму на групповое имя: тог-

да получить сообщение смогут только процессы, зарегистрировавшие дан-

ное имя. Наконец, третий способ — широковещательно разослать дейтаг-

рамму по всей сети. Такую дейтаграмму сможет получить любой процесс на

любой рабочей станции в локальной сети. Для отправки дейтаграммы на

уникальное или групповое имя применяется команда NCBDGSEND, а для

широковещания — NCBDGSENDBC.

Отправить дейтаграмму с помощью любой из этих команд элементарно.

Определите для поля ncb_num значение номера имени, возвращенного ко-

мандой NCBADDNAME или NCBADDGRNAME. Этот номер идентифицирует от-

правителя сообщения. Присвойте полю ncb_buffer значение адреса буфера, со-

держащего отправляемые данные, а полю ncb_length — количество отправля-

емых байтов. Затем задайте для поля ncb_lana_num значение номера LANA, по

которому хотите передать дейтаграмму. Наконец, присвойте полю ncb_cal-

lname значение NetBIOS-имени приемника. Это может быть уникальное или

групповое имя. Чтобы широковещательно послать дейтаграмму, выполните

все описанные шаги, кроме последнего: так как сообщение получат все рабо-

чие станции, присвоение значения полю ncb_callname не требуется.

Конечно, в каждом из перечисленных сценариев отправления должна

быть соответствующая команда получения дейтаграммы для фактического

приема данных. Дейтаграммы не требуют установки соединения; если дей-

таграмма достигает клиента, а у клиента нет уже ожидающей команды по-

лучения, данные теряются и клиент не может их восстановить (если сервер

не отправит их снова). Это недостаток дейтаграммной связи. Впрочем, об-

мен дейтаграммами намного быстрее, чем сеансовая связь — не нужно про-

верять ошибки, устанавливать соединение и т. п.

Листинг 1-4. (продолжение)

Page 49: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 35

Для получения дейтаграмм также предусмотрено три способа. Первые два

используют команду NCBDGRECV. Прежде всего, вы можете отдать команду

приема дейтаграммы для сообщений, направленных на конкретное имя —

уникальное или групповое. Во-вторых, вы вправе отдать такую команду для

любой дейтаграммы, предназначенной для любого имени в таблице имен

процесса NetBIOS. И наконец, отдайте такую команду для широковещатель-

ной дейтаграммы с помощью команды NCBDGRECVBC.

ПРИМЕЧАНИЕ Невозможно дать команду асинхронного приема дей-

таграмм, предназначенных для имени, которое зарегистрировано иным

процессом, если только оба процесса не зарегистрировали групповое

имя (тогда они могут получить одно и то же сообщение).

Чтобы отдать команду приема, присвойте полю ncb_num значение номе-

ра имени, возвращенного успешным вызовом NCBADDNAME или NCBADDGR-

NAME. Этот номер определяет, для какого имени вы слушаете входящие дей-

таграммы. Если вы присваиваете этому полю значение 0xFF, то будете полу-

чать дейтаграммы, предназначенные для любого имени в таблице имен Net-

BIOS этого процесса. Создайте буфер для получения данных и присвойте

полю ncb_buffer значение адреса буфера. Присвойте полю ncb_length значение

размера буфера. Наконец, задайте для поля ncb_lana_num значение номера

LANA, на котором надо ждать дейтаграммы. После возвращения успешного

вызова Netbios с командой NCBDGRECV или NCBDGRECVBC поле ncb_length

будет содержать фактическое количество полученных байтов, а поле ncb_cal-

lname — NetBIOS-имя процесса отправки.

Код в листинге 1-5 содержит основные дейтаграммные функции. Вся от-

правка реализуется блокирующими вызовами: как только команда выдана и

данные отправлены, функция завершается и вам не грозит блокировка из-

за переполнения буфера данными. Вызовы приема — асинхронные события,

так как неизвестно на каком из номеров LANA будут получены данные. Код

похож на код сервера сеансов, использующего события. Для каждого номе-

ра LANA код отдает асинхронную команду NCBDGRECV или NCBDGRECVBC

и ждет, пока она не достигнет успеха. Затем проверяются все асинхронные

команды, печатаются сообщения о тех, которые были успешны, и отменяют-

ся еще ожидающие команды. В примере есть функции, как для направлен-

ного, так и для широковещательного отправления и приема. Программа мо-

жет быть скомпилирована в пример приложения, конфигурируемого для от-

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

ки позволяют пользователю указать количество отправляемых или прини-

маемых дейтаграмм, задержку между отправками, использование широкове-

щательных, а не направленных дейтаграмм, получение дейтаграмм для лю-

бого имени и т. п.

Листинг 1-5. Пример работы NetBIOS с дейтаграммами (Nbdgram.c)

// Nbdgram.c

#include <windows.h>см. след. стр.

Page 50: Network Programming for Microsoft Windows

36 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

#include <stdio.h>

#include <stdlib.h>

#include "..\Common\nbcommon.h"

#define MAX_SESSIONS 254

#define MAX_NAMES 254

#define MAX_DATAGRAM_SIZE 512

BOOL bSender = FALSE, // Отправка или прием дейтаграмм

bRecvAny = FALSE, // Прием для любого имени

bUniqueName = TRUE, // Зарегистрировать мое имя как уникальное?

bBroadcast = FALSE, // Использовать широковещательные

дейтаграммы?

bOneLana = FALSE; // Использовать все LANA или только один?

char szLocalName[NCBNAMSZ + 1], // Локальное NetBIOS-имя

szRecipientName[NCBNAMSZ + 1]; // NetBIOS-имя приема

DWORD dwNumDatagrams = 25, // Количество отправляемых дейтаграмм

dwOneLana, // Если использовать один LANA, то какой?

dwDelay = 0; // Задержка между отправками дейтаграмм

//

// Функция: ValidateArgs

//

// Описание:

// Эта функция анализирует аргументы командной строки

// и устанавливает различные глобальные флаги, соответствующие выбору

//

void ValidateArgs(int argc, char **argv)

{

int i;

for(i = 1; i < argc; i++)

{

if (strlen(argv[i]) < 2)

continue;

if ((argv[i][0] == '-') || (argv[i][0] == '/'))

{

switch (tolower(argv[i][1]))

{

case 'n': // Используется уникальное имя

bUniqueName = TRUE;

if (strlen(argv[i]) > 2)

strcpy(szLocalName, &argv[i][3]);

break;

case 'g': // Используется групповое имя

bUniqueName = FALSE;

if (strlen(argv[i]) > 2)

Листинг 1-5. (продолжение)

Page 51: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 37

strcpy(szLocalName, &argv[i][3]);

break;

case 's': // Отправка дейтаграмм

bSender = TRUE;

break;

case 'c': // Количество дейтаграмм для отправки или приема

if (strlen(argv[i]) > 2)

dwNumDatagrams = atoi(&argv[i][3]);

break;

case 'r': // Имя получателя дейтаграмм

if (strlen(argv[i]) > 2)

strcpy(szRecipientName, &argv[i][3]);

break;

case 'b': // Используется широковещательная рассылка

дейтаграмм

bBroadcast = TRUE;

break;

case 'a': // Прием дейтаграмм для любого имени

bRecvAny = TRUE;

break;

case 'l': // Работа только на этом номере LANA

bOneLana = TRUE;

if (strlen(argv[i]) > 2)

dwOneLana = atoi(&argv[i][3]);

break;

case 'd': // Задержка (в миллисекундах) между отправками

if (strlen(argv[i]) > 2)

dwDelay = atoi(&argv[i][3]);

break;

default:

printf("usage: nbdgram ?\n");

break;

}

}

}

return;

}

//

// Функция: DatagramSend

//

// Описание:

// Отправляет направленные дейтаграммы к указанному приемнику на

// заданном номере LANA от данного номера имени к соответствующему приемнику.

// Также указывается буфер данных и количество отправляемых байтов.

//

int DatagramSend(int lana, int num, char *recipient,

char *buffer, int buflen)

Листинг 1-5. (продолжение)

см. след. стр.

Page 52: Network Programming for Microsoft Windows

38 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBDGSEND;

ncb.ncb_lana_num = lana;

ncb.ncb_num = num;

ncb.ncb_buffer = (PUCHAR)buffer;

ncb.ncb_length = buflen;

memset(ncb.ncb_callname, ' ', NCBNAMSZ);

strncpy(ncb.ncb_callname, recipient, strlen(recipient));

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("Netbios: NCBDGSEND failed: %d\n", ncb.ncb_retcode);

return ncb.ncb_retcode;

}

return NRC_GOODRET;

}

//

// Функция: DatagramSendBC

//

// Описание:

// Посылает широковещательную дейтаграму по конкретному номеру LANA с

// данного номера имени. Также указаны буфер данных и количество

// отправляемых байт.

//

int DatagramSendBC(int lana, int num, char *buffer, int buflen)

{

NCB ncb;

ZeroMemory(&ncb, sizeof(NCB));

ncb.ncb_command = NCBDGSENDBC;

ncb.ncb_lana_num = lana;

ncb.ncb_num = num;

ncb.ncb_buffer = (PUCHAR)buffer;

ncb.ncb_length = buflen;

if (Netbios(&ncb) != NRC_GOODRET)

{

printf("Netbios: NCBDGSENDBC failed: %d\n", ncb.ncb_retcode);

return ncb.ncb_retcode;

}

return NRC_GOODRET;

}

//

Листинг 1-5. (продолжение)

Page 53: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 39

// Функция: DatagramRecv

//

// Описание:

// Получает дейтаграмму на данном номере LANA направленную по имени,

// представленному параметром num. Данные копируются в предоставленный буфер.

// Если hEvent не 0, вызов приема выполняется асинхронно

// с указанным описателем события. Если параметр num равен 0xFF, слушает

// дейтаграммы, предназначенные для любого имени NetBIOS,

// зарегистрированного процессом.

int DatagramRecv(PNCB pncb, int lana, int num, char *buffer,

int buflen, HANDLE hEvent)

{

ZeroMemory(pncb, sizeof(NCB));

if (hEvent)

{

pncb->ncb_command = NCBDGRECV | ASYNCH;

pncb->ncb_event = hEvent;

}

else

pncb->ncb_command = NCBDGRECV;

pncb->ncb_lana_num = lana;

pncb->ncb_num = num;

pncb->ncb_buffer = (PUCHAR)buffer;

pncb->ncb_length = buflen;

if (Netbios(pncb) != NRC_GOODRET)

{

printf("Netbos: NCBDGRECV failed: %d\n", pncb->ncb_retcode);

return pncb->ncb_retcode;

}

return NRC_GOODRET;

}

//

// Функция: DatagramRecvBC

//

// Описание:

// Получает широковещательную дейтаграмму на данном номере LANA.

// Данные копируются в предоставленный буфер. Если hEvent не равно 0,

// вызов приема выполняется асинхронно с указанным

// описателем события.

//

int DatagramRecvBC(PNCB pncb, int lana, int num, char *buffer,

int buflen, HANDLE hEvent)

{

ZeroMemory(pncb, sizeof(NCB));

if (hEvent)

Листинг 1-5. (продолжение)

см. след. стр.

Page 54: Network Programming for Microsoft Windows

40 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

{

pncb->ncb_command = NCBDGRECVBC | ASYNCH;

pncb->ncb_event = hEvent;

}

else

pncb->ncb_command = NCBDGRECVBC;

pncb->ncb_lana_num = lana;

pncb->ncb_num = num;

pncb->ncb_buffer = (PUCHAR)buffer;

pncb->ncb_length = buflen;

if (Netbios(pncb) != NRC_GOODRET)

{

printf("Netbios: NCBDGRECVBC failed: %d\n", pncb->ncb_retcode);

return pncb->ncb_retcode;

}

return NRC_GOODRET;

}

//

// Функция: main

//

// Описание:

// Инициализирует интерфейс NetBIOS, выделяет ресурсы, а затем отправляет или

// получает дейтаграммы согласно пользовательским параметрам

//

int main(int argc, char **argv)

{

LANA_ENUM lenum;

int i, j;

char szMessage[MAX_DATAGRAM_SIZE],

szSender[NCBNAMSZ + 1];

DWORD *dwNum = NULL,

dwBytesRead,

dwErr;

ValidateArgs(argc, argv);

//

// Перечисление и сброс номеров LANA

//

if ((dwErr = LanaEnum(&lenum)) != NRC_GOODRET)

{

printf("LanaEnum failed: %d\n", dwErr);

return 1;

}

if ((dwErr = ResetAll(&lenum, (UCHAR)MAX_SESSIONS,

(UCHAR)MAX_NAMES, FALSE)) != NRC_GOODRET)

{

printf("ResetAll failed: %d\n", dwErr);

Листинг 1-5. (продолжение)

Page 55: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 41

return 1;

}

//

// Этот буфер содержит номер добавленного к каждому номеру LANA

// NetBIOS-имени

//

dwNum = (DWORD *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,

sizeof(DWORD) * lenum.length);

if (dwNum == NULL)

{

printf("out of memory\n");

return 1;

}

//

// Если мы собираемся работать только на одном номере LANA, имя регистрируется

// только на этом номере LANA, иначе имя регистрируется на всех

// номерах LANA

//

if (bOneLana)

{

if (bUniqueName)

AddName(dwOneLana, szLocalName, &dwNum[0]);

else

AddGroupName(dwOneLana, szLocalName, &dwNum[0]);

}

else

{

for(i = 0; i < lenum.length; i++)

{

if (bUniqueName)

AddName(lenum.lana[i], szLocalName, &dwNum[i]);

else

AddGroupName(lenum.lana[i], szLocalName, &dwNum[i]);

}

}

// Отправка дейтаграмм

//

if (bSender)

{

// Отправка с использованием широковещания

//

if (bBroadcast)

{

if (bOneLana)

{

// Широковещательная отправка сообщения только на одном номере

// LANA

Листинг 1-5. (продолжение)

см. след. стр.

Page 56: Network Programming for Microsoft Windows

42 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

for(j = 0; j < dwNumDatagrams; j++)

{

wsprintf(szMessage,

"[%03d] Test broadcast datagram", j);

if (DatagramSendBC(dwOneLana, dwNum[0],

szMessage, strlen(szMessage))

!= NRC_GOODRET)

return 1;

Sleep(dwDelay);

}

}

else

{

// Широковещательная отправка сообщения на каждом номере LANA

// на локальной машине

//

for(j = 0; j < dwNumDatagrams; j++)

{

for(i = 0; i < lenum.length; i++)

{

wsprintf(szMessage,

"[%03d] Test broadcast datagram", j);

if (DatagramSendBC(lenum.lana[i], dwNum[i],

szMessage, strlen(szMessage))

!= NRC_GOODRET)

return 1;

}

Sleep(dwDelay);

}

}

}

else

{

if (bOneLana)

{

// Отправка направленного сообщения на один указанный номер LANA

//

for(j = 0; j < dwNumDatagrams; j++)

{

wsprintf(szMessage,

"[%03d] Test directed datagram", j);

if (DatagramSend(dwOneLana, dwNum[0],

szRecipientName, szMessage,

strlen(szMessage)) != NRC_GOODRET)

return 1;

Sleep(dwDelay);

}

}

else

Листинг 1-5. (продолжение)

Page 57: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 43

{

// Отправка прямого сообщения на каждом номере LANA на

// локальной машине

//

for(j = 0; j < dwNumDatagrams; j++)

{

for(i = 0; i < lenum.length; i++)

{

wsprintf(szMessage,

"[%03d] Test directed datagram", j);

printf("count: %d.%d\n", j,i);

if (DatagramSend(lenum.lana[i], dwNum[i],

szRecipientName, szMessage,

strlen(szMessage)) != NRC_GOODRET)

return 1;

}

Sleep(dwDelay);

}

}

}

}

else // Прием дейтаграмм

{

NCB *ncb=NULL;

char **szMessageArray = NULL;

HANDLE *hEvent=NULL;

DWORD dwRet;

// Выделение массива структур NCB для передачи каждому приемнику

// на каждом LANA

//

ncb = (NCB *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,

sizeof(NCB) * lenum.length);

//

// Выделение массива буферов входящих данных

//

szMessageArray = (char **)GlobalAlloc(GMEM_FIXED,

sizeof(char *) * lenum.length);

for(i = 0; i < lenum.length; i++)

szMessageArray[i] = (char *)GlobalAlloc(GMEM_FIXED,

MAX_DATAGRAM_SIZE);

//

// Выделение массива описателей событий для

// асинхронных приемов

//

hEvent = (HANDLE *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,

sizeof(HANDLE) * lenum.length);

for(i = 0; i < lenum.length; i++)

Листинг 1-5. (продолжение)

см. след. стр.

Page 58: Network Programming for Microsoft Windows

44 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

hEvent[i] = CreateEvent(0, TRUE, FALSE, 0);

if (bBroadcast)

{

if (bOneLana)

{

// Синхронный широковещательный прием

// на одном указанном номере LANA

//

for(j = 0; j < dwNumDatagrams; j++)

{

if (DatagramRecvBC(&ncb[0], dwOneLana, dwNum[0],

szMessageArray[0], MAX_DATAGRAM_SIZE,

NULL) != NRC_GOODRET)

return 1;

FormatNetbiosName(ncb[0].ncb_callname, szSender);

printf("%03d [LANA %d] Message: '%s' "

"received from: %s\n", j,

ncb[0].ncb_lana_num, szMessageArray[0],

szSender);

}

}

else

{

// Асинхронный широковещательный прием на каждом

// доступном номере LANA. Для каждой успешной команды

// печатается сообщение, иначе команда отменяется.

//

for(j = 0; j < dwNumDatagrams; j++)

{

for(i = 0; i < lenum.length; i++)

{

dwBytesRead = MAX_DATAGRAM_SIZE;

if (DatagramRecvBC(&ncb[i], lenum.lana[i],

dwNum[i], szMessageArray[i],

MAX_DATAGRAM_SIZE, hEvent[i])

!= NRC_GOODRET)

return 1;

}

dwRet = WaitForMultipleObjects(lenum.length,

hEvent, FALSE, INFINITE);

if (dwRet == WAIT_FAILED)

{

printf("WaitForMultipleObjects failed: %d\n",

GetLastError());

return 1;

}

for(i = 0; i < lenum.length; i++)

{

Листинг 1-5. (продолжение)

Page 59: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 45

if (ncb[i].ncb_cmd_cplt == NRC_PENDING)

Cancel(&ncb[i]);

else

{

ncb[i].ncb_buffer[ncb[i].ncb_length] = 0;

FormatNetbiosName(ncb[i].ncb_callname,

szSender);

printf("%03d [LANA %d] Message: '%s' "

"received from: %s\n", j,

ncb[i].ncb_lana_num,

szMessageArray[i], szSender);

}

ResetEvent(hEvent[i]);

}

}

}

}

else

{

if (bOneLana)

{

// Блокирующий прием дейтаграмм на указанном

// номере LANA

//

for(j = 0; j < dwNumDatagrams; j++)

{

if (bRecvAny)

{

// Прием данных, предназначенных для любого имени NetBIOS

// в таблице имен этого процесса

//

if (DatagramRecv(&ncb[0], dwOneLana, 0xFF,

szMessageArray[0], MAX_DATAGRAM_SIZE,

NULL) != NRC_GOODRET)

return 1;

}

else

{

if (DatagramRecv(&ncb[0], dwOneLana,

dwNum[0], szMessageArray[0],

MAX_DATAGRAM_SIZE, NULL)

!= NRC_GOODRET)

return 1;

}

FormatNetbiosName(ncb[0].ncb_callname, szSender);

printf("%03d [LANA %d] Message: '%s' "

"received from: %s\n", j,

ncb[0].ncb_lana_num, szMessageArray[0],

Листинг 1-5. (продолжение)

см. след. стр.

Page 60: Network Programming for Microsoft Windows

46 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

szSender);

}

}

else

{

// Асинхронный прием дейтаграмм на каждом доступном номере LANA.

// Для успешных команд печатаются данные,

// иначе команда отменяется.

//

for(j = 0; j < dwNumDatagrams; j++)

{

for(i = 0; i < lenum.length; i++)

{

if (bRecvAny)

{

// Прием данных, предназначенных для любого имени

// NetBIOS в таблице имен этого процесса

//

if (DatagramRecv(&ncb[i], lenum.lana[i],

0xFF, szMessageArray[i],

MAX_DATAGRAM_SIZE, hEvent[i])

!= NRC_GOODRET)

return 1;

}

else

{

if (DatagramRecv(&ncb[i], lenum.lana[i],

dwNum[i], szMessageArray[i],

MAX_DATAGRAM_SIZE, hEvent[i])

!= NRC_GOODRET)

return 1;

}

}

dwRet = WaitForMultipleObjects(lenum.length,

hEvent, FALSE, INFINITE);

if (dwRet == WAIT_FAILED)

{

printf("WaitForMultipleObjects failed: %d\n",

GetLastError());

return 1;

}

for(i = 0; i < lenum.length; i++)

{

if (ncb[i].ncb_cmd_cplt == NRC_PENDING)

Cancel(&ncb[i]);

else

{

ncb[i].ncb_buffer[ncb[i].ncb_length] = 0;

FormatNetbiosName(ncb[i].ncb_callname,

Листинг 1-5. (продолжение)

Page 61: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 47

szSender);

printf("%03d [LANA %d] Message: '%s' "

"from: %s\n", j, ncb[i].ncb_lana_num,

szMessageArray[i], szSender);

}

ResetEvent(hEvent[i]);

}

}

}

}

// Очистка

//

for(i = 0; i < lenum.length; i++)

{

CloseHandle(hEvent[i]);

GlobalFree(szMessageArray[i]);

}

GlobalFree(hEvent);

GlobalFree(szMessageArray);

}

// Очистка

//

if (bOneLana)

DelName(dwOneLana, szLocalName);

else

{

for(i = 0; i < lenum.length; i++)

DelName(lenum.lana[i], szLocalName);

}

GlobalFree(dwNum);

return 0;

}

Скомпилировав этот пример, выполните следующие тесты, чтобы понять,

как работают дейтаграммы (табл. 1-2). В целях обучения запустите две ко-

пии приложений на разных компьютерах. Если вы запустите их на одном

компьютере, они будут работать, но вы можете не увидеть некоторые важ-

ные моменты, так как в этом случае LANA для обеих сторон будут соответ-

ствовать одному и тому же протоколу.

Табл. 1-2. Команды вызова Nbdgram.c

Команда клиента Команда сервера

Nbdgram /n:CLIENT01 Nbdgram /s /n:SERVER01 /r:CLIENT01

Nbdgram /n:CLIENT01 /b Nbdgram /s /n:SERVER01 /b

Nbdgram /g:CLIENTGROUP Nbdgram /s /r:CLIENTGROUP

Nbdgram /g:CLIENTGROUP Nbdgram /s /r:CLIENTGROUP

Листинг 1-5. (продолжение)

Page 62: Network Programming for Microsoft Windows

48 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

А теперь перечислим все параметры командной строки, доступные для

использования в программе-примере:

L /n:my-name — регистрирует уникальное имя my-name;

L /g:group-name — регистрирует групповое имя group-name;

L /s — отправляет дейтаграммы (по умолчанию, в примере дейтаграммы

принимаются);

L /c:n — отправляет или получает n дейтаграмм;

L /r:receiver — определяет NetBIOS-имя для отправки дейтаграммы;

L /b — использует широковещательную посылку дейтаграмм;

L /a — принимает данные для любого имени NetBIOS (присваивает полю

ncb_num значение 0xFF);

L /l:n — выполняет все операции только на номере LANA n (по умолчанию

все команды отправки и приема выполняются для всех номеров LANA);

L /d:n — ждет n миллисекунд между отправками.

Для выполнения третьей команды запустите несколько клиентов на раз-

ных компьютерах. Она иллюстрирует случай, когда один сервер посылает

одно сообщение группе, и каждый член группы, ожидающий данные, полу-

чит это сообщение.

Также попробуйте различные комбинации перечисленных команд с па-

раметром командной строки /l:x, где x — действительный номер LANA. Этот

параметр переключает программу из режима выполнения команд на всех

номерах LANA в режим выполнения команд только на конкретном номере

LANA. Например, команда Nbdgram /n:CLIENT01 /l:0 заставит приложение

слушать входящие дейтаграммы только на LANA 0 и игнорировать любые

данные, поступающие на какой-либо другой номер LANA.

Параметр /a имеет смысл только для клиентов. Этот флаг заставляет ко-

манду получения принимать входящие дейтаграммы, предназначенные для

любого имени NetBIOS, которое зарегистрировано процессом. В нашем при-

мере это не имеет особого значения, так как клиенты регистрируют только

одно имя, но вы можете по крайней мере посмотреть, как это должно выг-

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

для каждого параметра /n:name в командной строке. Запустите сервер с фла-

гом получателя, заданным только для одного из имен, зарегистрированных

клиентом. Клиент получит данные, несмотря на то, что команда NCBDGRECV

не обращается явно к конкретному имени.

Дополнительные команды NetBIOSВсе рассмотренные нами команды так или иначе относятся к установлению

сеанса, отправке или получению данных через сеанс или дейтаграмму. Но

есть несколько команд, предназначенных исключительно для обработки

приема информации: команда опроса состояния адаптера (NCBASTAT) и ко-

манда поиска имени (NCBFINDNAME). Мы рассмотрим их, а затем перейдем

Page 63: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 49

к программному сопоставлению номеров LANA протоколам — хотя это не

функция NetBIOS, но в справочных целях ознакомиться с ней полезно.

Проверка состояния адаптера (команда NCBASTAT)Команда опроса состояния адаптера полезна для получения информации о

локальном компьютере и его номерах LANA. Это единственный способ про-

граммно выяснить MAC-адрес компьютера из Windows 95 и NT 4. Функции IP

Helper, появившиеся в Windows 2000 и Windows 98 (см. приложение A), предо-

ставляют более универсальный интерфейс для выяснения MAC-адреса.

Команда и ее синтаксис довольно просты, но то, какие данные будут воз-

вращены, зависит от способа вызова функции. Команда опроса состояния

адаптера возвращает структуру ADAPTER_STATUS, сопровождаемую рядом

структур NAME_BUFFER. Эти структуры определены следующим образом:

typedef struct _ADAPTER_STATUS {

UCHAR adapter_address[6];

UCHAR rev_major;

UCHAR reserved0;

UCHAR adapter_type;

UCHAR rev_minor;

WORD duration;

WORD frmr_recv;

WORD frmr_xmit;

WORD iframe_recv_err;

WORD xmit_aborts;

DWORD xmit_success;

DWORD recv_success;

WORD iframe_xmit_err;

WORD recv_buff_unavail;

WORD t1_timeouts;

WORD ti_timeouts;

DWORD reserved1;

WORD free_ncbs;

WORD max_cfg_ncbs;

WORD max_ncbs;

WORD xmit_buf_unavail;

WORD max_dgram_size;

WORD pending_sess;

WORD max_cfg_sess;

WORD max_sess;

WORD max_sess_pkt_size;

WORD name_count;

} ADAPTER_STATUS, *PADAPTER_STATUS;

typedef struct _NAME_BUFFER {

UCHAR name[NCBNAMSZ];

UCHAR name_num;

UCHAR name_flags;

} NAME_BUFFER, *PNAME_BUFFER;

Page 64: Network Programming for Microsoft Windows

50 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

Поля, представляющие наибольший интерес: MAC-адрес (adapter_ad-

dress), максимальный размер дейтаграммы (max_dgram_size) и максималь-

ное количество сеансов (max_sess). Кроме того, поле name_count сообщает,

сколько было возвращено структур NAME_BUFFER. Максимальное количество

NetBIOS-имен на номер LANA — 254, так что вы можете обеспечить доста-

точно большой буфер для всех имен или вызвать команду опроса состояния

адаптера с полем ncb_length, равным 0. Функция Netbios по завершении вы-

дает необходимый размер буфера.

Поля, необходимые для вызова команды NCBASTAT: ncb_command, ncb_

buffer, ncb_length, ncb_lana_num и ncb_callname. Если первый символ поля

ncb_callname — звездочка (*), команда проверки состояния выполняется, но

возвращает только NetBIOS-имена, добавленные вызывающим процессом.

Впрочем, если вы вызываете Netbios с командой опроса состояния адаптера,

добавляете уникальное имя к таблице имен текущего процесса, а затем ис-

пользуете это имя в поле ncb_callname, все NetBIOS-имена, а также все име-

на, зарегистрированные системой, добавляются в таблицу имен локального

процесса. Вы можете также проверить состояние адаптера не с того ком-

пьютера, где выполняется команда. Для этого задайте в поле ncb_callname

имя удаленной рабочей станции.

ПРИМЕЧАНИЕ Помните, что во всех именах компьютеров Microsoft

16-му байту присваивается значение 0. Кроме того, они дополняются

пробелами до фиксированной длины.

Приведенная в качестве примера простая программа — Astat.c, проверя-

ет состояние всех LANA. Кроме того, при использовании флага /l:LOCAL-

NAME эта команда выполняется на локальном компьютере, но выдает пол-

ную таблицу имен. Флаг /r:REMOTENAME инициирует удаленный опрос для

указанного имени компьютера.

При использовании команды, проверяющей состояние адаптера, нужно

учитывать некоторые моменты. Во-первых, у компьютера с несколькими

адаптерами будет несколько MAC-адресов. Так как NetBIOS не позволяет вы-

яснить, к которым адаптерам и протоколам привязан LANA, разбираться в

возвращенных значениях придется самостоятельно. Кроме того, если уста-

новлена служба удаленного доступа (Remote Access Service, RAS), система вы-

делит номера LANA и для удаленных соединений. Пока соединения RAS не-

активны, проверка состояния адаптера на этих LANA вернет нулевой MAC-

адрес. Если установлено соединение RAS, MAC-адрес будет соответствовать

тому, который служба RAS назначает всем своим виртуальным сетевым уст-

ройствам.

Наконец, проверку состояния удаленного адаптера вы должны выполнять

по общему для обоих компьютеров транспортному протоколу. Например,

системная команда Nbtstat (версия NCBASTAT для командной строки) выпол-

няет опрос только по TCP/IP. Если на удаленном компьютере нет TCP/IP, ко-

манда не будет выполнена.

Page 65: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 51

Команда поиска имени (NCBFINDNAME)Эта команда доступна только в Windows NT и Windows 2000, сообщает, кто

зарегистрировал данное имя NetBIOS. Чтобы успешно выполнить запрос на

поиск имени, процесс должен добавить свое уникальное имя в таблицу имен.

Для этого необходимо задать следующие поля: команда, номер LANA, буфер

и длина буфера. Запрос вернет структуру FIND_NAME_HEADER и несколько

структур FIND_NAME_BUFFER, определенных следующим образом:

typedef struct _FIND_NAME_HEADER {

WORD node_count;

UCHAR reserved;

UCHAR unique_group;

} FIND_NAME_HEADER, *PFIND_NAME_HEADER;

typedef struct _FIND_NAME_BUFFER {

UCHAR length;

UCHAR access_control;

UCHAR frame_control;

UCHAR destination_addr[6];

UCHAR source_addr[6];

UCHAR routing_info[18];

} FIND_NAME_BUFFER, *PFIND_NAME_BUFFER;

Как и в случае команды проверки состояния адаптера, если команда NCB-

FINDNAME выполняется с длиной буфера равной 0, функция Netbios вернет

требуемую длину и ошибку NRC_BUFLEN.

Структура FIND_NAME_HEADER, которую возвращает успешный опрос,

показывает, зарегистрировано ли имя как уникальное или как групповое.

Если поле unique_group содержит 0 — это уникальное имя, если 1 — груп-

повое. Поле node_count указывает, сколько было возвращено структур FIND_

NAME_BUFFERS. Структура FIND_NAME_BUFFER возвращает совсем немного

информации, большая часть которой полезна на уровне протокола. Одна-

ко нас интересуют поля destination_addr и source_addr. Поле source_addr

содержит MAC-адрес сетевого адаптера, зарегистрировавшего имя, а поле

destination_addr — MAC-адрес адаптера, выполнившего запрос.

Запрос на поиск имени может быть отдан на любом номере LANA на ло-

кальном компьютере. Возвращенные данные должны быть одинаковы на

всех действительных LANA в локальной сети (вы можете выполнить коман-

ду поиска имени для RAS-подключения, чтобы определить, зарегистрирова-

но ли имя в удаленной сети).

Если в Windows NT 4 поиск имени выполняется по протоколу TCP/IP,

Netbios возвращает ложную информацию. Убедитесь, что выбран номер

LANA, соответствующий транспорту, отличному от TCP/IP.

Сопоставление протоколов номерам LANAВ зависимости от того, какой транспорт использует ваше приложение, мо-

гут возникать разные проблемы, так что неплохо уметь программно опре-

Page 66: Network Programming for Microsoft Windows

52 ЧАСТЬ I Устаревшие сетевые APIТББЕЗОПАСНОСТЬ

делять доступные транспорты. Это невозможно сделать средствами «родно-

го» опроса NetBIOS — надо использовать Winsock 2 для Windows NT 4 и

Windows 2000. Функция Winsock 2 WSAEnumProtocols возвращает информа-

цию о доступных транспортных протоколах (подробнее о ней — в главах 5

и 6). Хотя Winsock 2 доступен в Windows 95 и, по умолчанию, в Windows 98,

информация о протоколе, хранимая на этих платформах, не содержит ни-

каких сведений о NetBIOS.

Мы не будем подробно обсуждать Winsock 2, поскольку этому интерфей-

су посвящена часть II этой книги. Основные шаги следующие: загрузка

Winsock 2 через функцию WSAStartup, вызов функции WSAEnumProtocols и

просмотр возвращенных запросом структур WSAPROTOCOL_INFO. Пример

Nbproto.c на прилагаемом компакт-диске содержит код для выполнения та-

кого опроса.

Функция WSAEnumProtocols принимает в качестве параметров адрес буфе-

ра для блока данных и длину буфера. Сначала вызовите эту функцию с ну-

левыми адресом и длиной буфера. Вызов будет неудачным, но параметр дли-

ны буфера теперь содержит требуемый размер. Вызовите функцию снова —

WSAEnumProtocols вернет количество найденных протоколов. Структура WSA-

PROTOCOL_INFO велика и содержит множество полей, но нас интересуют

только szProtocol, iAddressFamily и iProtocol. Если поле iAddressFamily равно

AF_NETBIOS, то абсолютное значение iProtocol — номер LANA для протоко-

ла, указанного в строке szProtocol. Кроме того, для сопоставления возвращен-

ного протокола предопределенному GUID протокола можно использовать

ProviderId GUID.

Здесь есть один нюанс. В Windows NT и Windows 2000 поле iProtocol для

любого протокола, установленного на LANA 0, имеет значение 0x80000000.

Дело в том, что протокол 0 зарезервирован для специального использова-

ния; любой протокол, назначенный LANA 0, всегда будет иметь значение

0x80000000, так что надо просто проверить это значение.

Рекомендации по выбору платформРеализуя связь средствами NetBIOS на следующих платформах, имейте в виду

следующие ограничения.

Платформа Windows CEИнтерфейс NetBIOS в Windows CE не доступен. Перенаправитель поддержи-

вает имена и разрешения имен NetBIOS, но не программный интерфейс.

Платформа Windows 9xВ Windows 95 и Windows 98 есть несколько ошибок. На любой из этих плат-

форм вы должны сбросить все номера LANA перед добавлением любого име-

ни NetBIOS к любому номеру LANA. Так как сброс одного номера LANA раз-

рушает таблицы имен других номеров, избегайте кода, подобного следую-

щему:

Page 67: Network Programming for Microsoft Windows

ГЛАВА 9 ГЛАВА 1 Интерфейс NetBIOS 53

LANA_ENUM lenum;

// Перечисление номеров LANA

for(i = 0; i < lenum.length; i++)

{

Reset(lenum.lana[i]);

AddName(lenum.lana[i], MY_NETBIOS_NAME);

}

Кроме того, не пытайтесь асинхронно выполнить в Windows 95 команду

NCBRESET на соответствующем протоколу TCP/IP номере LANA. Для начала,

не следует отдавать эту команду асинхронно, так как прежде, чем вы сможе-

те сделать что-нибудь с этим номером LANA, должен завершиться сброс. При

асинхронном выполнении команды NCBRESET приложение вызовет фаталь-

ную ошибку в драйвере виртуального устройства (virtual device driver, VXD)

NetBIOS TCP/IP и придется перезагружать компьютер.

Для любых платформПри сеансовой связи одна сторона может посылать сколь угодно много дан-

ных, однако отправитель на деле буферизует посылаемые данные, пока по-

лучатель не подтвердит их получение, отдав команду приема. NetBIOS-ко-

манды NCBSENDNA и NCBCHAINSENDNA — варианты команд отправки, не

требующие подтверждения. Вы можете использовать их, если намеренно не

хотите, чтобы команда отправки ждала подтверждения от получателя. По-

скольку в нижележащем протоколе TCP/IP реализована собственная схема

подтверждения, команды отправки, не требующие подтверждения от полу-

чателя, ведут себя так же, как и ожиадающие подтверждения.

РезюмеNetBIOS — мощный, но устаревший прикладной интерфейс. Одна из его

сильных сторон — независимость от протокола: приложения могут работать

поверх TCP/IP, NetBEUI и SPX/IPX. NetBIOS обеспечивает связь с установле-

нием логического соединения и без такового. Значительное преимущество

интерфейса NetBIOS перед Winsock — единый способ разрешения имен и

регистрации. Приложение NetBIOS нуждается только в имени NetBIOS, а

приложение Winsock, использующее разные протоколы, должно знать схе-

му адресации каждого (см. часть II).

В главе 2 речь пойдет о перенаправителе — составной части почтовых

ящиков и именованных каналов (о них — в главах 3 и 4).

Page 68: Network Programming for Microsoft Windows

Э. Джонс, Дж. Оланд

Программирование в сетях Microsoft Windows.

Мастер-класс

Перевод с английского под общей редакцией А. В. Иванова

Редактор Н. Е. Субботина

Предметный указатель С. В. Дергачев

Технический редактор Н. Г. Тимченко

Компьютерная верстка Д. В. Петухов

Дизайнер обложки Е. В. Козлова

Оригинал-макет выполнен с использованием

издательской системы Adobe PageMaker 6.0

Совместное издание издательства «Русская Редакция»

и издательства «Питер»

Лицензия ЛР № 066422 от 19.03.99 г.

Лицензия ИД № 01940 от 05.06.00 г.

Подписано в печать 30.10.01 г. Тираж 5 000 экз.

Формат 70х100/16. Физ. п. л. 38