Как работает sendmsg? - PullRequest
       4

Как работает sendmsg?

12 голосов
/ 23 ноября 2010

Как вы знаете, sendmsg имеет эту декларацию:

int sendmsg(int s, const struct msghdr *msg, int flags);

Структура

и msghdr имеет следующий вид:

struct msghdr {
    void         * msg_name;     /* optional address */
    socklen_t    msg_namelen;    /* size of address */
    struct iovec * msg_iov;      /* scatter/gather array */
    size_t       msg_iovlen;     /* # elements in msg_iov */
    void         * msg_control;  /* ancillary data, see below */
    socklen_t    msg_controllen; /* ancillary data buffer len */
    int          msg_flags;      /* flags on received message */
};

Как видите, msghdr имеет массив буферов iovec и количество буферов msg_iovlen. Что мне интересно, так это то, как sendmsg отправляет эти буферы. Объединяет ли он все буферы и отправляет или отправляет цикл for?

Ответы [ 3 ]

25 голосов
/ 23 ноября 2010

На странице руководства говорится о сообщении (единственном числе) и нескольких элементах (множественном числе):

Для send() и sendto() сообщение находится в buf и имеет длину len.Для sendmsg() на сообщение указывают элементы массива msg.msg_iov.Вызов sendmsg() также позволяет отправлять вспомогательные данные (также известные как управляющая информация).

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

Для дейтаграмм или сокетов сообщений я понимаю, почему немного большей ясности было бы полезно.Но похоже, что вы отправляете только одну дейтаграмму или сообщение с помощью одного sndmsg вызова;не один на элемент буфера.

Я на самом деле копался в исходном коде Linux из любопытства, чтобы лучше понять этот ответ.Похоже, send и sendto - это просто оболочки для sendmsg в Linux, которые создают для вас struct msghdr.И на самом деле, реализация UDP sendmsg освобождает место для одного заголовка UDP на sendmsg вызов.

Если вы беспокоитесь о производительности, она не выглядитВы получите sendmsg, если сдадите только один iovec.Однако, если вы объединяете буферы в пользовательском пространстве, это потенциально может вас выиграть.

Это немного похоже на writev, но с дополнительным преимуществом вы можете указать адрес назначения для использования с без установления соединения.сокеты типа UDP.Вы также можете добавить вспомогательные данные, если вам нравятся подобные вещи.(Обычно используется для отправки файловых дескрипторов через доменные сокеты UNIX.)

1 голос
/ 23 ноября 2010

Это зависит от вашего стека TCP / IP. Встроенные стеки TCP / IP потенциально могут отправлять различные iovecs непосредственно на NIC. Но в обычных стеках TCP / IP уже должна быть копия из памяти пользовательского пространства в память пространства ядра, поэтому здесь нет никакого усиления, и iovecs концептуально копируется в один большой кусок памяти (это могут быть отдельные страницы памяти, если Драйвер поддерживает ввод / вывод scather / collect, но важной частью здесь является то, что границы iovec не сохраняются ).

1 голос
/ 23 ноября 2010

Согласно http://opengroup.org/onlinepubs/007908799/xns/sendmsg.html ...

Данные из каждой области хранения, обозначенные msg_iov, отправляются по очереди.

Myинтерпретация заключается в том, что sendmsg() не будет объединять данные сообщений, хранящиеся в iovec;каждое из них будет отправлено в виде отдельного сообщения.

[ Редактировать : Моя интерпретация неверна;см. другие ответы для лучшего объяснения.]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...