Вход/Регистрация
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
вернуться

Кёртен Роб

Шрифт:

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

Составные сообщения

До сих пор мы демонстрировали только обмен сообщениями, когда данные передаются из одного буфера в адресном пространстве клиента в другой буфер в адресном пространстве сервера (и наоборот — в случае ответа на сообщение).

При том, что данный подход вполне приемлем для большинства приложений, его применение далеко не всегда эффективно. Вспомните: наша функция write из Си-библиотеки берет переданный ей буфер и добавляет в его начало небольшой заголовок. Используя то, что мы уже изучили ранее, вы могли бы ожидать, что реализация write в Си-библиотеке может выглядеть примерно так (это не реальный код!):

ssize_t write(int fd, const void *buf, size_t nbytes) {

 char *newbuf;

 io_write_t *wptr;

 int nwritten;

 newbuf = malloc(nbytes + sizeof(io_write_t));

 // Заполнить write_header

 wptr = (io_write_t*)newbuf;

 wptr->type = _IO_WRITE;

 wptr->nbytes = nbytes;

 // Сохранить данные от клиента

 memcpy(newbuf + sizeof(io_write_t), buf, nbytes);

 // Отправить сообщение серверу

 nwritten =

MsgSend(fd, newbuf, nbytes + sizeof(io_write_t),

newbuf, sizeof(io_write_t));

 free(newbuf);

 return(nwritten);

}

Понимаете, что произошло? Несколько неприятных вещей:

• Функция write теперь должна быть способна выделить память под буфер достаточно большого размера как для данных клиента (которые могут быть довольно значительными по объему), так и для заголовка. Размер заголовка не имеет значения — в этом случае он был равен 12 байтам.

• Мы были должны скопировать данные дважды: в первый раз — при использовании функции memcpy, и затем еще раз, снова — уже при осуществлении передачи сообщения.

• Мы должны были предусмотреть указатель на тип

io_write_t
и установить его на начало буфера, вместо использования обычных механизмов доступа (впрочем, это незначительный недостаток).

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

На наше счастье, в QNX/Neutrino реализован механизм, который позволяет нам сделать именно так! Механизм этот называется IOV (i/o vector), или «вектор ввода/вывода».

Давайте для начала рассмотрим некоторую программу, а затем обсудим, что происходит с применением такого вектора.

#include <sys/neutrino.h>

ssize_t write(int fd, const void *buf, size_t nbytes) {

 io_write_t whdr;

 iov_t iov[2];

 // Установить IOV на обе части:

 SETIOV(iov + 0, &whdr, sizeof(whdr));

 SETIOV(iov + 1, buf, nbytes);

 // Заполнить io_write_t

 whdr.type = _IO_WRITE;

 whdr.nbytes = nbytes;

 // Отправить сообщение серверу

 return (MsgSendv(coid, iov, 2, iov, 1));

}

Прежде всего, обратите внимание на то, что не применяется никакой функции malloc и никакой функции memcpy. Затем обратим внимание на тип применяемого вектора IOV —

iov_t
. Это структура, которая содержит два элемента — адрес и длину. Мы определили массив из двух таких структур и назвали его iov.

Определение типа вектора

iov_t
содержится в
<sys/neutrino.h>
и выглядит так:

typedef struct iovec {

 void *iov_base;

 size_t iov_len;

} iov_t;

Мы заполняем в этой структуре пары «адрес — длина» для заголовка операции записи (первая часть) и для данных клиента (вторая часть). Существует удобная макрокоманда, SETIOV, которая выполняет за нас необходимые присвоения. Она формально определена следующим образом:

  • Читать дальше
  • 1
  • ...
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: