Используя CFNetServices
CFNetServices
API в CFNetwork
платформа (Базовый уровень Основы), который позволяет Вам публиковать или искать сетевые службы.
На высоком уровне, CFNetServices
API обеспечивает доступ к Добрый день через три объекта:
CFNetService
— Объект, представляющий единственную службу на сеть. ACFNetService
объект имеет имя, тип, домен и номер порта. Типы службы, используемыеCFNetServices
сохраняются в http://www .dns-sd.org/servicetypes.html.CFNetServiceBrowser
— Объект, используемый, чтобы обнаружить домены и обнаружить сетевые службы в доменах.CFNetServiceMonitor
— Объект раньше контролировал службы для изменений в их записях TXT.
Публикация службы Используя CFNetServices
Публикация службы на сеть включает две задачи: создание службы и регистрация службы. Следующие два раздела описывают то, что требуется, чтобы выполнять эти две задачи.
Создание объекта CFNetService
Создать a CFNetService
объект, вызвать CFNetServiceCreate
и предоставьте следующую информацию о службе:
Имя. Человекочитаемое имя службы (такой как “
Sales Laser Printer
”)Тип службы. Тип службы, такой как “
_printer._tcp
“;Домен. Домен для службы, обычно пустая строка (
CFSTR("")
) для домена (ов) по умолчанию, илиlocal.
для локального домена толькоПорт. Номер порта служба слушает на
Если Вы реализуете протокол, полагающийся на данные, хранившие в текстовых записях DNS, можно связать ту информацию с a CFNetService
объект путем вызова CFNetServiceSetTXTData
).
Свяжите функцию обратного вызова с Вашим CFNetService
объект путем вызова CFNetServiceSetClient
. Вашу функцию обратного вызова вызывают для создания отчетов об ошибках, происходящих, в то время как служба работает и сообщить относительно состояния публикации.
Если Вы захотите, чтобы служба работала асинхронно, то необходимо также запланировать службу на цикл выполнения путем вызова CFNetServiceScheduleWithRunLoop
; иначе, служба будет работать синхронно. Для получения дополнительной информации о режимах, в которых служба может работать, seeAsynchronous и Синхронные Режимы.
Перечисление a-1 показывает, как создать a CFNetService
объект.
Перечисление a-1 , создающее a CFNetService
объект
CFStringRef serviceType = CFSTR("_printer._tcp"); |
CFStringRef serviceName = CFSTR("Sales Laser Printer"); |
CFStringRef theDomain = CFSTR(""); |
int chosenPort = 515; |
CFNetServiceRef netService = CFNetServiceCreate(NULL, theDomain, serviceType, serviceName, chosenPort); |
Регистрация CFNetService
Для предоставления доступа к службе доступной в сети вызвать CFNetServiceRegisterWithOptions
. (Эта работа также известна как «публикация» службы.) Служба может тогда быть найдена клиентами, пока Вы не не регистрируете службу путем вызова CFNetServiceCancel
.
См. Перечисление a-2 для примера кода на этом предмете.
Перечисление a-2 , Регистрирующее асинхронную службу
void registerCallback ( |
CFNetServiceRef theService, |
CFStreamError* error, |
void* info) |
{ |
// ... |
} |
void startBonjour (CFNetServiceRef netService) { |
CFStreamError error; |
CFNetServiceClientContext clientContext = { 0, NULL, NULL, NULL, NULL }; |
CFNetServiceSetClient(netService, registerCallback, &clientContext); |
CFNetServiceScheduleWithRunLoop(netService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); |
CFOptionFlags options = 0; // or kCFNetServiceFlagNoAutoRename |
if (CFNetServiceRegisterWithOptions(netService, options, &error) == false) { |
CFNetServiceUnscheduleFromRunLoop(netService, CFRunLoopGetCurrent(),kCFRunLoopCommonModes); |
CFNetServiceSetClient(netService, NULL, NULL); |
CFRelease(netService); |
fprintf(stderr, "could not register Bonjour service"); |
} |
} |
Просмотр для использования Служб CFNetServices
Просмотреть для служб, представленных a CFNetService
объект, вызвать CFNetServiceBrowserCreate
и обеспечьте указатель на функцию обратного вызова, которую вызовут, поскольку найдены службы.
Если Вы захотите, чтобы поиски были проведены асинхронно, то необходимо также запланировать браузер на цикл выполнения путем вызова CFNetServiceBrowserScheduleWithRunLoop
.
Для просмотра для служб можно вызвать CFNetServiceBrowserSearchForServices
и укажите службы для поиска. Для доменного параметра у Вас есть две опции. Рекомендуется передать пустую строку (CFSTR("")
) как домен, позволяя Вам обнаружить службы в любом домене, на котором регистрируется Ваша система. Также можно указать домен для поиска в. Вашу функцию обратного вызова вызовут и передадут a CFNetService
объект, представляющий службу соответствия. CFNetServiceBrowser
объект продолжает искать, пока Ваше приложение не останавливает поиск путем вызова CFNetServiceBrowserStopSearch
.
Для каждого CFNetService
возразите, что Ваша функция обратного вызова получает, можно вызвать CFNetServiceResolveWithTimeout
обновить службу с IP-адресом для службы. Тогда вызовите CFNetServiceGetAddressing
получить массив CFDataRef
объекты, один для каждого IP-адреса связались со службой. Каждый CFDataRef
объект, в свою очередь, содержит a sockaddr
структура с IP-адресом.
Хороший пример того, как просмотреть для служб, может быть замечен в Перечислении a-3.
Перечисление a-3 , Просматривающее асинхронно для служб
void MyBrowseCallBack ( |
CFNetServiceBrowserRef browser, |
CFOptionFlags flags, |
CFTypeRef domainOrService, |
CFStreamError* error, |
void* info) |
{ |
// ... |
} |
static Boolean MyStartBrowsingForServices(CFStringRef type, CFStringRef domain) { |
CFNetServiceClientContext clientContext = { 0, NULL, NULL, NULL, NULL }; |
CFStreamError error; |
Boolean result; |
assert(type != NULL); |
CFNetServiceBrowserRef gServiceBrowserRef = CFNetServiceBrowserCreate(kCFAllocatorDefault, MyBrowseCallBack, &clientContext); |
assert(gServiceBrowserRef != NULL); |
CFNetServiceBrowserScheduleWithRunLoop(gServiceBrowserRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); |
result = CFNetServiceBrowserSearchForServices(gServiceBrowserRef, domain, type, &error); |
if (result == false) { |
// Something went wrong, so let's clean up. |
CFNetServiceBrowserUnscheduleFromRunLoop(gServiceBrowserRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); CFRelease(gServiceBrowserRef); |
gServiceBrowserRef = NULL; |
fprintf(stderr, "CFNetServiceBrowserSearchForServices returned (domain = %ld, error = %d)\n", (long)error.domain, error.error); |
} |
return result; |
} |
Разрешение службы Используя CFNetServices
После того, как у Вас есть имя, введите, и домен, можно разрешить службу для получения ее имени хоста и порта. Как с регистрацией службы, разрешая службу также требует a CFNetServiceRef
объект. Если у Вас уже есть один (обычно полученный посредством обратного вызова работы обзора), Вы не должны принимать дальнейшие меры. Иначе, можно создать тот сами путем вызова CFNetServiceCreate
.
Если Вы планируете разрешить службу асинхронно, связаться недавно создаваемый CFNetServiceRef
объект с функцией обратного вызова, которая получит a CFNetServiceRef
возразите и указатель на a CFStreamError
объект. Можно установить этот обратный вызов путем вызова CFNetServiceSetClient
. Обязательно вызовите CFNetServiceScheduleWithRunLoop
позже для добавления службы к циклу выполнения (который обычно является результатом вызова к CFRunLoopGetCurrent
).
После установки цикла выполнения вызвать CFNetServiceResolve
. Если этот вызов возвращает ошибку, необходимо очистить все ссылки, которые Вы создали. Иначе, просто ожидайте своих функций обратного вызова, которые вызовут.
Пример разрешения службы с CFNetService
находится в Перечислении a-4.
Перечисление a-4 , Разрешающее службу асинхронно
void MyResolveCallback ( |
CFNetServiceRef theService, |
CFStreamError* error, |
void* info) |
{ |
// ... |
} |
static void MyResolveService(CFStringRef name, CFStringRef type, CFStringRef domain) |
{ |
CFNetServiceClientContext context = { 0, NULL, NULL, NULL, NULL }; |
CFTimeInterval duration = 0; // use infinite timeout |
CFStreamError error; |
CFNetServiceRef gServiceBeingResolved = CFNetServiceCreate(kCFAllocatorDefault, domain, type, name, 0); |
assert(gServiceBeingResolved != NULL); |
CFNetServiceSetClient(gServiceBeingResolved, MyResolveCallback, &context); |
CFNetServiceScheduleWithRunLoop(gServiceBeingResolved, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); |
if (CFNetServiceResolveWithTimeout(gServiceBeingResolved, duration, &error) == false) { |
// Something went wrong, so let's clean up. |
CFNetServiceUnscheduleFromRunLoop(gServiceBeingResolved, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); |
CFNetServiceSetClient(gServiceBeingResolved, NULL, NULL); |
CFRelease(gServiceBeingResolved); |
gServiceBeingResolved = NULL; |
fprintf(stderr, "CFNetServiceResolve returned (domain = %ld, error = %d)\n", (long)error.domain, error.error); |
} |
return; |
} |
Контроль службы Используя CFNetServices
CFNetServiceMonitor
позволяет Вам наблюдать службы за изменениями в TXT
записи.
В приложении, публикующем службу, можно обеспечить пользовательское TXT
запись путем вызова CFNetServiceSetTXTData
. Самый прямой способ предоставить совместимые спецификацией данные путем вызова CFNetServiceCreateTXTDataWithDictionary
и передача его словарь значений для публикации.
В приложении, которое должно контролировать службу, выполните следующие шаги:
После того, как у Вас есть a
CFNetServiceRef
объект для службы Вы хотите контролировать, создать ссылку монитора (CFNetServiceMonitorRef
) путем вызоваCFNetServiceMonitorCreate
.Запланируйте ссылку монитора на цикл выполнения с
CFNetServiceMonitorScheduleWithRunLoop
. (Можно получить выполненный цикл по умолчанию путем вызоваCFRunLoopGetCurrent
.)Запустите монитор путем вызова
CFNetServiceMonitorStart
, передача его ссылка монитора и функция обратного вызова для обработки получающихся данных. Обязательно проверьте возвращаемое значение, чтобы гарантировать, что монитор запустился успешно.В функции обратного вызова, самый прямой способ обработать
TXT
данные путем вызоваCFNetServiceCreateDictionaryWithTXTData
получить словарь, содержащий исходные пары ключ/значение.
Когда Вы больше не должны будете контролировать службу, вызвать CFNetServiceMonitorStop
(для остановки контроля), CFNetServiceMonitorUnscheduleFromRunLoop
(чтобы не запланировать Ваш монитор от его цикла выполнения), и CFNetServiceMonitorInvalidate
(для уничтожения ссылки монитора).
Асинхронные и синхронные режимы
Несколько CFNetServices
функции могут работать в асинхронном или синхронном режиме. Планирование a CFNetService
или CFNetServiceBrowser
объект на цикле выполнения заставляет службу или браузер работать в асинхронном режиме. Если a CFNetService
или CFNetServiceBrowser
объект не планируется на цикл выполнения, он работает в синхронном режиме. Работа в асинхронном режиме изменяет поведение своих функций.
Несмотря на то, что возможно использовать синхронные режимы этих функций, иметь в виду, что недопустимо блокировать пользовательский интерфейс или другие функции Вашей программы, в то время как Вы ожидаете синхронных функций для возврата. Поскольку сетевые операции могут занять произвольное количество времени для завершения, оно настоятельно рекомендовано это, Вы используете асинхронные режимы каждой функции.
Таблица a-1 описывает различия в поведении между синхронными и асинхронными режимами.
Функция | Асинхронный режим | Синхронный режим |
---|---|---|
Запускает регистрацию и возвраты. Функция обратного вызова для | Блоки до Вашего приложения отменяют службу от другого потока или пока ошибка не происходит, в которой точке возвращается функция. Если ошибка происходит, ошибка возвращается через предоставленную ошибочную структуру. Служба доступна в сети, пока Ваше приложение не отменяет регистрацию, или ошибка происходит. | |
Запускает разрешение и возвраты. Функция обратного вызова для | Блоки по крайней мере до одного IP-адреса найдены для службы, ошибка происходит, время, указанное, поскольку параметр тайм-аута достигнут, или Ваше приложение отменяет разрешение, в которой точке возвращается функция. Если ошибка происходит, ошибка возвращается через предоставленную ошибочную структуру. Работа разрешения продолжает работать, пока Ваше приложение не отменяет ее, или ошибка происходит. | |
Запускает поиск и возвраты. Функция обратного вызова для | Блоки до ошибки происходят или Ваши вызовы приложения | |
Запускает поиск и возвраты. Функция обратного вызова для | Блоки до ошибки происходят или до Ваших вызовов приложения |
Закрытие служб и поисков
Для закрытия службы, работающей в асинхронном режиме приложение не планирует службу от всех циклов выполнения, на которые это может быть запланировано. Приложение тогда вызывает CFNetServiceSetClient
с clientCB
набор параметра к NULL
разъединять Вашу функцию обратного вызова с CFNetService
объект. Наконец, вызовы приложения CFNetServiceCancel
остановить службу.
Для закрытия службы, работающей в синхронном режиме приложение только должно вызвать CFNetServiceCancel
от другого потока.
Перечисление a-5 показывает хороший пример закрытия асинхронного CFNetService
не испытавшая таймаут работа решения.
Перечисление a-5 , Отменяющее асинхронное CFNetService
работа решения
void MyCancelResolve(CFNetServiceRef gServiceBeingResolved) |
{ |
assert(gServiceBeingResolved != NULL); |
CFNetServiceUnscheduleFromRunLoop(gServiceBeingResolved, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); |
CFNetServiceSetClient(gServiceBeingResolved, NULL, NULL); |
CFNetServiceCancel(gServiceBeingResolved); |
CFRelease(gServiceBeingResolved); |
gServiceBeingResolved = NULL; |
return; |
} |
Для закрытия браузера, работающего в асинхронном режиме приложение не планирует браузер от всех циклов выполнения, что это может быть запланировано на и затем вызывает CFNetServiceBrowserInvalidate
. Тогда Ваши вызовы приложения CFNetServiceBrowserStopSearch
. Если браузер работает в синхронном режиме, только необходимо вызвать CFNetServiceBrowserStopSearch
. Пример этих функций может быть замечен в Перечислении a-6.
Просмотр Остановки перечисления a-6 для служб
static void MyStopBrowsingForServices(CFNetServiceBrowserRef gServiceBrowserRef) |
{ |
CFStreamError streamerror; |
assert(gServiceBrowserRef != NULL); |
CFNetServiceBrowserStopSearch(gServiceBrowserRef, &streamerror); |
CFNetServiceBrowserUnscheduleFromRunLoop(gServiceBrowserRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); |
CFNetServiceBrowserInvalidate(gServiceBrowserRef); |
CFRelease(gServiceBrowserRef); |
gServiceBrowserRef = NULL; |
return; |
} |