Означает ли это, что вызов send () всегда будет возвращаться немедленно, если в буфере отправки ядра есть место?
Да.Пока сразу означает, что после того, как вы предоставили память, она была скопирована в буфер ядра.Который, в некоторых крайних случаях, не может быть настолько немедленным.Например, если указатель, который вы передаете, вызывает сбой страницы, который должен извлечь буфер из файла с отображенной памятью или из файла подкачки, это добавило бы значительную задержку к возвращаемому вызову.
поведение и производительность вызова send () идентичны для TCP и UDP?Если нет, то почему?
Не совсем.Возможные различия в производительности зависят от реализации ОС стека TCP / IP.Теоретически сокет UDP может быть немного дешевле, так как ОС должна делать с ним меньше вещей.
РЕДАКТИРОВАТЬ: С другой стороны, поскольку вы можете отправлять гораздо больше данных за системный вызовс TCP, как правило, стоимость за байт может быть намного ниже с TCP.Это может быть смягчено с помощью sendmmsg () в последних ядрах Linux.
Что касается поведения, оно почти идентично.
Для блокирования сокетов будут блокироваться как TCP, так и UDP.пока не будет места в буфере ядра.Различие, однако, состоит в том, что сокет UDP будет ожидать, пока весь ваш буфер может быть сохранен в буфере ядра, тогда как сокет TCP может решить скопировать только один байт в буфер ядра (хотя обычно это более одного байта).
Если вы попытаетесь отправить пакеты, размер которых превышает 64 КБ, сокет UDP, скорее всего, будет постоянно терпеть неудачу с EMSGSIZE .Это связано с тем, что UDP, являющийся сокетом дейтаграммы , гарантирует отправку всего буфера в виде одного IP-пакета (или последовательности фрагментов IP-пакетов) или не отправляет его вообще.
Non blockingсокеты ведут себя идентично версиям блокировки, за исключением того, что вместо блокировки (если в буфере ядра недостаточно места) вызовы завершаются с EAGAIN (или EWOULDBLOCK ).Когда это происходит, пришло время поместить сокет обратно в epoll / kqueue / select (или что вы используете), чтобы дождаться, когда он снова станет доступным для записи.
Как обычно при работе с POSIX, имейте в видучто ваш вызов может завершиться ошибкой с EINTR (если вызов был прерван сигналом).В этом случае вы, скорее всего, захотите снова позвонить send()
.