А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Протокол TCP не поддерживает многоадресную рассылку, поэтому все, что далее будет сказано, относится только к протоколу UDP. Отметим также, что при многоадресной рассылке через границы подсетей маршрутизаторы должны поддерживать передачу многоадресных пакетов. Глава "Многоадресная рассылка" в [3], к сожалению, содержит множество неточностей. Далее мы будем обращать внимание на эти неточности, чтобы облегчить чтение этой книги.
Многоадресная рассылка в IP является одноранговой и в плоскости управления, и в плоскости данных (в [3] вместо "одноранговая" употребляется слово "немаршрутизируемая" — видимо, переводчик просто перепутал слова non-rooted и non-routed). Это значит, что все сокеты, участвующие в ней, paвноправны. Каждый сокет без каких-либо ограничений может подключиться к многоадресной группе и получать все сообщения, отправленные на групповой адрес. При этом послать сообщение на групповой адрес может любой сокет, в том числе и не входящий в группу. Для групповых адресов протокол IP задействует диапазон от 224.0.0.0 до 239.255.255.255. Часть из этих адресов зарезервирована для стандартных служб, поэтому своим группам лучше назначать адреса, начиная с 225.0.0.0. Кроме того, весь диапазон от 224.0.0.0 до 224.0.0.255 зарезервирован для групповых сообщений, управляющих маршрутизаторами, поэтому сообщения, отправленные на эти адреса, никогда не передаются в соседние подсети.
Есть два варианта осуществления многоадресной рассылки с использованием IP средствами WinSock. Первый реализуется средствами WinSock 1 и жестко привязан к протоколу IP. Второй вариант подразумевает работу с WinSock 2 и осуществляется универсальными, не привязанными к конкретному протоколу средствами.
Если рассылка будет осуществляться средствами WinSock 1, то сокет, участвующий в ней, создается обычным образом — с помощью функции WSASocket
со стандартным набором флагов или с помощью функции socket
с обычными параметрами, задаваемыми при создании UDP-сокета. Если же используется WinSock 2, то сокет должен быть создан с указанием его роли в плоскостях управления и данных. Так как многоадресная рассылка в IP является одноранговой, все сокеты, участвующие в ней, могут быть только "листьями", поэтому сокет для рассылки должен создаваться функцией WSASocket
с указанием флагов WSA_FLAG_MULTIPONT_C_LEAF
(4) и WSA_FLAG_MULTIPOINT_D_LEAF
(16). В [3] на странице 313 написано, что для рассылки средствами WinSock 2 можно создавать сокет функцией socket
— это неверно. Впрочем, на странице 328 все-таки сказано, что указанные флаги задавать обязательно. Далее сокет, который планируется добавить в группу, привязывается к любому локальному порту обычным способом — с помощью функции bind
. Этот шаг ничем не отличается от привязки к адресу обычного сокета, не использующего групповой адрес.
Затем выполняется собственно добавление сокета в группу. В WinSock 12 для этого потребуется функция setsockopt
с параметром IP_ADD_MEMBERSHIP
, в качестве уровня следует указать IPPROTO_IP
. При этом через параметр optval
передается указатель на запись ip_mreq
, описанную так, как показано в листинге 2.79.
TIPMreq
// ***** Описание на C++ *****
struct ip_mreq {
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
}
// ***** Описание на Delphi *****
TIPMreq = packed record
IMR_MultiAddr: TSockAddr;
IMR_Interface: TSockAddr
end;
Поле IMR_MultiAddr
задает групповой адрес, к которому присоединяется сокет. У этой структуры должны быть заполнены поля sin_family
(значением AF_INET
) и sin_addr
. Номер порта здесь указывать не нужно, значение этого поля игнорируется. Поле IMR_Interface
определяет адрес сетевого интерфейса, через который будет вестись прием многоадресной рассылки. Если программу устраивает интерфейс, выбираемый системой по умолчанию, значение поля IMR_Interface.sin_addr
должно быть INADDR_ANY
(на компьютерах с одним сетевым интерфейсом обычно используется именно это значение). Но если у компьютера несколько сетевых интерфейсов, которые связывают его с разными сетями, интерфейс для получения групповых пакетов, выбираемый системой по умолчанию, может быть связан не с той сетью, из которой они реально ожидаются. В этом случае программа может явно указать IP-адрес того интерфейса, через который данный сокет должен принимать групповые пакеты. Как и в поле IMR_MultiAddr
, в поле IMR_Interface
задействованы только поля sin_familу
и sin_addr
, а остальные поля игнорируются.
Для прекращения членства сокета в группе служит та же функция setsockopt
, но с параметром IP_DROP_MEMBERSHIP
. Через параметр optval
при этом также передается структура ip_mreq
, значимые поля которой должны быть заполнены так же, как и при добавлении данного сокета в данную группу. Несмотря на то, что структура ip_mreq
относится к WinSock 1, в модуле WinSock ее описание отсутствует. Константы IP_ADD_MEMBERSHIP
и IP_DROP_MEMBERSHIP
в этом модуле объявлены, но работать с ними следует с осторожностью, потому что они должны иметь разные значения в WinSock 1 и WinSock 2. В WinSock 1 они должны иметь значения 5 и 6 соответственно, а в WinSock 2 — 12 и 13. Из-за этого нужно внимательно следить, чтобы значения соответствовали той библиотеке, из которой импортируется функция setsockopt: 5 и 6 — для WSock32.dll и 12 и 13 — для WS2_32.dll.
В WinSock 2 для присоединения сокета к группе объявлена функция WSAJoinLeaf
, прототип которой приведен в листинге 2.80.
WSAJoinLeaf
// ***** описание на C++ *****
SOCKET WSAJoinLeaf(SOCKET s, const struct sockaddr FAR *name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS, LPQOS lpGQOS, DWORD dwFlags);
// ***** описание на Delphi *****
function WSAJoinLeaf(S: TSocket; var Name: TSockAddr; NameLen: Integer; lpCallerData, lpCalleeData: PWSABuf; lpSQOS, lpGQOS: PQOS; dwFlags: DWORD): TSocket;
Параметры lpCallerData
и lpCalleeData
задают буферы, в которые помещаются данные, передаваемые и получаемые при присоединении к группе. Протокол IP не поддерживает передачу таких данных, поэтому при его использовании эти параметры должны быть равны nil
. Параметры lpSQOS
и lpGQOS
относятся к качеству обслуживания, которое мы здесь не рассматриваем, поэтому их мы тоже полагаем равными nil
.
Параметр S
определяет сокет, который присоединяется к группе, Name
— адрес группы, NameLen
— размер буфера с адресом. Параметр dfFlags
определяет, будет ли сокет служить для отправки данных ( JL_SENDER_ONLY
, 1), для получения данных ( JL_RECEIVER_ONLY
, 2) или и для отправки, и для получения ( JL_BOTH
, 4).
Функция возвращает сокет, который создан для взаимодействия с группой. В протоколах типа ATM подключение к группе похоже на установление связи в TCP, и функция WSAJoinLeaf
, подобно функции accept
, создаёт новый сокет, подключенный к группе. В случае UDP новый сокет не создается, и функция WSAJoinLeaf
возвращает значение переданного ей параметра S
.
Интервал:
Закладка: