Программирование в сетях Windows. Э. Джонс, Д. Оланд
Скачать 2.88 Mb.
|
dwErr; \\ '" }ЧуовЯя»чв*гд5 :ймдамуФ \\ ValidateArgs(argc, argv); \\ // :mmomO \\ II Перечисление и сброс номеров LANA штв)в»*вж><}м»в -вР^уноП \\ // »п в изт«у«1«10)« * ->Д \\ if ((dwErr = LanaEnum(&lenum)) != NRC_G0ODRET) iWwwrtfa г iNtjf; ta \\ { . «rrwdoo mm i i \\ printf("LanaEnum f a i l e d : Xd\n", dwErr); \, return 1; •&}№%' ,.m tnl } , й int if ((dwErr = ResetAlK&lenum, (UCHAR)MAX_SESSIONS, ' J (UCHAR)HAX_NAMES, FALSE)) 1= NRC.GOODRET) otie ,dor .me,* 1 { s.v9' p r i n t f ( " R e s e t A l l f a i l e d : Xd\n", dwErr); Г Л А В А 1 Интерфейс NetBIOS 41 Листинг 1-5. (продолжение) return 1; // Этот буфер содержит номер добавленного к каждому номеру LANA // NetBIOS-имени // dwNum = (DWORD .)GlobalAlloc(GMEH_FIXED | GMEM_ZEROINIT, sizeof(DWORD) * lenum.length); if (dwNum == NULL) { printf("out of memory\n"); return 1; // Если мы собираемся работать только на одном номере LANA, имя регистрируется // только на этом номере LANA, иначе имя регистрируется на всех // номерах LANA // if (bOneLana) П \i { if (bUniqueName) AddName(dwOneLana, szLocalName, &dwNum[0]); else AddGroupName(dwOneLana, szLocalName, &dwNura[0]); > else { for(i = 0; i < lenum.length; i++) { if (bUniqueName) AddName(lenum.lana[i], szLocalName, &dwNum[i]); else AddGroupNarne(lenum.lana[i], szLocalName, &dwNum[i]); // Отправка дейтаграмм // if (bSender) * { // Отправка с использованием широковещания .ще- II if (bBroadcast) ti { if (bOneLana) n < // Широковещательная отправка сообщения только на одном номере // LANA и . след. стр. Листинг 1 -5. (продолжение) for(j = 0; j < dwNumDatagrams; ]++) wsprintf(szMessage, "[J(03d] Test broadcast datagram", j ) ; if (DatagramSendBC(dwOneLana, dwNum[0], szMessage, strlen(szMessage)) != NRC_G00DRET) return 1; Sleep(dwDelay); f j j t ' / } ,{ г МИР To 'TUO*" 11 л else » , ! ) •( ,| < { // Широковещательная отправка сообщения на каждом номере LAN^ // на локальной машине , ,3 ^ // иг \\ for(j = 0; j < dwNumDatagrams; j++) , ,-, н ^ { \\ for(i = 0; i < lenum.length; i++) l s®r,l'4) 1i wsprintf(szMessage, } ^ "[)(03d] Test broadcast datagram", j); if (DatagramSendBC(lenum.lana[i], dwNum[i], w , £ e szMessage, strlen(szMessage)) S M # > »ЯН >¥*<•* 1= NRC_GOODRET) *®хя* n { return 1; к U» 1 } I X else " { i f •. %**< ы * S l e e p ( d w D e l a y ) ; ( n - t ; r t J 8 r > 9 } m m t n n m t t • 8 A t j a t t a l e u t * ( b O n e L a n a ) // Отправка направленного сообщения for(j = 0; j < dwNumDatagrams; j++) { '} U • { на один укщтныА :ЦН&\уМА •Ш) ft } wsprintf(szMessage, « о «ж - L "[X03d] Test directed datagram", J>; if (DatagramSend(dwOneLana, dwNum[0], (jp, Ui szRecipientName, szMessage, 1 strlen(szMessage)) != NRC.GOODRET) , return 1; Sleep(dwDelay); 4 H C , \\ else rAil f*il« Г Л А В А 1 Интерфейс NetBIOS 43 Листинг 1 -5. (продолжение) // Отправка прямого сообщения на каждом номере LANA на // локальной машине for(j = 0; j < dwNumDatagrams; { for(i = 0; i < lenum.length; wsprintf(szMessage, "[K03d] Test directed datagram", j); printf("count: Xd.JSd\n", j,i); if (DatagramSend(lenum.lana[i], dwNum[i], szRecipientName, szMessage, strlen(szMessage)) != NRCJ300DRET) return 1; } ©It 1 > > Sleep(dwDelay); else // Прием дейтаграмм { NCB *ncb=NULL; char ««szMessageArray = NULL; HANDLE *hEvent=NULL; DWORD dwRet; // Выделение массива структур NCB для передачи каждому приемнику // на каждом LANA // neb = (NCB *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(NCB) « lenum.length); // // Выделение массива буферов входящих данных // szMessageArray = (char ••)GlobalAlloc(GMEM_FIXED, sizeof(char *) • lenum.length); for(i = 0; l < lenum.length; i++) szMessageArray[i] = (char *)GlobalAlloc(GMEM_FIXED, MAX_DATAGRAM_SIZE); // // Выделение массива описателей событий для // асинхронных приемов // hEvent = (HANDLE OGlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(HANDLE) • lenum.length); for(i = 0; i < lenum.length; i++) } см. след. стр. 44 ЧАСТЬ I Устаревшие сетевые API Листинг 1-5. (продолжение) hEvent[i] = CreateEvent(O, TRUE, FALSE, 0); if (bBroadcast) { if (bOneLana) { // Синхронный широковещательный прием // на одном указанном номере LANA / / ' * • » for(j = 0; j < dwNumOatagrams; if (DatagramRecvBC(&ncb[O], dwOneLana, dwNum[0], szMessageArray[O], MAX_DATAGRAM_SIZE, NULL) != NRC_GOODRET) '*** return 1; FormatNetbiosName(ncb[0].ncb_callnarne, szSender); " printf("X03d [LANA Xd] Message: 'Xs' " "received from: Xs\n", j, * ncb[O].ncb_lana_num, szMessageArray[O], { szSender); { > < > Mitt else } { 8ОИ // Асинхронный широковещательный прием на каждом з /I доступном номере LANA. Для каждой успешной команды // печатается сообщение, иначе команда отменяется. for(] = 0; j < dwNumDatagrams; for(i = 0; i < lenum.length; i++) \\ dwBytesRead = MAX_DATAGRAM_SIZE; if (DatagramRecvBC(&ncb[i], lenum.lana[i], \\ dwNumfi], szMessageArray[i], ,кмцЛ \\ MAX_DATAGRAM_SIZE, hEvent[i]) " * $ != NRC_GOODRET) return 1; dwRet = WaitForMultipleObjects(lenum.length, hEvent, FALSE, INFINITE); if (dwRet == WAIT_FAILED) \\ < l \ \ pnntfC'WaitForMultipleObjects failed: Xd\n", t \\ GetLastErrorO); \\ return 1; K}v3rf > nl$ for(i = 0; i < lenum. length; i++) *, ,.u •• I ,0 Г Л А В А 1 Интерфейс NetBIOS 45 Листинг 1 -5. (продолжение) if (ncb[i].ncb_cmd_cplt == NRCJPENDING) Cancel(&ncb[i]); else { ncb[i].ncb_buffer[ncb[i].ncb_length] = 0; ' AVfAJ eqe FormatNetbiosName(ncb[i].ncb_callname, szSender); printf("X03d [LANA Xd] Message: 'Xs 1 " "received from: Xs\n", j, * ncb[i].ncb_lana_num, ' szMessageArray[i], szSender); f } ResetEvent(hEvent[i]); K } > m } } else { if (bOneLana) { // Блокирующий прием дейтаграмм на указанном // номере LANA // * u for(j = 0; j < dwNumDatagrams; ]++) if (bRecvAny) . // Прием данных, предназначенных для любого имени NetBIOS // в таблице имен этого процесса if (DatagramRecv(&ncb[O], dwOneLana, OxFF, szMessageArray[O], MAX_DATAGRAM_SIZE, NULL) != NRC_GOODRET) Sl return 1; } j, else { if (DatagramRecv(&ncb[O], dwOneLana, dwNum[0], szMessageArray[O], MAX_OATAGRAM_SIZE, NULL) != NRC_GOODRET) return 1; } FormatNetbiosName(ncb[0].ncb.callnarne, szSender); printf("X03d [LANA Xd] Message: 'Xs - " "received from: Xs\n", j, • . r , ncb[O].ncb_lana_num, szMessageArray[O], см. след. стр. , м р е в ш и е с е т е в ы е A K I Листинг 1-5. (продолжение) szSender); else // Асинхронный прием дейтаграмм на каждом доступном номере LANA. // Для успешных команд печатаются данные, // иначе команда отменяется. for(j = 0; 2 < dwNumDatagrams; j { for(i = 0; i < lenum.length; { If (bRecvAny) // Прием данных, предназначенных для любойо // NetBIOS в таблице имен этого процесса { // tele if (DatagramRecv(&ncb[i], lenum.lana[i], } OxFF, szMes'sageArray[i], i MAX_DATAGRAM_SIZE, hEvent[i]) } ^ |= NRC_GOODRET) return 1; 1 { 'ft t it (DatagramRecv(&ncb[l], lenum.lana[i], dwNum[l], szMessageArray[i], MAX_DATAGRAM_SIZE, hEvent[i]) |= NRC.GOODRET) return 1; , } ft» '} dwRet = WaitForMultipleObjects(lenum.length, hEvent, FALSE, INFINITE); if (dwRet == WAIT_FAILED) { printf("WaitForMultipleObjects failed: Xd\n", GetLastErrorQ); return 1; for(i = 0; i < lenum.length; i f ( n c b [ i ] . n c b _ c m d _ c p l t = = NRC_PENOING) iJV*"- C a n c e l ( & n c b [ i ] ) ; e l s e ( ncb[i].ncb_buffer[ncb[i].ncb_length] = 0; FormatNetbiosName(ncb[i].ncb_callname, Г Л А В А 1 интерфейс Netbiob 4/ Листинг 1 -5. (продолжение) szSender); printf("X03d [LANA Xd] Message: 'Xs' " "from: Xs\n", j, nob[i].ncb_lana_num, szHessageArray[i], szSender); } ResetEvent(hEvent[i]); // Очистка // for(i = 0; i < lenum.length; CloseHandle(hEvent[i]); GlobalFree(szMessageArray[i]); } -f GlobalFree(hEvent); f. GlobalFree(szMessageArray); л > // Очистка •t И if (bOneLana) DelName(dwOneLana, szLocalName); x else 3 1 f o r ( i = 0; i < lenum.length; ^ DelName(lenum.lana[i], szLocalName); } -t GlobalFree(dwNum); return 0; } Скомпилировав этот пример, выполните следующие тесты, чтобы понять, как работают дейтаграммы (табл. 1-2). В целях обучения запустите две ко- пии приложений на разных компьютерах. Если вы запустите их на одном компьютере, они будут работать, но вы можете не увидеть некоторые важ- ные моменты, так как в этом случае LANA для обеих сторон будут соответ- ствовать одному и тому же протоколу. Табл. 1-2. Команды вызова Nbdgram.c Команда клиента Команда сервера . Nbdgram /n:CLIENTO I Nbdgram /s /n:SERVER01 /r-CLIENTO 1 Nbdgram /n:CLIENT01 /b Nbdgram /s /n:SERVER01 /b Nbdgram /g:CLIENTGROUP Nbdgram /s /r.CLIENTGROUP Nbdgram /g:CLIENTGROUP Nbdgram /s /r.CLIENTGROUP 4AUI ь I Устаревшие сетевые API А теперь перечислим все параметры командной строки, доступные для использования в программе-примере: Ш /п:ту-пате — регистрирует уникальное имя ту-пате\ Ж /g:group-name — регистрирует групповое имя group -name; Ш /s — отправляет дейтаграммы (по умолчанию, в примере дейтаграммы принимаются); • /с:п — отправляет или получает п дейтаграмм; • /r:receiver — определяет NetBIOS-имя для отправки дейтаграммы; Ш /Ъ — использует широковещательную посылку дейтаграмм; Ж /а — принимает данные для любого имени NetBIOS (присваивает полю ncbjium значение OxFF); Ш /1:п — выполняет все операции только на номере LANA n (по умолчанию все команды отправки и приема выполняются для всех номеров LANA); • /d:n — ждет п миллисекунд между отправками. Для выполнения третьей команды запустите несколько клиентов на раз- ных компьютерах. Она иллюстрирует случай, когда один сервер посылает одно сообщение группе, и каждый член группы, ожидающий данные, полу- чит это сообщение. Также попробуйте различные комбинации перечисленных команд с па- раметром командной строки /1-х, где х — действительный номер LANA. Этот параметр переключает программу из режима выполнения команд на всех номерах LANA в режим выполнения команд только на конкретном номере LANA. Например, команда Nbdgram /n:CLIENT01 /1:0 заставит приложение слушать входящие дейтаграммы только на LANA 0 и игнорировать любые данные, поступающие на какой-либо другой номер LANA. Параметр /а имеет смысл только для клиентов. Этот флаг заставляет ко- манду получения принимать входящие дейтаграммы, предназначенные для любого имени NetBIOS, которое зарегистрировано процессом. В нашем при- мере это не имеет особого значения, так как клиенты регистрируют только одно имя, но вы можете по крайней мере посмотреть, как это должно выг- лядеть в коде. Попробуйте изменить код так, чтобы он регистрировал имя для каждого параметра /п-.пате в командной строке. Запустите сервер с фла- гом получателя, заданным только для одного из имен, зарегистрированных клиентом. Клиент получит данные, несмотря на то, что команда NCBDGRECV не обращается явно к конкретному имени. Дополнительные команды NetBIOS Все рассмотренные нами команды так или иначе относятся к установлению сеанса, отправке или получению данных через сеанс или дейтаграмму. Но есть несколько команд, предназначенных исключительно для обработки приема информации: команда опроса состояния адаптера (NCBASTAT) и ко- манда поиска имени (NCBFJNDNAME). Мы рассмотрим их, а затем перейдем s r Г Л А В А 1 Интерфейс NetBlUb к программному сопоставлению номеров LANA протоколам — хотя это не функция NetBIOS, но в справочных целях ознакомиться с ней полезно. Проверка состояния адаптера (команда NCBASTAT) Команда опроса состояния адаптера полезна для получения информации о локальном компьютере и его номерах LANA Это единственный способ про- граммно выяснить МАС-адрес компьютера из Windows 95 и NT 4. Функции IP Helper, появившиеся в Windows 2000 и Windows 98 (см. приложение А), предо- ставляют более универсальный интерфейс для выяснения МАС-адреса. Команда и ее синтаксис довольно просты, но то, какие данные будут воз- вращены, зависит от способа вызова функции. Команда опроса состояния адаптера возвращает структуру ADAPTER_STATUS, сопровождаемую рядом структур NAME_BUFFER. Эти структуры определены следующим образом: typedef struct _ADAPTER_STATUS { UCHAR UCHAR UCHAR UCHAR UCHAR WORD > « WORD WORD WORD WORD DWORD DWORD WORD WORD WORD WORD DWORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD > ADAPTER adapter_address[6]; rev_major; reservedO; adaptsr_type; revjninor; duration; frmr_recv; frmr_xmit; iframe_recv_err; xmit_aborts; xmit_success; recv_success; iframe_xmit_err; recv_buff_unavail; t1_timeouts; ti_timeouts; reservedi; free_ncbs; max_cfg_ncbs; max_ncbs; xmit_buf_unavail; max_dgram_size; pending_sess; max_cfg_sess; max_sess; max_sess_pkt_size; name_count; STATUS, *PADAPTER_STATUS; typedef struct _NAME_BUFFER { UCHAR name[NCBNAHSZ]; UCHAR name_num; UCHAR name_flags; } NAME.BUFFER, *PNAME_BUFFER; .IK 4'f < y o i з р е в ш и е с е т е в ы е M K I Поля, представляющие наибольший интерес: МАС-адрес (adapter_ad- dress), максимальный размер дейтаграммы (jnax_dgram_size) и максималь- ное количество сеансов (max_sess). Кроме того, поле name count сообщает, сколько было возвращено структур NAME_BUFFER. Максимальное количество NetBIOS-имен на номер LANA — 254, так что вы можете обеспечить доста- точно большой буфер для всех имен или вызвать команду опроса состояния адаптера с полем ncbjength, равным 0. Функция Netbios по завершении вы- дает необходимый размер буфера. Поля, необходимые для вызова команды NCBASTAT-. ncb_command, ncb_ buffer, ncbjength, ncbjananum и ncbjzallname. Если первый символ поля ncb_callname — звездочка ('), команда проверки состояния выполняется, но возвращает только NetBIOS-имена, добавленные вызывающим процессом. Впрочем, если вы вызываете Netbios с командой опроса состояния адаптера, добавляете уникальное имя к таблице имен текущего процесса, а затем ис- пользуете это имя в поле ncb_callname, все NetBIOS-имена, а также все име- на, зарегистрированные системой, добавляются в таблицу имен локального процесса. Вы можете также проверить состояние адаптера не с того ком- пьютера, где выполняется команда. Для этого задайте в поле ncb_callname тля удаленной рабочей станции. ПРИМЕЧАНИЕ Помните, что во всех именах компьютеров Microsoft 1б-му байту присваивается значение 0. Кроме того, они дополняются пробелами до фиксированной длины. Приведенная в качестве примера простая программа — Astat.c, проверя- ет состояние всех LANA. Кроме того, при использовании флага /1:LOCAL- NAME эта команда выполняется на локальном компьютере, но выдает пол- ную таблицу имен. Флаг /r:REMOTENAME инициирует удаленный опрос для указанного имени компьютера. При использовании команды, проверяющей состояние адаптера, нужно учитывать некоторые моменты. Во-первых, у компьютера с несколькими адаптерами будет несколько МАС-адресов. Так как NetBIOS не позволяет вы- яснить, к которым адаптерам и протоколам привязан LANA, разбираться в возвращенных значениях придется самостоятельно. Кроме того, если уста- новлена служба удаленного доступа (Remote Access Service, RAS), система вы- делит номера LANA и для удаленных соединений. Пока соединения RAS не- активны, проверка состояния адаптера на этих LANA вернет нулевой МАС- адрес. Если установлено соединение RAS, МАС-адрес будет соответствовать тому который служба RAS назначает всем своим виртуальным сетевым уст- ройствам. Наконец, проверку состояния удаленного адаптера вы должны выполнять по общему для обоих компьютеров транспортному протоколу. Например, системная команда Nbtstat (версия NCBASTATрдя командной строки) выпол- няет опрос только по TCP/IP. Если на удаленном компьютере нет TCP/IP, ко- манда не будет выполнена. |