Функция sendto (winsock.h)
Функция sendto отправляет данные в определенное место назначения.
Синтаксис
int sendto(
[in] SOCKET s,
[in] const char *buf,
[in] int len,
[in] int flags,
[in] const sockaddr *to,
[in] int tolen
);
Параметры
[in] s
Дескриптор, определяющий сокет (возможно, подключенный).
[in] buf
Указатель на буфер, содержащий передаваемые данные.
[in] len
Длина (в байтах) данных, на которые указывает параметр buf .
[in] flags
Набор флагов, указывающих способ вызова.
[in] to
Необязательный указатель на структуру sockaddr , содержащую адрес целевого сокета.
[in] tolen
Размер (в байтах) адреса, на который указывает параметр to .
Возвращаемое значение
Если ошибка не возникает, функция sendto возвращает общее количество отправленных байтов, которое может быть меньше числа, указанного в len. В противном случае возвращается значение SOCKET_ERROR, а определенный код ошибки можно получить, вызвав WSAGetLastError.
Код ошибки | Значение |
---|---|
Перед использованием этой функции должен произойти успешный вызов WSAStartup . | |
Произошел сбой сетевой подсистемы. | |
Запрошенный адрес является широковещательным, но соответствующий флаг не установлен. Вызовите метод setsockopt с параметром SO_BROADCAST, чтобы разрешить использование широковещательного адреса. | |
Был указан неизвестный флаг или MSG_OOB для сокета с включенным SO_OOBINLINE. | |
Блокирующий вызов Windows Sockets 1.1 был отменен через WSACancelBlockingCall. | |
Выполняется блокирующий вызов Windows Sockets 1.1 или поставщик услуг по-прежнему обрабатывает функцию обратного вызова. | |
Параметры buf или to не являются частью адресного пространства пользователя или параметр tolen слишком мал. | |
Подключение было разорвано из-за действия поддержания активности, обнаруживающего сбой во время выполнения операции. | |
Нет свободного места в буфере. | |
Сокет не подключен (только сокеты, ориентированные на подключение). | |
Дескриптор не является сокетом. | |
MSG_OOB указано, но сокет не является потоковым, например тип SOCK_STREAM, данные OOB не поддерживаются в домене связи, связанном с этим сокетом, или сокет является однонаправленным и поддерживает только операции получения. | |
Сокет был выключен; невозможно отправить в сокет после вызова завершения работыс параметром SD_SEND или SD_BOTH. | |
Сокет помечается как неблокировочный, и запрошенная операция будет блокироваться. | |
Сокет ориентирован на сообщения, и сообщение больше максимального значения, поддерживаемого базовым транспортом. | |
В настоящее время с этого узла не удается связаться с удаленным узлом. | |
Виртуальное подключение разорвано из-за тайм-аута или иного сбоя. Приложение должно закрыть сокет, поскольку он больше не может использоваться. | |
Виртуальное подключение было сброшено удаленной стороной путем прерывания. Для сокетов UDP удаленный узел не смог доставить ранее отправленную датаграмму UDP и ответил пакетом ICMP "Порт недоступен". Приложение должно закрыть сокет, поскольку он больше не может использоваться. | |
Удаленный адрес не является допустимым адресом, например ADDR_ANY. | |
Адреса из заданного семейства адресов не могут использоваться с этим сокетом. | |
Требуется адрес назначения. | |
В настоящее время сеть недоступна с этого узла. | |
Сделана попытка выполнить операцию на сокете для недоступного хоста. | |
Подключение было прервано из-за сбоя сети или из-за того, что система на другом конце не работает без предварительного уведомления. |
Комментарии
Функция sendto используется для записи исходящих данных в сокет. Для сокетов, ориентированных на сообщения, необходимо соблюдать осторожность, чтобы не превышать максимальный размер пакета базовых подсетей, который можно получить с помощью команды getsockopt для получения значения параметра сокета SO_MAX_MSG_SIZE. Если данные слишком длинны для атомарной передачи через базовый протокол, возвращается ошибка WSAEMSGSIZE и данные не передаются.
Параметр to может быть любым допустимым адресом в семействе адресов сокета, включая широковещательный или любой адрес многоадресной рассылки. Для отправки на широковещательный адрес приложение должно использовать setsockopt с включенным SO_BROADCAST. В противном случае sendto завершится ошибкой с кодом WSAEACCES. Для TCP/IP приложение может отправлять сообщения на любой адрес многоадресной рассылки (не становясь участником группы).
Если сокет не подключен,
Функцию getockname можно использовать для определения номера локального порта, связанного с сокетом, но возвращаемый IP-адрес устанавливается в качестве подстановочного адреса для заданного протокола (например, INADDR_ANY или "0.0.0.0" для IPv4 и IN6ADDR_ANY_INIT или "::" для IPv6).
Успешное завершение отправки не означает, что данные были успешно доставлены.
Функция sendto обычно используется в сокете без подключения для отправки датаграммы в конкретный одноранговый сокет, определенный параметром to . Даже если сокет без подключения был ранее подключен к определенному адресу, параметр to переопределяет адрес назначения только для этой датаграммы. В сокете, ориентированном на подключение, параметры to и tolen игнорируются, что делает sendto эквивалентным отправке.
Пример кода
В следующем примере показано использование функции sendto .#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
int main()
{
int iResult;
WSADATA wsaData;
SOCKET SendSocket = INVALID_SOCKET;
sockaddr_in RecvAddr;
unsigned short Port = 27015;
char SendBuf[1024];
int BufLen = 1024;
//----------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup failed with error: %d\n", iResult);
return 1;
}
//---------------------------------------------
// Create a socket for sending data
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (SendSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//---------------------------------------------
// Set up the RecvAddr structure with the IP address of
// the receiver (in this example case "192.168.1.1")
// and the specified port number.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = inet_addr("192.168.1.1");
//---------------------------------------------
// Send a datagram to the receiver
wprintf(L"Sending a datagram to the receiver...\n");
iResult = sendto(SendSocket,
SendBuf, BufLen, 0, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
if (iResult == SOCKET_ERROR) {
wprintf(L"sendto failed with error: %d\n", WSAGetLastError());
closesocket(SendSocket);
WSACleanup();
return 1;
}
//---------------------------------------------
// When the application is finished sending, close the socket.
wprintf(L"Finished sending. Closing socket.\n");
iResult = closesocket(SendSocket);
if (iResult == SOCKET_ERROR) {
wprintf(L"closesocket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
//---------------------------------------------
// Clean up and quit.
wprintf(L"Exiting.\n");
WSACleanup();
return 0;
}
Для сокетов, использующих IP-адрес (версия 4)
Для отправки широковещательной рассылки (только на SOCK_DGRAM) можно создать адрес, на который указывает параметр to , содержащий специальный IPv4-адрес INADDR_BROADCAST (определенный в Winsock2.h) вместе с предполагаемым номером порта. Если адрес, на который указывает параметр to , содержит адрес INADDR_BROADCAST и предполагаемый порт, трансляция будет отправляться на этот порт по всем интерфейсам.Если широковещательная рассылка должна быть отправлена только через определенный интерфейс, то адрес, на который указывает параметр to , должен содержать адрес широковещательной подсети для интерфейса и предполагаемый порт. Например, сетевой адрес IPv4 192.168.1.0 с маской подсети 255.255.255.0 будет использовать широковещательный адрес подсети 192.168.1.255.
Как правило, не рекомендуется, чтобы широковещательная датаграмма превышала размер, при котором может произойти фрагментация, что означает, что часть данных датаграммы (за исключением заголовков) не должна превышать 512 байт.
Если в транспортной системе нет буферного пространства для хранения передаваемых данных, sendto будет блокироваться, если сокет не был помещен в неблокировочный режим. При неблокировке потоковых сокетов число записанных байтов может составлять от 1 до требуемой длины в зависимости от доступности буфера в клиентской и серверной системах. Функция select, WSAAsyncSelect или WSAEventSelect может использоваться для определения возможности отправки дополнительных данных.
Вызов sendto с len 0 является допустимым и возвращает ноль в качестве допустимого значения. Для сокетов, ориентированных на сообщения, отправляется транспортная датаграмма нулевой длины.
Параметр flags можно использовать для влияния на поведение вызова функции за пределами параметров, указанных для связанного сокета. Семантика этой функции определяется параметрами сокета и параметром flags . Последний создается с помощью побитового оператора OR с любым из следующих значений.
Значение | Значение |
---|---|
MSG_DONTROUTE | Указывает, что данные не должны подвергаться маршрутизации. Поставщик службы Сокетов Windows может игнорировать этот флаг. |
MSG_OOB | Отправляет данные OOB (только сокет в стиле потока, например SOCK_STREAM). |
Windows Phone 8. Эта функция поддерживается для приложений Магазина Windows Phone Windows Phone 8 и более поздних версий.
Windows 8.1 и Windows Server 2012 R2: эта функция поддерживается для приложений Магазина Windows на Windows 8.1, Windows Server 2012 R2 и более поздних версий.
Требования
Минимальная версия клиента | Windows 8.1, Windows Vista [классические приложения | Приложения UWP] |
Минимальная версия сервера | Windows Server 2003 [классические приложения | Приложения UWP] |
Целевая платформа | Windows |
Header | winsock.h (включая Winsock2.h) |
Библиотека | Ws2_32.lib |
DLL | Ws2_32.dll |