Функция WSASendTo (winsock2.h)
Функция WSASendTo отправляет данные в определенное место назначения с помощью перекрывающихся операций ввода-вывода, если это применимо.
Синтаксис
int WSAAPI WSASendTo(
[in] SOCKET s,
[in] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesSent,
[in] DWORD dwFlags,
[in] const sockaddr *lpTo,
[in] int iTolen,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Параметры
[in] s
Дескриптор, определяющий сокет (возможно, подключенный).
[in] lpBuffers
Указатель на массив структур WSABUF . Каждая структура WSABUF содержит указатель на буфер и длину буфера в байтах. Для приложения Winsock после вызова функции WSASendTo система владеет этими буферами, и приложение может не получить к ним доступ. Этот массив должен оставаться действительным в течение операции отправки.
[in] dwBufferCount
Количество структур WSABUF в массиве lpBuffers .
[out] lpNumberOfBytesSent
Указатель на количество байтов, отправленных этим вызовом, если операция ввода-вывода завершается немедленно.
Используйте значение NULL для этого параметра, если параметр lpOverlapped не равен NULL , чтобы избежать потенциально ошибочных результатов. Этот параметр может иметь значение NULL , только если параметр lpOverlapped не равен NULL.
[in] dwFlags
Флаги, используемые для изменения поведения вызова функции WSASendTo .
[in] lpTo
Необязательный указатель на адрес целевого сокета в структуре SOCKADDR .
[in] iTolen
Размер адреса в байтах в параметре lpTo .
[in] lpOverlapped
Указатель на структуру WSAOVERLAPPED (игнорируется для неперекрывающихся сокетов).
[in] lpCompletionRoutine
Тип: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
Указатель на подпрограмму завершения, вызываемую при завершении операции отправки (игнорируется для неперекрывающихся сокетов).
Возвращаемое значение
Если ошибка не возникает и операция отправки была завершена немедленно, WSASendTo возвращает ноль. В этом случае подпрограмма завершения уже запланирована на вызов после того, как вызывающий поток перейдет в состояние предупреждения. В противном случае возвращается значение SOCKET_ERROR , а конкретный код ошибки можно получить, вызвав WSAGetLastError. Код ошибки WSA_IO_PENDING указывает, что перекрывающаяся операция была успешно инициирована и что завершение будет указано позже. Любой другой код ошибки указывает на то, что перекрывающаяся операция не была успешно инициирована и не будет никаких указаний завершения.
Код ошибки | Значение |
---|---|
Запрошенный адрес является широковещательным, но соответствующий флаг не установлен. | |
Удаленный адрес не является допустимым адресом (например, ADDR_ANY). | |
Адреса из заданного семейства адресов не могут использоваться с этим сокетом. | |
Для сокета датаграммы UDP эта ошибка указывает на то, что предыдущая операция отправки привела к сообщению ICMP "Порт недоступен". | |
Требуется адрес назначения. | |
Параметры lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent или lpCompletionRoutine не являются частью адресного пространства пользователя или параметр lpTo слишком мал. | |
Сделана попытка выполнить операцию на сокете для недоступного хоста. | |
Выполняется блокирующий вызов Windows Sockets 1.1 или поставщик услуг по-прежнему обрабатывает функцию обратного вызова. | |
Блокирующий вызов Windows Socket 1.1 был отменен через WSACancelBlockingCall. | |
Сокет не был привязан с помощью привязки или сокет не создан с перекрывающимся флагом. | |
Сокет ориентирован на сообщения, и сообщение больше максимального значения, поддерживаемого базовым транспортом. | |
Произошел сбой сетевой подсистемы. | |
Для сокета датаграмм эта ошибка указывает на то, что срок жизни истек. | |
В настоящее время сеть недоступна с этого узла. | |
Поставщик сокетов Windows сообщает о взаимоблокировке буфера. | |
Сокет не подключен (только сокеты, ориентированные на подключение). | |
Дескриптор не является сокетом. | |
Сокет был выключен; невозможно выполнить WSASendTo в сокете после вызова завершения работыс параметром SD_SEND или SD_BOTH. | |
Windows NT:
Перекрывающиеся сокеты: слишком много невыполненных перекрывающихся запросов ввода-вывода. Неперекрывающиеся сокеты. Сокет помечается как неблокируемый, и операция отправки не может быть завершена немедленно. |
|
Перед использованием этой функции должен произойти успешный вызов WSAStartup . | |
Перекрываемая операция была успешно инициирована, и ее завершение будет указано позже. | |
Перекрываемая операция была отменена из-за закрытия сокета или выполнения команды SIO_FLUSH в WSAIoctl. |
Комментарии
Функция WSASendTo предоставляет расширенные функции по сравнению со стандартной функцией sendto в двух важных областях:
- Его можно использовать в сочетании с перекрывающимися сокетами для выполнения перекрывающихся операций отправки.
- Он позволяет указать несколько буферов отправки, что делает их применимыми к типу точечной и сборной операций ввода-вывода.
Для перекрывающихся сокетов (созданных с помощью WSASocket с флагом WSA_FLAG_OVERLAPPED) при отправке данных используются перекрывающиеся операции ввода-вывода, если только lpOverlapped и lpCompletionRoutine не имеют значения NULL , в этом случае сокет считается неперекрытым сокетом. Когда буферы были использованы транспортом, произойдет указание завершения (вызов подпрограммы завершения или настройка объекта события). Если операция не завершается немедленно, окончательное состояние завершения извлекается с помощью процедуры завершения или WSAGetOverlappedResult.
Для неперекрывающихся сокетов последние два параметра (lpOverlapped, lpCompletionRoutine) игнорируются, и WSASendTo использует ту же семантику блокировки, что и send. Данные копируются из буферов в буфер транспорта. Если сокет не блокируется и ориентирован на поток и в буфере транспорта недостаточно места, WSASendTo возвращает только часть буферов приложения. Учитывая ту же ситуацию с буфером и блокирующий сокет, WSASendTo будет блокироваться до тех пор, пока не будет занято все содержимое буфера приложения.
Если эта функция выполняется в перекрывающемся режиме, поставщик службы Winsock отвечает за запись структур WSABUF перед возвращением из этого вызова. Это позволяет приложениям создавать массивы WSABUF на основе стека, на которые указывает параметр lpBuffers .
Для сокетов, ориентированных на сообщения, необходимо соблюдать осторожность, чтобы не превышать максимальный размер сообщения базового транспорта, который можно получить, получив значение параметра сокета SO_MAX_MSG_SIZE. Если данные слишком длинные для атомарной передачи через базовый протокол, возвращается ошибка WSAEMSGSIZE и данные не передаются.
Если сокет не привязан, система присваивает ему уникальные значения, а затем помечается как привязанный.
Если сокет подключен, функцию getsockname можно использовать для определения локального IP-адреса и порта, связанных с сокетом.
Если сокет не подключен,
Функцию getockname можно использовать для определения номера локального порта, связанного с сокетом, но возвращаемый IP-адрес устанавливается в качестве подстановочного адреса для заданного протокола (например, INADDR_ANY или "0.0.0.0" для IPv4 и IN6ADDR_ANY_INIT или "::" для IPv6).
Успешное завершение WSASendTo не означает, что данные были успешно доставлены.
Параметр dwFlags можно использовать для влияния на поведение вызова функции за пределами параметров, указанных для связанного сокета. То есть семантика этой функции определяется параметрами сокета и параметром dwFlags . Последнее создается с помощью побитового оператора OR с любым из значений, перечисленных в следующей таблице.
Значение | Значение |
---|---|
MSG_DONTROUTE | Указывает, что данные не должны подвергаться маршрутизации. Поставщик службы сокета Windows может игнорировать этот флаг. |
MSG_OOB | Отправка данных OOB (только сокет в стиле потока, например SOCK_STREAM ). |
MSG_PARTIAL | Указывает, что lpBuffers содержит только частичное сообщение. Имейте в виду, что код ошибки WSAEOPNOTSUPP будет возвращен транспортом, который не поддерживает частичную передачу сообщений. |
Перекрывающиеся ввода-вывода сокета
Если перекрывающаяся операция завершается немедленно, WSASendTo возвращает нулевое значение, а параметр lpNumberOfBytesSent обновляется числом отправленных байтов. Если перекрывающаяся операция успешно инициирована и завершится позже, WSASendTo возвращает SOCKET_ERROR и указывает код ошибки WSA_IO_PENDING. В этом случае lpNumberOfBytesSent не обновляется. После завершения перекрывающейся операции объем передаваемых данных указывается либо с помощью параметра cbTransferred в подпрограмме завершения (если указано), либо с помощью параметра lpcbTransfer в WSAGetOverlappedResult.Параметр lpOverlapped должен быть действителен в течение всего времени перекрывающейся операции. Если одновременно выполняется несколько операций ввода-вывода, каждая из них должна ссылаться на отдельную структуру WSAOVERLAPPED .
Если параметр lpCompletionRoutine имеет значение NULL, параметр hEventlpOverlapped получает сигнал о завершении перекрывающейся операции, если он содержит допустимый дескриптор объекта события. Приложение может использовать WSAWaitForMultipleEvents или WSAGetOverlappedResult для ожидания или опроса объекта события.
Если lpCompletionRoutine не имеет значение NULL, параметр hEvent игнорируется и может использоваться приложением для передачи контекстных сведений в подпрограмму завершения. Вызывающий объект, который передает не nulllpCompletionRoutine и более поздние версии вызывает WSAGetOverlappedResult для того же перекрывающегося запроса ввода-вывода, может не задать для параметра fWait для этого вызова WSAGetOverlappedResult значение TRUE. В этом случае использование параметра hEvent не определено, и попытка дождаться параметра hEvent приведет к непредсказуемым результатам.
Процедура завершения соответствует тем же правилам, что и для процедур завершения ввода-вывода файлов Windows. Подпрограмма завершения не будет вызываться до тех пор, пока поток не перейдет в состояние ожидания с оповещением, например при вызове функции WSAWaitForMultipleEvents с параметром fAlertable, равнымTRUE .
Поставщики транспорта позволяют приложению вызывать операции отправки и получения из контекста подпрограммы завершения ввода-вывода сокета и гарантируют, что для данного сокета подпрограммы завершения ввода-вывода не будут вложенными. Это позволяет передавать конфиденциальные данные во времени полностью в контексте вытеснения.
Прототип подпрограммы завершения выглядит следующим образом.
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
Функция CompletionRoutine — это заполнитель для имени функции, определяемой приложением или библиотекой. Параметр dwError указывает состояние завершения перекрывающейся операции, как указано в параметре lpOverlapped. Параметр cbTransferred указывает количество отправленных байтов. В настоящее время значения флагов не определены, и dwFlags будет иметь нулевое значение. Эта функция не возвращает значение.
Возврат из этой функции позволяет использовать другую подпрограмму завершения для этого сокета. Все подпрограммы завершения ожидания вызываются до того, как оповещенный поток будет удовлетворен кодом возврата WSA_IO_COMPLETION. Подпрограммы завершения можно вызывать в любом порядке, не обязательно в том же порядке, в котором выполняются перекрывающиеся операции. Однако отправленные буферы гарантированно будут отправляться в том же порядке, в который они указаны.
Пример кода
В следующем примере демонстрируется использование функции WSASendTo с использованием объекта события .#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
int __cdecl main(int argc, char **argv)
{
//---------------------------------------------
// Declare and initialize variables
WSADATA wsaData;
WSABUF DataBuf;
WSAOVERLAPPED Overlapped;
SOCKET SendToSocket = INVALID_SOCKET;
struct sockaddr_in RecvAddr;
struct sockaddr_in LocalAddr;
int RecvAddrSize = sizeof (RecvAddr);
int LocalAddrSize = sizeof (LocalAddr);
u_short Port = 27777;
struct hostent *localHost;
char *ip;
char *targetip;
char *targetport;
char SendBuf[1024] = "Data buffer to send";
int BufLen = 1024;
DWORD BytesSent = 0;
DWORD Flags = 0;
int rc, err;
int retval = 0;
// Validate the parameters
if (argc != 3) {
printf("usage: %s targetip port\n", argv[0]);
printf(" to sendto the localhost on port 27777\n");
printf(" %s 127.0.0.1 27777\n", argv[0]);
return 1;
}
targetip = argv[1];
targetport = argv[2];
//---------------------------------------------
// Initialize Winsock
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc != 0) {
printf("Unable to load Winsock: %d\n", rc);
return 1;
}
// Make sure the Overlapped struct is zeroed out
SecureZeroMemory((PVOID) &Overlapped, sizeof(WSAOVERLAPPED));
// Create an event handle and setup the overlapped structure.
Overlapped.hEvent = WSACreateEvent();
if (Overlapped.hEvent == WSA_INVALID_EVENT) {
printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
//---------------------------------------------
// Create a socket for sending data
SendToSocket =
WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (SendToSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACloseEvent(Overlapped.hEvent);
WSACleanup();
return 1;
}
//---------------------------------------------
// Set up the RecvAddr structure with the IP address of
// the receiver (in this example case "123.123.123.1")
// and the specified port number.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_addr.s_addr = inet_addr(targetip);
if (RecvAddr.sin_addr.s_addr == INADDR_NONE) {
printf("The target ip address entered must be a legal IPv4 address\n");
WSACloseEvent(Overlapped.hEvent);
WSACleanup();
return 1;
}
RecvAddr.sin_port = htons( (u_short) atoi(targetport));
if(RecvAddr.sin_port == 0) {
printf("The targetport must be a legal UDP port number\n");
WSACloseEvent(Overlapped.hEvent);
WSACleanup();
return 1;
}
//---------------------------------------------
// Set up the LocalAddr structure with the local IP address
// and the specified port number.
localHost = gethostbyname("");
ip = inet_ntoa(*(struct in_addr *) *localHost->h_addr_list);
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_addr.s_addr = inet_addr(ip);
LocalAddr.sin_port = htons(Port);
//---------------------------------------------
// Bind the sending socket to the LocalAddr structure
// that has the internet address family, local IP address
// and specified port number.
rc = bind(SendToSocket, (struct sockaddr *) &LocalAddr, LocalAddrSize);
if (rc == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
WSACloseEvent(Overlapped.hEvent);
closesocket(SendToSocket);
WSACleanup();
return 1;
}
//---------------------------------------------
// Send a datagram to the receiver
printf("Sending datagram from IPv4 address = %s port=%d\n",
inet_ntoa(LocalAddr.sin_addr), ntohs(LocalAddr.sin_port) );
printf(" to IPv4 address = %s port=%d\n",
inet_ntoa(RecvAddr.sin_addr), ntohs(RecvAddr.sin_port) );
// printf("Sending a datagram...\n");
DataBuf.len = BufLen;
DataBuf.buf = SendBuf;
rc = WSASendTo(SendToSocket, &DataBuf, 1,
&BytesSent, Flags, (SOCKADDR *) & RecvAddr,
RecvAddrSize, &Overlapped, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
printf("WSASendTo failed with error: %d\n", err);
WSACloseEvent(Overlapped.hEvent);
closesocket(SendToSocket);
WSACleanup();
return 1;
}
rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents failed with error: %d\n",
WSAGetLastError());
retval = 1;
}
rc = WSAGetOverlappedResult(SendToSocket, &Overlapped, &BytesSent,
FALSE, &Flags);
if (rc == FALSE) {
printf("WSASendTo failed with error: %d\n", WSAGetLastError());
retval = 1;
}
else
printf("Number of sent bytes = %d\n", BytesSent);
//---------------------------------------------
// When the application is finished sending, close the socket.
printf("Finished sending. Closing socket.\n");
WSACloseEvent(Overlapped.hEvent);
closesocket(SendToSocket);
printf("Exiting.\n");
//---------------------------------------------
// Clean up and quit.
WSACleanup();
return (retval);
}
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 | winsock2.h |
Библиотека | Ws2_32.lib |
DLL | Ws2_32.dll |