Используя CFNetServices

CFNetServices API в CFNetwork платформа (Базовый уровень Основы), который позволяет Вам публиковать или искать сетевые службы.

На высоком уровне, CFNetServices API обеспечивает доступ к Добрый день через три объекта:

Публикация службы Используя 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 и передача его словарь значений для публикации.

В приложении, которое должно контролировать службу, выполните следующие шаги:

  1. После того, как у Вас есть a CFNetServiceRef объект для службы Вы хотите контролировать, создать ссылку монитора (CFNetServiceMonitorRef) путем вызова CFNetServiceMonitorCreate.

  2. Запланируйте ссылку монитора на цикл выполнения с CFNetServiceMonitorScheduleWithRunLoop. (Можно получить выполненный цикл по умолчанию путем вызова CFRunLoopGetCurrent.)

  3. Запустите монитор путем вызова CFNetServiceMonitorStart, передача его ссылка монитора и функция обратного вызова для обработки получающихся данных. Обязательно проверьте возвращаемое значение, чтобы гарантировать, что монитор запустился успешно.

  4. В функции обратного вызова, самый прямой способ обработать TXT данные путем вызова CFNetServiceCreateDictionaryWithTXTData получить словарь, содержащий исходные пары ключ/значение.

Когда Вы больше не должны будете контролировать службу, вызвать CFNetServiceMonitorStop (для остановки контроля), CFNetServiceMonitorUnscheduleFromRunLoop (чтобы не запланировать Ваш монитор от его цикла выполнения), и CFNetServiceMonitorInvalidate (для уничтожения ссылки монитора).

Асинхронные и синхронные режимы

Несколько CFNetServices функции могут работать в асинхронном или синхронном режиме. Планирование a CFNetService или CFNetServiceBrowser объект на цикле выполнения заставляет службу или браузер работать в асинхронном режиме. Если a CFNetService или CFNetServiceBrowser объект не планируется на цикл выполнения, он работает в синхронном режиме. Работа в асинхронном режиме изменяет поведение своих функций.

Несмотря на то, что возможно использовать синхронные режимы этих функций, иметь в виду, что недопустимо блокировать пользовательский интерфейс или другие функции Вашей программы, в то время как Вы ожидаете синхронных функций для возврата. Поскольку сетевые операции могут занять произвольное количество времени для завершения, оно настоятельно рекомендовано это, Вы используете асинхронные режимы каждой функции.

Таблица a-1 описывает различия в поведении между синхронными и асинхронными режимами.

Табличное a-1  Поведение определенных CFNetServices функции в асинхронном и синхронном режиме

Функция

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

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

CFNetServiceRegisterWithOptions

Запускает регистрацию и возвраты. Функция обратного вызова для CFNetService вызывается для создания отчетов о любых ошибках, происходящих, в то время как работает служба. Служба доступна в сети, пока Ваше приложение не отменяет регистрацию.

Блоки до Вашего приложения отменяют службу от другого потока или пока ошибка не происходит, в которой точке возвращается функция. Если ошибка происходит, ошибка возвращается через предоставленную ошибочную структуру. Служба доступна в сети, пока Ваше приложение не отменяет регистрацию, или ошибка происходит.

CFNetServiceResolveWithTimeout

Запускает разрешение и возвраты. Функция обратного вызова для CFNetService вызывается для создания отчетов о любых ошибках, происходящих во время разрешения. Выполнения работы разрешения до указанного тайм-аута достигнуты или, если тайм-аут был указан как нуль, пока это не отменяется.

Блоки по крайней мере до одного IP-адреса найдены для службы, ошибка происходит, время, указанное, поскольку параметр тайм-аута достигнут, или Ваше приложение отменяет разрешение, в которой точке возвращается функция. Если ошибка происходит, ошибка возвращается через предоставленную ошибочную структуру. Работа разрешения продолжает работать, пока Ваше приложение не отменяет ее, или ошибка происходит.

CFNetServiceBrowserSearchForDomains

Запускает поиск и возвраты. Функция обратного вызова для CFNetServiceBrowser вызывается для каждого домена, найденного и когда любая ошибка происходит при просмотре. Просмотр продолжает работать, пока Ваше приложение не останавливает просмотр.

Блоки до ошибки происходят или Ваши вызовы приложения CFNetServiceBrowserStopSearch, в котором времени функция обратного вызова для CFNetServiceBrowser вызывается для каждого найденного домена. Любая ошибка возвращается через предоставленную ошибочную структуру. Просмотр продолжается, пока Ваше приложение не останавливает работу просмотра.

CFNetServiceBrowserSearchForServices

Запускает поиск и возвраты. Функция обратного вызова для CFNetServiceBrowser вызывается для каждого CFNetService когда любая ошибка происходит при просмотре, это найдено и. Просмотр продолжает работать, пока Ваше приложение не останавливает просмотр.

Блоки до ошибки происходят или до Ваших вызовов приложения CFNetServiceBrowserStopSearch, в котором времени функция обратного вызова для CFNetServiceBrowser вызывается для каждого CFNetService это было найдено. Любая ошибка возвращается в предоставленной ошибочной структуре. Просмотр продолжается, пока Ваше приложение не останавливает просмотр.

Закрытие служб и поисков

Для закрытия службы, работающей в асинхронном режиме приложение не планирует службу от всех циклов выполнения, на которые это может быть запланировано. Приложение тогда вызывает 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;
}