Главная страница

Программирование в сетях Windows. Э. Джонс, Д. Оланд


Скачать 2.88 Mb.
НазваниеЭ. Джонс, Д. Оланд
АнкорПрограммирование в сетях Windows.pdf
Дата12.10.2017
Размер2.88 Mb.
Формат файлаpdf
Имя файлаПрограммирование в сетях Windows.pdf
ТипКнига
#9346
страница5 из 50
1   2   3   4   5   6   7   8   9   ...   50
Листинг 1-4. Клиент на основе асинхронных событий (Nbclient.c)
// Nbclient с
((include
«include
((include

Г Л А В А 1 Интерфейс NetBIOS
31
Листинг 1 -4. (продолжение)
«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, mt 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)
{
pnntf( ERROR Netbios NCBCONNECT Xd\n",
pncb->ncb_retcode),
return pncb->ncb_retcode,
}
return NRCJ3OODRET,
// Функция main
//
// Описание
// Инициализирует интерфейс NetBIOS, распределяет некоторые ресурсы
// (описатели событий, буфер отправки и т п ) и дает команду
// NCBCALL для каждого номера LANA на указанном сервере Когда соединение
// создано, отменяет или разрывает любые неудавшиеся
// соединения Затем посылает/получает данные Наконец, выполняет очистку
ян
>uki
&*
см след. стр.

32 ЧАСТЬ I Устаревшие сетевые API
Листинг 1 -4. {продолжение)
int. main(int argc, char **argv)
HANDLE
NCB
char
DWORD
LANA.ENUM
int if (argc !=
• hArray;
*pncb;
szSendBuff[MAX_BUFFER];
dwBufferLen,
dwRet,
dwlndex,
dwNum;
lenum;
1;
3)
printf("usage: nbclient CLIENT-NAME SERVER-NAHE\n");
return 1;
}
// Перечисление и сброс всех номеров LANA
// . .
if (LanaEnum(&lenum) != NRC_GOODRET) j return 1; .
t q
if (ResetAll(&lenum, (UCHAR)MAX_SESSIONS, (UCHAR)MAX_NAMES, iq
FALSE) != NRC_GOODRET)
return 1;
strcpy(szServerName, argv[2]);
//
// Выделение массива описателей для использования асинхронных событий. l
// Выделение массива структур NCB. Нам нужен один описатель !
// и одна структура NCB для каждого номера LANA.
// f hArray = (HANDLE *)GlobalAlloc(GMEM_FIXED,
sizeof(HANDLE) * lenum.length);
pncb = (NCB *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(NCB) * lenum.length);
//
a
// Создание события и присвоение его соответствующей структуре NCB,
{
// начало асинхронного соединения (NCBCALL). {
// Не забудьте добавить имя клиента к каждому номеру
// LANA, no которому он хочет соединиться. .^
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 Интерфейс NetBIOS 33
Листинг 1 -4. (продолжение)
II
dwlndex = WaitForMultipleObjectsQenum.length, hArray, FALSE,
INFINITE);
if (dwlndex == WAIT_FAILED)
{
printfC'ERROR: WaitForMultipleObjects: Xd\n",
GetLastErrorO);
else
// Если успешно более чем одно соединение, лишние
// соединения разрываются. Мы будем использовать соединение, возвращенное
// WaitForMultipleObjects, иначе если оно еще не установлено,
// отменим его.
//
for(i = 0; 1 < lenum.length; i++)
{
if (i != dwlndex)
{
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; Xd\n", pncb[dwlndex].ncb_lana_num);
rti- //
i // Отправка и прием сообщений к
for(i = 0; i < 20; i i' wsprintf(szSendBuff, "Test message X03d", i);
dwRet = Send(pncb[dwlndex].ncb_lana_num,
"* pncb[dwlndex].ncb_lsn, szSendBuff,
'*«' strlen(szSendBuff));
•A'i if (dwRet 1= NRCJ300DRET)
break;
dwBufferLen = MAX_BUFFER;
dwRet = Recv(pncb[dwlndex].ncb_lana_num,
pncb[dwlndex].ncb_lsn, szSendBuff, &dwBufferLen);
if (dwRet != NRC_GOODRET)
break;
szSendBuff[dwBufferLen] = 0;
printf("Read: • X s ' W , szSendBuff);
}
Hangup(pncb[dwlndex].ncb_lana_num, pncb[dwlndex].ncb_lsn);
}
// Очистка
см. след. стр.

34 ЧАСТЬ I Устаревшие сетевые API
Листинг 1-4. (продолжение)
//
for(i = 0, 1 < lenum length,
DelName(lenum lana[i], argv[1]),
CloseHandle(hArray[i]),
}
GlobalFree(hArray),
GlobalFree(pncb),
return 0,
Дейтаграммные операции
Дейтаграмма — это способ связи без установления логического соединения
Отправитель просто направляет каждый пакет по указанному имени NetBIOS
Целостность данных и порядок доставки пакетов не гарантируются
Есть три способа отправить дейтаграмму Первый — направить дейтаг- рамму на определенное (уникальное или групповое) имя Это означает, что получить эту дейтаграмму может только процесс, зарегистрировавший имя приемника Второй способ — отправить дейтаграмму на групповое имя тог- да получить сообщение смогут только процессы, зарегистрировавшие дан- ное имя Наконец, третий способ — широковещательно разослать дейтаг- рамму по всей сети Такую дейтаграмму сможет получить любой процесс на любой рабочей станции в локальной сети Для отправки дейтаграммы на уникальное или групповое имя применяется команда NCBDGSEND, а для широковещания — NCBDGSENDBC
Отправить дейтаграмму с помощью любой из этих команд элементарно
Определите для поля ncb_num значение номера имени, возвращенного ко- мандой NCBADDNAME или NCBADDGRNAME Этот номер идентифицирует от- правителя сообщения Присвойте полю ncbjmffer значение адреса буфера, со- держащего отправляемые данные, а полю ncbjength — количество отправля- емых байтов Затем задайте для поля ncbjanajnum значение номера LANA, по которому хотите передать дейтаграмму Наконец, присвойте полю ncbjcal-
Iname значение NetBIOS-имени приемника Это может быть уникальное или групповое имя Чтобы широковещательно послать дейтаграмму, выполните все описанные шаги, кроме последнего так как сообщение получат все рабо- чие станции, присвоение значения полю neb_callname не требуется
Конечно, в каждом из перечисленных сценариев отправления должна быть соответствующая команда получения дейтаграммы для фактического приема данных Дейтаграммы не требуют установки соединения, если дей- таграмма достигает клиента, а у клиента нет уже ожидающей команды по- лучения, данные теряются и клиент не может их восстановить (если сервер не отправит их снова) Это недостаток дейтаграммной связи Впрочем, об- мен дейтаграммами намного быстрее, чем сеансовая связь — не нужно про- верять ошибки, устанавливать соединение и т п

Г Л А В А 1 Интерфейс NetBIOS 35
Для получения дейтаграмм также предусмотрено три способа Первые два используют команду NCBDGRECV Прежде всего, вы можете отдать команду приема дейтаграммы для сообщений, направленных на конкретное имя —
уникальное или групповое Во-вторых, вы вправе отдать такую команду для любой дейтаграммы, предназначенной для любого имени в таблице имен процесса NetBIOS И наконец, отдайте такую команду для широковещатель- ной дейтаграммы с помощью команды NCBDGRECVBC
ПРИМЕЧАНИЕ Невозможно дать команду асинхронного приема дей- таграмм, предназначенных для имени, которое зарегистрировано иным процессом, если только оба процесса не зарегистрировали групповое имя (тогда они могут получить одно и то же сообщение)
Чтобы отдать команду приема, присвойте полю ncbjium значение номе- ра имени, возвращенного успешным вызовом NCBADDNAME или NCBADDGR-
NAME Этот номер определяет, для какого имени вы слушаете входящие дей- таграммы Если вы присваиваете этому полю значение OxFF, то будете полу- чать дейтаграммы, предназначенные для любого имени в таблице имен Net-
BIOS этого процесса Создайте буфер для получения данных и присвойте полю ncb_buffer значение адреса буфера Присвойте полю ncbjength значение размера буфера Наконец, задайте для поля ncb_lana_num значение номера
LANA, на котором надо ждать дейтаграммы После возвращения успешного вызова Netbios с командой NCBDGRECV или NCBDGRECVBC поле ncbjength
будет содержать фактическое количество полученных байтов, а поле ncb_cal-
Iname — NetBIOS-имя процесса отправки
Код в листинге 1-5 содержит основные дейтаграммные функции Вся от- правка реализуется блокирующими вызовами как только команда выдана и данные отправлены, функция завершается и вам не грозит блокировка из- за переполнения буфера данными Вызовы приема — асинхронные события,
так как неизвестно на каком из номеров LANA будут получены данные Код похож на код сервера сеансов, использующего события Для каждого номе- ра LANA код отдает асинхронную команду NCBDGRECV или NCBDGRECVBC
и ждет, пока она не достигнет успеха Затем проверяются все асинхронные команды, печатаются сообщения о тех, которые были успешны, и отменяют- ся еще ожидающие команды В примере есть функции, как для направлен- ного, так и для широковещательного отправления и приема Программа мо- жет быть скомпилирована в пример приложения, конфигурируемого для от- правки или получения дейтаграмм Несколько параметров командной стро- ки позволяют пользователю указать количество отправляемых или прини- маемых дейтаграмм, задержку между отправками, использование широкове- щательных, а не направленных дейтаграмм, получение дейтаграмм для лю- бого имени и т п
Листинг 1-5. Пример работы NetBIOS с дейтаграммами (Nbdgram.c)
// Nbdgram с
W §
«include * i«
)in)t i см cjieo.cmp.

36
ЧАСТЬ I Устаревшие сетевые API
Листинг 1-5. (продолжение)
«include
«include
«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;
char szLocalName[NCBNAMSZ + 1],
szRecipientName[NCBNAMSZ + 1 ] ;
DWORD dwNumDatagrams = 25,
dwOneLana,
dwDelay = 0;
// Отправка или прием дейтаграмм
// Прием для любого имени
// Зарегистрировать мое имя как уникальное?
// Использовать широковещательные
// Использовать все LANA или только один?
// Локальное NetBIOS-имя
// NetBIOS-имя приема
// Количество отправляемых дейтаграмм
// Если использовать один LANA, то какой?
// Задержка между отправками дейтаграмм
// Функция: ValidateArgs
// Описание:
// Эта функция анализирует аргументы командной строки
// и устанавливает различные глобальные флаги, соответствующие выбору
void ValidateArgs(int argc, char **argv)
int i;
for(i = 1; i < argc;
{
if (strlen(argv[i]> < 2)
continue;
if ((argv[i][0] == •-') || (argv[i][0]
{
switch (tolower(argv[i][1]))
V))
case 'n': // Используется уникальное имя
bUniqueName = TRUE;
if (strlen(argv[i]) > 2)
strcpy(szLocalName, &argv[i][3]);
break;
case 'g
1
: // Используется групповое имя
bUniqueName = FALSE;
M
if (strlen(argv[i]) > 2)

Г Л А В А 1 Интерфейс NetBIOS
37
Листинг 1-5.
if-
t/
2»'
i f дв*|«грамм
tf
printr return
strcpy(szLocalName, &argv[i][3]);
break;
case 's': // Отправка дейтаграмм
bSender = TRUE;
break;
case 'с': // Количество дейтаграмм для отправки или приема
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 '1'; // Работа только на этом номере 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)
см. след. стр-

38 ЧАСТЬ I Устаревшие сетевые API
Листинг 1-5. (продолжение)
NCB neb;
ZeroMemory(&ncb, sizeof(NCB));
ncb.ncb_command = NCBDGSEND;
ncb.ncb_lana_num = lana;
neb.ncb_num = num;
ncb.ncb_buffer = (PUCHAR)buffer; '
ncb.ncb_length = buflen;
Л
memset(ncb.ncb_callname, ' ', NCBNAMSZ);
strncpy(ncb.ncb_callname, recipient, strlen(recipient)); ywn <•<•»«<>#
ч
if (Netbios(&ncb) != NRC_G00DRET)
{
printf("Netbios: NCBDGSEND failed: Xd\n", neb.ncb_retcode);
return ncb.ncb_retcode;
}
return NRC_G00DRET;
// Функция: DatagramSendBC
//
// Описание:
// Посылает широковещательную дейтаграму по конкретному номеру LANA с
// данного номера имени. Также указаны буфер данных и количество
// отправляемых байт.
//
int DatagramSendBC(int lana, int num, char «buffer, mt buflen)
{
NCB neb;
ZeroMemory(&ncb, sizeof(NCB));
ncb.neb_command = NCBDGSENDBC; {
neb.ncb_lana_num = lana; ?вч
ncb.ncb_num = num; {
ncb.ncb_buffer = (PUCHAR)buffer; 7
ncb.ncb_length = buflen; \\
&Q :m '*
if (Netbios(&ncb) 1= NRC.GOODRET)
{
printfC'Netbios: NCBDGSENDBC failed: Xd\n", ncb.ncb.retcode);
return ncb.ncb_retcode;
}
return NRC.GOODRET;
J .Jflftt!
1

Г Л А В А 1 Интерфейс NetBIOS
39
Листинг 1-5. (продолжение)
II Функция: DatagramRecv
//
// Описание:
// Получает дейтаграмму на данном номере LANA направленную по имени,
// представленному параметром num. Данные копируются в предоставленный буфер.
// Если hEvent не 0, вызов приема выполняется асинхронно
// с указанным описателем события. Если параметр num равен OxFF, слушает
// дейтаграммы, предназначенные для любого имени 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; „ s ,
a j A i ! ч1
if (Netbios(pncb) != NRC_G00DRET)
{
printf("Netbos: NCBDGRECV failed: И\п", pncb->ncb_retcode);
return pncb->ncb_retcode;
} I8J*.
return NRC_GOODRET; ,|
// Функция: DatagramRecvBC
//
// Описание:
// Получает широковещательную дейтаграмму на данном номере LANA.
// Данные копируются в предоставленный буфер. Если hEvent не равно О,
// вызов приема выполняется асинхронно с указанным
// описателем события.
//
int DatagramRecvBC(PNCB pncb, int lana, int num, char «buffer,
int buflen, HANDLE hEvent)
ZeroHemory(pncb, sizeof(NCB));
if (hEvent)
,"n/bt :to9ix*1
см.след.стр.

Листинг 1-5. (продолжение)
{
pncb->ncb_command = NCBDGRECVBC | ASYNCH;
pncb->ncb_event = hEvent;
}
else pnob->ncb_comrnand = NCBDGRECVBC;
pncb->ncb_lana_num = lana; *t t
pncb->ncb_num = nuin; Ь >
pncb->ncb_buffer = (PUCHAR)buffer; ы к ч pncb->ncb_length = buflen;
tni
'if (Netbios(pncb) != NRC_G00DRET)
*{
printf("Netbios: NCBDGRECVBC failed: Xd\n", pncb->ncb_retcode);
return pncb->ncb_retcode;
return NRC_G00DRET; щ
II Функция: main
// %
II Описание: З
// Инициализирует интерфейс NetBIOS, выделяет ресурсы, а затем отправляет илщ
// получает дейтаграммы согласно пользовательским параметрам I
//
int main(int argc, char *»argv) W; 4
i )
LANA_ENUM lenum; »«")t-- ,
int i, j ; •*} '*'
char ' '' szMes9age[MAX_DATAGRAM_SIZE], {
szSender[NCBNAMSZ + 1 ] ; < ЗЙТО8.,/ '«Jei
DWORD «dwNufli = NULL, {
dwBytesRead,
1   2   3   4   5   6   7   8   9   ...   50


написать администратору сайта