MsgReceive(), MsgReceive_r()

Ожидать сообщения или импульса

Прототип:

#include <sys/neutrino.h>
int MsgReceive( int chid,
void *msg,
int bytes,
struct _msg_info *info );
int MsgReceive_r( int chid,
void *msg,
int bytes,
struct _msg_info *info );

Аргументы:

chid
Идентификатор канала, созданного с помощью функции ChannelCreate().
msg
Указатель на буфер, в котором функция будет сохранять получаемые данные.
bytes
Размер буфера.
info
NULL или указатель на структуру struct _msg_info, в которой функция будет сохранять дополнительную информацию о сообщении.

Библиотека:

libc

Описание:

Функции MsgReceive() и MsgReceive_r() ждут поступления сообщения или импульса в канал, имеющий идентификатор chid, и сохраняют полученные данные в буфере, на который указывает msg.

Данные функции идентичны за исключением способа возврата ошибок.

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


Note: Размер буфера msg должен быть как минимум достаточным для получения импульса. В противном случае функция вернёт ошибку EFAULT.

Если сообщение уже отправлено клиентом до того, как сервер вызвал MsgReceive(), то поток-сервер не блокируется, и сообщение немедленно записывается в приёмный буфер. Если же сообщение ещё не было отправлено, то поток-сервер переходит в состояние RECEIVE-блокирован до момента поступления сообщения.

Если в канал было отправлено несколько сообщений и не было потока, их ожидающего, то сообщения будут помещены в очередь в порядке их приоритетов.


Note: Эффективный приоритет потока-сервера может изменяться при получении сообщений, наследуя приоритет потока-клиента.

Если вместо NULL задан указатель info на структуру struct _msg_info, то функция сохранит дополнительную информацию о сообщении и о потоке-клиенте, его отправившем. Эта информация может также быть получена позже с помощью функции MsgInfo().

Возвращаемое значение:

>0
Получено сообщение; возвращаемое значение является rcvid (идентификатором сообщения), оно идентифицирует поток-клиент и его локальный идентификатор соединения. Идентификатор rcvid может использоваться при вызове других функций Msg*() для взаимодействия с потоком-клиентом и для отправки ему ответа. Вызов функции MsgReceive() меняет состояние потока-клиента на REPLY-блокирован. При вызове потоком-сервером MsgReply*() для ответа на полученное сообщение поток-клиент будет переведен в состояние READY.
0
Получен импульс; буфер msg содержит структуру-импульс, имеющую тип _pulse. При получении импульса используемое им адресное пространство ядра немедленно освобождается. Структура struct _msg_info не обновляется.


Note: На импульс нельзя ответить.

Состояния блокировки:

STATE_RECEIVE
Ожидание сообщений

Сетевые взаимодействия

При передаче сообщений по сети сервер получает их от своего локального менеджера lsm-qnet.so. При этом rcvid, возвращаемый MsgReceive(), будет выполнять роль своего рода "куки".

Обмен данными между модулями lsm-qnet.so осуществляется фрагментами, размер которых составляет 18 КБ. В результате, если, например, клиент отправляет 1 МБ данных, и сервер также выделяет для получения сообщения 1 МБ, то после передачи первого фрагмента размером 18 КБ произойдёт разблокирование сервера. То есть реально на момент разблокировки будет передан только один фрагмент. При этом клиент останется заблокированным для того, чтобы сервер мог вычитать всё сообщение. Таким образом, на стороне сервера необходимо организовать получение всего сообщения. Для решения этой задачи сервер может выяснять количество переданных данных и размер буфера клиента с помощью последнего параметра функции MsgReceive() или с помощью функции MsgInfo(), точнее с помощью структуры struct _msg_info.

Следующий код демонстрирует способ решения задачи обмена сообщениями с учетом особенностей сетевой передачи данных. Обратите внимание, что библиотека менеджеров ресурсов делает это автоматически:

chid = ChannelCreate( _NTO_CHF_SENDER_LEN );
...
rcvid = MsgReceive( chid, msg, nbytes, &info );
/*
* Выполнение сетевой транзакции, не всё сообщение
* было отправлено, поэтому получаем остаток...
*/
if ( rcvid > 0 && info.srcmsglen > info.msglen && info.msglen < nbytes )
{
int n;
if ( (n = MsgRead_r( rcvid, (char *)msg + info.msglen,
nbytes - info.msglen, info.msglen )) < 0 )
{
MsgError( rcvid, -n );
continue;
}
info.msglen += n;
}

Возвращаемое значение:

В случае успешного выполнения обе функции возвращают положительное значение, если получено сообщение, или 0, осли получен импульс. При возникновении ошибки:

MsgReceive()
возвращает -1 и устанавливает значение errno.
MsgReceive_r()
возвращает отрицательное значение, указанное ниже в секции "Коды ошибок". Функция не устанавливает errno.

Коды ошибок:

EFAULT
Ошибка при попытке доступа к предоставленным буферам.
EINTR
Функция была прервана сигналом.
ESRCH
Отсутствует канал с идентификатором chid.
ETIMEDOUT
Функция прервана по тайм-ауту ядра. См. TimerTimeout().

Классификация:

ЗОСРВ «Нейтрино»

Точка остановки потока
Нет
Обработчик прерываний
Нет
Обработчик сигналов
Да
В потоке
Да

Предостережения:

Максимальный размер сообщения ограничен размером пользовательского виртуального адресного пространства и зависит от процессорной архитектуры.

Тематические ссылки:

ChannelCreate(), struct _msg_info, MsgInfo(), MsgRead(), MsgReadv(), MsgReceivePulse(), MsgReceivePulsev(), MsgReceivev(), MsgReply(), MsgReplyv(), MsgSend(), MsgWrite(), MsgWritev(), _pulse, TimerTimeout()




Предыдущий раздел: Описание API системной библиотеки