Как sendmsg работает?
Как известно sendmsg это заявление:
int sendmsg(int s, const struct msghdr *msg, int flags);
и непосредственно передаваемых параметров структура имеет такой вид:
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 ответов
manpage говорит о сообщении (единственное число) и нескольких элементах (множественное число):
на
send()
иsendto()
сообщение находится вbuf
и имеет длинуlen
. Дляsendmsg()
, на сообщение указывают элементы массивmsg.msg_iov
. Thesendmsg()
call также позволяет отправлять вспомогательные данные (также известные как контрольная информация).
для сокета потока это не имело бы значения в любом случае. Любые данные, которые вы отправляете, просто заканчиваются как один длинный поток данных на другой стороне.
для сокетов дейтаграмм или сообщений я понимаю, почему было бы полезно немного больше ясности. Но, похоже, вы отправляете только одну дейтаграмму или сообщение с одним sndmsg
вызов; не один на буферный элемент.
я на самом деле пошел копаться в исходном коде Linux из любопытства и получить лучшее представление об этом ответе. Похоже на send
и sendto
это просто обертки для sendmsg
в Linux, которые строят struct msghdr
для тебя. И на самом деле, UDP sendmsg
реализация освобождает место для один заголовок UDP на sendmsg
звонок.
если производительность-это то, о чем вы беспокоитесь, не похоже, что вы выиграете от sendmsg
если вы проходите только один iovec
. Если вы объединяете буферы в пользовательском пространстве, это может потенциально выиграть вас.
это немного похоже на writev
, с дополнительным преимуществом, что вы можете указать адрес назначения для использования с connectionless гнездами как UDP. Вы также можете добавить дополнительные данные, если вы в такого рода вещи. (Обычно используется для отправки дескрипторов файлов через доменные сокеты UNIX.)
Это зависит от вашего стека TCP/IP. Встроенный протокол TCP/IP стеков потенциально может отправить различные iovecs к адаптеру. Но на обычных стеках TCP/IP уже должна быть копия из памяти userspace в память kernelspace, поэтому там нет усиления, и iovecs концептуально копируются в один большой кусок памяти (это могут быть отдельные страницы памяти, если драйвер поддерживает scather/gather I/O, но важная часть здесь заключается в том, что границы iovec не получают сохранилось).
согласно http://opengroup.org/onlinepubs/007908799/xns/sendmsg.html ...
данные из каждой области хранения указанные msg_iov отправляется в свою очередь.
моя интерпретация такова sendmsg()
не будет объединять данные сообщения, хранящиеся в iovec; каждый будет отправлен как отдельное сообщение.
[редактировать: моя интерпретация не была правильной; см. другие ответы для лучшего объяснение.]