Функция reсvfrom
recvfrom
дейтаграммы во входном буфере сокета отсутствуют, функция будет ждать, пока они там появятся, и до этого момента не вернет управление вызвавшей её программе. Если в буфере находится несколько дейтаграмм, то они читаются в порядке очередности поступления в буфер. Напомним, что дейтаграммы могут поступать в буфер не в том порядке, в котором они были отправлены. Кроме того, в очень редких случаях буфер может содержать несколько копий одной дейтаграммы, каждую из которых нужно извлекать отдельно.Значение, возвращаемое функцией recvfrom
sendto
нужно задать параметр len
равным нулю). Если обнаружена какая-то ошибка, возвращается значение SOCKET_ERROR
.Если размер буфера, определяемого параметром Buf
recvfrom
завершается с ошибкой (WSAGetLastError
при этом вернет ошибку WSAEMSGSSIZE
). Оставшаяся часть дейтаграммы при этом безвозвратно теряется, при следующем вызове recvfrom
будет прочитана следующая дейтаграмма. Этой проблемы легко избежать, т.к. длина дейтаграммы в UDP не может превышать 65 507 байтов. Достаточно подготовить буфер соответствующей длины, и и в него гарантированно поместится любая дейтаграмма.Другой способ избежать подобной проблемы — использовать флаг MSG_PEEK
recvfrom
, равно длине дейтаграммы. При этом в буфер, заданный параметром Buf
, копируется та часть дейтаграммы, которая в нем помещается. Программа может действовать следующим образом: вызвать recvfrom
с флагом MSG_PEEK
, выделить память, требуемую для хранения дейтаграммы, вызвать recvfrom
без флага MSG_PEEK
, чтобы прочитать дейтаграмму целиком и удалить ее из входного буфера сокета. Этот метод сложнее, а 65 507 байтов — не очень большая по нынешним меркам память, поэтому легче все-таки заранее приготовить буфер фиксированной длины. Функция recvfrom
непригодна для тех сокетов, которые еще не привязаны к адресу, поэтому перед вызовом этой функции должна быть вызвана либо функция bind
, либо функция, которая осуществляет неявную привязку сокета к адресу (например, sendto
).Протокол UDP не поддерживает соединения в том смысле, в котором их поддерживает TCP, но библиотека сокетов позволяет частично имитировать такие соединения, Для этого служит функция connect
function connect(s: TSocket; var name: TSockAddr; namelen: Integer): Integer;
Параметр s
addr
функции sendto
. Параметр namelen
содержит длину структуры, описывающей адрес, и должен быть равен SizeOf(TSockAddr)
. Функция возвращает ноль при успешном завершении и SOCKET_ERROR
— в случае ошибки. Вызов функции connect
в случае UDP устанавливает фильтр для входящих дейтаграмм. Дейтаграммы, адрес отправителя которых не совпадает с адресом, заданным в функции connect
, игнорируются: новые дейтаграммы не помещаются во входной буфер сокета, а те, которые находились там на момент вызова connect
, удаляются из него. Функция connect
не проверяет, существует ли адрес, с которым сокет "соединяется", и может успешно завершиться, даже если узла с таким IP-адресом нет.Программа может вызывать connect неограниченное число раз с разными адресами. Если параметр name задает IP-адрес INADDR_ANY
connect
. Для сокетов, не привязанных к адресу, connect
неявно вызывает bind
.После вызова connect
send
со следующим прототипом:function send(s: TSocket; var Buf; len, flags: Integer): Integer;
От функции sendto
addrto
и tolen
. При использовании send
дейтаграмма отправляется по адресу, заданному при вызове connect
. В остальном эти функции ведут себя одинаково, функция sendto
при работе с "соединенным" сокетом ведет себя так же, как с несоединенным, т.е. отправляет дейтаграмму по адресу, определяемому параметром addrlen
, а не по адресу, заданному при вызове connect
.