Дарвинские понятия уведомления
В этой главе описываются, как отправить и получить Дарвинские уведомления. Дарвинская система уведомления является относительно прямой для разработчиков, знакомых с программированием в других UNIX/операционных системах Linux. Это набрасывается на обычно используемые системы, такие как дескрипторы файлов и сигналы обеспечить поставку сообщений к клиентскому процессу.
Дарвинские уведомления поддерживаются notifyd(8)
демон, процесс, прислушивающийся к входящим уведомлениям и повторно поставляющий те уведомления заинтересованным процессам во множестве путей.
Включая соответствующие заголовки
При записи инструмента, использующего Дарвинские уведомления, обычно используются следующие заголовки:
#include <unistd.h> // good idea in general |
#include <stdlib.h> // good idea in general |
#include <strings.h> // for bcopy, used by FD_COPY macro |
// (file descriptor delivery) |
#include <sys/select.h> // for select (file descriptors delivery) |
#include <stdio.h> // for read (file descriptor delivery) |
#include <signal.h> // for signal names (signal delivery) |
#include <mach/message.h> // For mach message functions and types |
// (mach message delivery) |
#include <notify.h> // for all notifications |
Отправка уведомлений
Отправка Дарвинского уведомления очень проста. Просто вызовите функцию notify_post
. Функция берет отдельный аргумент, содержащий имя уведомления. (См., Как нужно Назвать Уведомления? для получения информации об именовании уведомления.)
Например, если Вы интегрируете уведомления в веб-сервер Apache и хотите уведомить его, что его конфигурационный файл изменился, Вы могли бы отправить уведомление с вызовом как следующее:
if (notify_post("org.apache.httpd.configFileChanged")) { |
printf("Notification failed.\n"); exit(-1); |
} |
Функция notify_post
возвраты обнуляют на успехе или коде ошибки при отказе. Возможные коды ошибки описаны в Кодах состояния в Дарвинском Уведомлении Ссылка API.
Получение уведомлений
Дарвинские уведомления обеспечивают пять механизмов для получения уведомлений: Базовая Основа, дескрипторы файлов, сигналы, сообщения Маха и ручной опрос. В этом разделе описываются эти механизмы поставки и объясняет, когда необходимо выбрать каждого.
Когда добавление уведомления поддерживает к существующим приложениям, необходимо выбрать, какой бы ни механизм является самым простым интегрировать в приложение или инструмент. Если Ваше приложение уже использует сигнальную обработку, необходимо использовать сигналы. Если Ваше приложение уже использует сокеты или дескрипторы файлов, необходимо использовать дескрипторы файлов. И т.д.
Если Вы пишете новое приложение с нуля, Базовые уведомления Основы рекомендуются, если Ваше приложение основывается на Базовой Основе. Для неосновных приложений Основы дескрипторы файлов являются предпочтительным транспортом уведомления, потому что они более устойчивы против потери сообщений, чем сигналы и проще использовать, чем сообщения Маха. Снова, необходимо выбрать механизм, наиболее близко соответствующий архитектуре инструмента, который Вы пишете.
Как правило необходимо избегать использования интерфейса опроса (описанный в Получении Уведомлений Вручную). Необходимо использовать опрос, только если необходимо нечасто проверять на изменение состояния.
Получение уведомлений Используя базовую основу
Для регистрации для Дарвинских уведомлений с помощью Базовой Основы сначала создайте центр уведомления путем вызова CFNotificationCenterGetDarwinNotifyCenter
. Это создает объект, взаимодействующий с демоном уведомления от Вашего имени.
Затем, вызовите CFNotificationCenterAddObserver
. Эта функция дает центру уведомления команду регистрироваться для уведомлений в демоне уведомления.
Следующий отрывок показывает, как зарегистрироваться для уведомления, описанного в Передающих Уведомлениях:
/* This function is called when a notification is received. */ |
void MyNotificationCenterCallBack(CFNotificationCenterRef center, |
void *observer, |
CFStringRef name, |
const void *object, |
CFDictionaryRef userInfo) |
{ |
printf("Notification center handler called\n"); |
} |
... |
/* Create a notification center */ |
CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter(); |
/* Tell notifyd to alert us when this notification |
is received. */ |
if (center) { |
CFNotificationCenterAddObserver(center, |
NULL, |
MyNotificationCenterCallBack, |
CFSTR("org.apache.httpd.configFileChanged"), |
NULL, |
CFNotificationSuspensionBehaviorDeliverImmediately); |
... |
} |
Получение уведомлений Используя дескрипторы файлов
Получение уведомлений с дескрипторами файлов является относительно прямым. Во-первых, необходимо вызвать notify_register_file_descriptor
зарегистрироваться для уведомлений. Например, следующий отрывок показывает, как зарегистрироваться для уведомления, отправленного в Передающих Уведомлениях:
int fd; /* file descriptor---one per process if |
NOTIFY_REUSE is set, else one per name */ |
int notification_token; /* notification token---one per name */ |
... |
if (notify_register_file_descriptor("org.apache.httpd.configFileChanged", |
&fd, |
0, |
¬ification_token)) { |
/* Something went wrong. Bail. */ |
printf("Registration failed.\n"); exit(-1); |
} |
Функция notify_register_file_descriptor
возвраты обнуляют на успехе или коде ошибки при отказе. Возможные коды ошибки описаны в Кодах состояния в Дарвинском Уведомлении Ссылка API.
После регистрации для уведомления Вы начнете получать данные через возвращенный дескриптор файла. Можно обнаружить поступление нового использования данных select(2)
или poll(2)
, как показано в следующем отрывке:
fd_set receive_descriptors, receive_descriptors_copy; |
FD_SET(fd, /* from call to notify_register_file_descriptor */ |
&receive_descriptors); |
FD_COPY(&receive_descriptors, &receive_descriptors_copy); |
while (select(fd + 1, &receive_descriptors_copy, |
NULL, NULL, NULL) >= 0) { |
/* Data was received. */ |
if (FD_ISSET(fd, &receive_descriptors_copy)) { |
/* Data was received on the right descriptor. |
Do something. */ |
int token; |
/*! Read four bytes from the file descriptor. */ |
if (read(fd, &token, sizeof(token)) != sizeof(token)) { |
/* An error occurred. Panic. */ |
printf("Read error on descriptor. Exiting.\n"); |
exit(-1); |
} |
/* At this point, the value in token should match one of the |
registration tokens returned through the fourth parameter |
of a previous call to notify_register_file_descriptor. */ |
} |
FD_COPY(&receive_descriptors, &receive_descriptors_copy); |
} |
Для получения дополнительной информации о select
системный вызов, см. страницу руководства для select(2)
.
Получение уведомлений Используя сигналы
Для получения сигнала, когда новое уведомление будет отправлено вызовите функцию notify_register_signal
. Эта функция говорит демону уведомления отправлять сигнал в Ваш процесс каждый раз, когда это добавляет новые сообщения.
Следующий отрывок показывает, как зарегистрироваться для уведомления, описанного в Передающих Уведомлениях:
int notification_token; |
... |
/* Set up a signal handler for SIGHUP */ |
signal(SIGHUP, &my_sighup_handler); |
/* Tell notifyd to send SIGHUP when this notification |
is received. */ |
if (notify_register_signal( |
"org.apache.httpd.configFileChanged", SIGHUP, |
¬ification_token)) { |
printf("Registration failed.\n"); exit(-1); |
} |
Функция notify_register_signal
возвраты обнуляют на успехе или коде ошибки при отказе. Возможные коды ошибки описаны в Кодах состояния в Дарвинском Уведомлении Ссылка API.
Значение notification_token
установлен в целочисленное значение, определенное для имени для этого уведомления. Именно Ваша ответственность отслеживать эти символические стоимости уведомления так, чтобы можно было узнать уведомление, была отправлена (если Вы не регистрируетесь только для единственного уведомления и не заботитесь о ложных положительных сторонах, вызванных сигналами, не сгенерированными notifyd
).
После регистрации для получения сигналов, необходимо тогда вызвать notify_check
определить, который (если таковые имеются) уведомление инициировало сигнал, как показано в следующем отрывке:
int was_posted; |
if (notify_check(notification_token, &was_posted)) { |
printf("Call to notify_check failed.\n"); exit(-1); |
} |
if (was_posted) { |
/* The notification org.apache.httpd.configFileChanged |
was posted. */ |
} |
Функция notify_check
возвраты обнуляют на успехе или коде ошибки при отказе. Возможные коды ошибки описаны в Кодах состояния в Дарвинском Уведомлении Ссылка API. Функция возвращает значение через второй параметр, чтобы указать, было ли уведомление отправлено с прошлого раза Вы вызвали notify_check
.
Получение уведомлений Используя сообщения Маха
Если Ваш инструмент или приложение используют сообщения Маха для коммуникации, можно счесть удобным использовать сообщения Маха для получения уведомления. Коммуникация на основе Маха, обменивающегося сообщениями, не рекомендуется для использования в новых проектах, потому что относительно просто повредить память Вашего приложения, если используется неправильно.
Можно зарегистрировать для Маха основанное на сообщении уведомление на порту Маха путем вызова notify_register_mach_port
, как показано в отрывке ниже:
mach_port_name_t port; /* mach port---one per process if |
NOTIFY_REUSE is set, else one per name */ |
int notification_token; /* notification token---one per name */ |
/* Allocate a mach port. If you already have receive rights on a |
port and would prefer to use that, you can do so, of course. */ |
if (mach_port_allocate (mach_task_self(), |
MACH_PORT_RIGHT_RECEIVE, &port) != KERN_SUCCESS) { |
printf("Could not allocate mach port.\n"); exit(-1); |
} |
if (notify_register_mach_port("org.apache.httpd.configFileChanged", |
&port, |
NOTIFY_REUSE, |
¬ification_token)) { |
/* Something went wrong. Bail. */ |
printf("Registration failed.\n"); exit(-1); |
} |
Функция notify_register_mach_port
возвраты обнуляют на успехе или коде ошибки при отказе. Возможные коды ошибки описаны в Кодах состояния в Дарвинском Уведомлении Ссылка API.
При желании можно позволить Маху выделить порт для Вас путем пропуска вызова к mach_port_allocate
и передача в 0
вместо NOTIFY_REUSE
.
После регистрации для уведомления можно получить сообщения на порту с mach_msg_overwrite
вызовите, как показано в следующем отрывке:
struct { |
mach_msg_header_t hdr; |
int token; |
} mydatastructure; |
while (1) { |
mach_msg_overwrite(NULL, MACH_RCV_MSG, |
0, sizeof(mydatastructure), port, MACH_MSG_TIMEOUT_NONE, |
MACH_PORT_NULL, (mach_msg_header_t *)&mydatastructure, |
sizeof(mydatastructure.token)); |
printf("Data received : %d (compare to %d).\n", mydatastructure.token, notification_token); |
} |
Получение уведомлений вручную
Несмотря на то, что это не распространено для этого, что можно иногда считать полезным опросить для наблюдения (на случайной основе), произошло ли определенное уведомление. Чтобы сделать это, необходимо запросить маркер, соответствующий имени уведомления путем вызова notify_register_check
, как показано в следующем отрывке:
if (notify_register_check( |
"org.apache.httpd.configFileChanged", ¬ification_token)) { |
printf("Registration failed.\n"); exit(-1); |
} |
Можно тогда проверить на использование уведомлений notify_check
(когда Вы были бы для сигнальной поставки), как показано в следующем отрывке:
int was_posted; |
while (1) { |
sleep(1); |
if (notify_check(notification_token, &was_posted)) { |
printf("Call to notify_check failed.\n"); exit(-1); |
} |
if (was_posted) { |
/* The notification org.apache.httpd.configFileChanged |
was posted. */ |
printf("Notification %d was posted.\n", notification_token); |
} |
} |
Функция notify_check
возвраты обнуляют на успехе или коде ошибки при отказе. Возможные коды ошибки описаны в Кодах состояния в Дарвинском Уведомлении Ссылка API. Функция возвращает значение через второй параметр, чтобы указать, было ли уведомление отправлено с прошлого раза Вы вызвали notify_check
.