Обе функции возвращают количество записанных или прочитанных байтов в случае успешного выполнения, -1 в случае ошибки
Первые три аргумента,
sockfd
,
buff
и
nbytes
, идентичны первым трем аргументам
функций
read
и
write
: дескриптор, указатель на буфер, из которого производится чтение или в который происходит запись, и число байтов для чтения или записи.
Мы расскажем об аргументе
flags
в главе 14, где мы рассматриваем функции
recv
,
send
,
recvmsg
и
sendmsg
, поскольку сейчас в нашем простом примере они не нужны. Пока мы всегда будем устанавливать аргумент
flags
в нуль.
Аргумент to для функции
sendto
— это структура адреса сокета, содержащая адрес протокола (например, IP-адрес и номер порта) адресата. Размер этой структуры адреса сокета задается аргументом
addrlen
. Функция
recvform
заполняет структуру адреса сокета, на которую указывает аргумент from, записывая в нее протокольный адрес отправителя дейтаграммы. Число байтов, хранящихся в структуре адреса сокета, также возвращается вызывающему процессу в целом числе, на которое указывает аргумент
addrlen
. Обратите внимание, что последний аргумент функции
sendto
является целочисленным значением, в то время как последний аргумент функции
recvfrom
— это указатель на целое значение (аргумент типа «значение-результат»).
Последние два аргумента функции recvfrom аналогичны двум последним аргументам функции
accept
: содержимое структуры адреса сокета по завершении сообщает нам, кто отправил дейтаграмму (в случае UDP) или кто инициировал соединение (в случае TCP). Последние два аргумента функции
sendto
аналогичны двум последним аргументам функции
connect
: мы заполняем структуру адреса сокета протокольным адресом получателя дейтаграммы (в случае UDP) или адресом узла, с которым будет устанавливаться соединение (в случае TCP).
Обе функции возвращают в качестве значения функции длину данных, которые были прочитаны или записаны. При типичном использовании функции
recvfrom
с протоколом дейтаграмм возвращаемое значение — это объем пользовательских данных в полученной дейтаграмме.
Дейтаграмма может иметь нулевую длину. В случае UDP при этом возвращается дейтаграмма IP, содержащая заголовок IP (обычно 20 байт для IPv4 или 40 байт для IPv6), 8-байтовый заголовок UDP и никаких данных. Это также означает, что возвращаемое из функции
recvfrom
нулевое значение вполне приемлемо для протокола дейтаграмм: оно не является признаком того, что собеседник закрыл соединение, как это происходит при возвращении нулевого значения из функции
read
на сокете TCP. Поскольку протокол UDP не ориентирован на установление соединения, то в нем и не существует такого события, как закрытие соединения.
Если аргумент from функции
recvfrom
является пустым указателем, то соответствующий аргумент длины (
addrlen
) также должен быть пустым указателем, и это означает, что нас не интересует адрес отправителя данных.
И функция
recvfrom
, и функция
sendto
могут использоваться с TCP, хотя обычно в этом нет необходимости.
8.3. Эхо-сервер UDP: функция main
Теперь мы переделаем нашу простую
модель клиент-сервер из главы 5, используя UDP. Диаграмма вызовов функций в программах наших клиента и сервера UDP показана на рис. 8.1. На рис. 8.2 представлены используемые функции. В листинге 8.1 [1] показана функция сервера
main
.
1
Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.
Рис. 8.2. Простая модель клиент-сервер, использующая UDP