Функция WSASend (winsock2.h)
Функция WSASend отправляет данные в подключенный сокет.
Синтаксис
int WSAAPI WSASend(
[in] SOCKET s,
[in] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesSent,
[in] DWORD dwFlags,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Параметры
[in] s
Дескриптор, идентифицирующий подключенный сокет.
[in] lpBuffers
Указатель на массив структур WSABUF . Каждая структура WSABUF содержит указатель на буфер и длину буфера (в байтах). Для приложения Winsock после вызова функции WSASend система владеет этими буферами, и приложение может не получить к ним доступ. Этот массив должен оставаться действительным в течение операции отправки.
[in] dwBufferCount
Количество структур WSABUF в массиве lpBuffers .
[out] lpNumberOfBytesSent
Указатель на число в байтах, отправляемое этим вызовом, если операция ввода-вывода завершается немедленно.
Используйте значение NULL для этого параметра, если параметр lpOverlapped не равен NULL , чтобы избежать потенциально ошибочных результатов. Этот параметр может иметь значение NULL , только если параметр lpOverlapped не равен NULL.
[in] dwFlags
Флаги, используемые для изменения поведения вызова функции WSASend . Дополнительные сведения см. в разделе Использование dwFlags в разделе Примечания.
[in] lpOverlapped
Указатель на структуру WSAOVERLAPPED . Этот параметр игнорируется для неперекрывающихся сокетов.
[in] lpCompletionRoutine
Тип: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
Указатель на подпрограмму завершения, вызываемую при завершении операции отправки. Этот параметр игнорируется для неперекрывающихся сокетов.
Возвращаемое значение
Если ошибка не возникает и операция отправки завершена немедленно, WSASend возвращает ноль. В этом случае подпрограмма завершения уже запланирована на вызов после того, как вызывающий поток перейдет в состояние предупреждения. В противном случае возвращается значение SOCKET_ERROR , а конкретный код ошибки можно получить, вызвав WSAGetLastError. Код ошибки WSA_IO_PENDING указывает, что перекрывающаяся операция была успешно инициирована и что завершение будет указано позже. Любой другой код ошибки указывает на то, что перекрывающаяся операция не была успешно инициирована и не будет никаких указаний завершения.
Код ошибки | Значение |
---|---|
Виртуальное подключение разорвано из-за тайм-аута или иного сбоя. | |
Для сокета потока виртуальная цепь была сброшена удаленной стороной. Приложение должно закрыть сокет, поскольку он больше не может использоваться. Для сокета датаграммы UDP эта ошибка указывает на то, что предыдущая операция отправки привела к сообщению ICMP "Порт недоступен". | |
Параметр lpBuffers, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine не полностью содержится в допустимой части адресного пространства пользователя. | |
Блокирующий вызов Windows Socket 1.1 был отменен через WSACancelBlockingCall. | |
Выполняется блокирующий вызов Windows Sockets 1.1 или поставщик услуг по-прежнему обрабатывает функцию обратного вызова. | |
Сокет не был привязан с помощью привязки или сокет не создан с перекрывающимся флагом. | |
Сокет ориентирован на сообщения, и сообщение больше максимального значения, поддерживаемого базовым транспортом. | |
Произошел сбой сетевой подсистемы. | |
Для сокета потока подключение было разорвано из-за действия поддержания активности, обнаруживающего сбой во время выполнения операции. Для сокета датаграмм эта ошибка указывает на то, что срок жизни истек. | |
Поставщик сокетов Windows сообщает о взаимоблокировке буфера. | |
Сокет не подключен. | |
Дескриптор не является сокетом. | |
MSG_OOB указано, но сокет не является потоковым, например тип SOCK_STREAM, данные OOB не поддерживаются в домене связи, связанном с этим сокетом, MSG_PARTIAL не поддерживаются, либо сокет является однонаправленным и поддерживает только операции получения. | |
Сокет был выключен; Невозможно выполнить WSASend в сокете после вызова завершения работы с параметром SD_SEND или SD_BOTH. | |
Windows NT:
Перекрывающиеся сокеты. Существует слишком много невыполненных перекрывающихся запросов ввода-вывода. Неперекрывающиеся сокеты. Сокет помечается как неблокируемый, и операция отправки не может быть завершена немедленно. |
|
Перед использованием этой функции должен произойти успешный вызов WSAStartup . | |
Перекрываемая операция была успешно инициирована, и ее завершение будет указано позже. | |
Перекрывающаяся операция была отменена из-за закрытия сокета, выполнения команды "SIO_FLUSH" в WSAIoctl или из-за того, что поток, инициирующий перекрывающийся запрос, завершился до завершения операции. Дополнительные сведения см. в разделе «Примечания». |
Комментарии
Функция WSASend предоставляет функции сверх стандартной функции отправки в двух важных областях:
- Его можно использовать в сочетании с перекрывающимися сокетами для выполнения перекрывающихся операций отправки .
- Он позволяет указать несколько буферов отправки , что делает их применимыми к типу точечной и сборной операций ввода-вывода.
Сокет, созданный функцией сокета , будет иметь перекрывающийся атрибут по умолчанию. Сокет, созданный функцией WSASocket с параметром dwFlags, переданнымв WSASocket с WSA_FLAG_OVERLAPPED набором битов, будет иметь перекрывающийся атрибут. Для сокетов с перекрывающимся атрибутом WSASend использует перекрывающиеся операции ввода-вывода, если только параметры lpOverlapped и lpCompletionRoutine не имеют значения NULL. В этом случае сокет рассматривается как неперекрывающийся сокет. Если буферы были использованы транспортом, произойдет указание завершения подпрограммы или задания объекта события. Если операция не завершается немедленно, окончательное состояние завершения извлекается с помощью процедуры завершения или WSAGetOverlappedResult.
Если и lpOverlapped , и lpCompletionRoutine имеют значение NULL, сокет в этой функции будет рассматриваться как неперекрытый сокет.
Для неперекрывающихся сокетов два последних параметра (lpOverlapped, lpCompletionRoutine) игнорируются, а WSASend принимает ту же семантику блокировки, что и send. Данные копируются из буферов в буфер транспорта. Если сокет не блокируется и ориентирован на поток и в буфере транспорта недостаточно места, WSASend возвращает только часть буферов приложения. Учитывая ту же ситуацию с буфером и блокирующий сокет, WSASend будет блокироваться до тех пор, пока не будет занято все содержимое буфера приложения.
Для сокетов, ориентированных на сообщения, не следует превышать максимальный размер сообщения базового поставщика, который можно получить, получив значение параметра сокета SO_MAX_MSG_SIZE. Если данные слишком длинные для атомарной передачи через базовый протокол, возвращается ошибка WSAEMSGSIZE и данные не передаются.
Windows Me/98/95: Функция WSASend поддерживает не более 16 буферов.
Использование dwFlags
Параметр dwFlags можно использовать для влияния на поведение вызова функции за пределами параметров, указанных для связанного сокета. То есть семантика этой функции определяется параметрами сокета и параметром dwFlags . Последнее создается с помощью побитового оператора OR с любым из значений, перечисленных в следующей таблице.Значение | Значение |
---|---|
MSG_DONTROUTE | Указывает, что данные не должны подвергаться маршрутизации. Поставщик службы Windows Sockets может игнорировать этот флаг. |
MSG_OOB | Отправлять данные OOB только в сокет в стиле потока, например SOCK_STREAM . |
MSG_PARTIAL | Указывает, что lpBuffers содержит только частичное сообщение. Имейте в виду, что код ошибки WSAEOPNOTSUPP будет возвращен транспортом, который не поддерживает частичную передачу сообщений. |
Перекрывающиеся сокеты ввода-вывода
Если перекрывающаяся операция завершается немедленно, WSASend возвращает нулевое значение, а параметр lpNumberOfBytesSent обновляется числом отправленных байтов. Если перекрывающаяся операция успешно инициирована и завершится позже, WSASend возвращает SOCKET_ERROR и указывает код ошибки WSA_IO_PENDING. В этом случае lpNumberOfBytesSent не обновляется. После завершения перекрывающейся операции объем передаваемых данных указывается либо с помощью параметра cbTransferred в подпрограмме завершения (если указано), либо с помощью параметра lpcbTransfer в WSAGetOverlappedResult.Параметр lpOverlapped должен быть действителен в течение всего периода перекрываемой операции. Если одновременно выполняется несколько операций ввода-вывода, каждая из них должна ссылаться на отдельную структуру WSAOVERLAPPED .
Если параметр lpCompletionRoutine имеет значение NULL, параметр hEventобъекта lpOverlapped получает сигнал о завершении перекрываемой операции, если он содержит допустимый дескриптор объекта события. Приложение может использовать WSAWaitForMultipleEvents или WSAGetOverlappedResult для ожидания или опроса объекта события.
Если значение lpCompletionRoutine не равно NULL, параметр hEvent игнорируется и может использоваться приложением для передачи контекстных сведений в подпрограмму завершения. Вызывающий объект, который передает lpCompletionRoutine, отличный от NULL, а затем вызывает WSAGetOverlappedResult для того же перекрывающегося запроса ввода-вывода, может не задать для параметра fWait для этого вызова WSAGetOverlappedResult значение TRUE. В этом случае использование параметра hEvent не определено, и попытка ожидания параметра hEvent приведет к непредсказуемым результатам.
Процедура завершения соответствует тем же правилам, которые предусмотрены для процедур завершения файлового ввода-вывода Windows. Подпрограмма завершения не будет вызываться до тех пор, пока поток не будет находиться в состоянии ожидания, доступном для предупреждений, например при вызове функции WSAWaitForMultipleEvents с параметром fAlertable, равнымTRUE .
Поставщики транспорта позволяют приложению вызывать операции отправки и получения из контекста подпрограммы завершения ввода-вывода сокета и гарантируют, что для данного сокета подпрограммы завершения ввода-вывода не будут вложенными. Это позволяет полностью выполнять передачу конфиденциальных во времени данных в контексте вытеснения.
Следующий пример кода C++ является прототипом процедуры завершения.
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
Функция CompletionRoutine — это заполнитель для имени определяемой приложением или библиотекой функции. Параметр dwError указывает состояние завершения для перекрываемой операции, как указано в lpOverlapped. cbTransferred указывает количество отправленных байтов. В настоящее время значения флагов не определены, и dwFlags будет иметь нулевое значение. Эта функция не возвращает значение.
Возвращаясь из этой функции, можно использовать для этого сокета вызов другой подпрограммы отложенного завершения. Все подпрограммы завершения ожидания вызываются до того, как оповещенный поток будет удовлетворен кодом возврата WSA_IO_COMPLETION. Процедуры завершения могут вызываться в любом порядке, не обязательно в том же порядке, в каком выполняются перекрывающиеся операции. Однако отправленные буферы гарантированно будут отправляться в том же порядке, в который они указаны.
Порядок вызовов WSASend также является порядком передачи буферов на транспортный уровень. WSASend не следует вызывать в одном и том же сокете, ориентированном на поток, из разных потоков, так как некоторые поставщики Winsock могут разделить большой запрос на отправку на несколько передач, что может привести к непреднамеренное чередование данных из нескольких одновременных запросов на отправку в одном сокете, ориентированном на поток.
Пример кода
В следующем примере кода показано, как использовать функцию WSASend в режиме перекрывающихся операций ввода-вывода.#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#define DATA_BUFSIZE 4096
#define SEND_COUNT 10
int __cdecl main()
{
WSADATA wsd;
struct addrinfo *result = NULL;
struct addrinfo hints;
WSAOVERLAPPED SendOverlapped;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET AcceptSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD SendBytes;
DWORD Flags;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc, i;
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
printf("Unable to load Winsock: %d\n", rc);
return 1;
}
// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID) & hints, sizeof(struct addrinfo));
// Initialize the hints to obtain the
// wildcard bind address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
rc = getaddrinfo(NULL, "27015", &hints, &result);
if (rc != 0) {
printf("getaddrinfo failed with error: %d\n", rc);
return 1;
}
ListenSocket = socket(result->ai_family,
result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
return 1;
}
rc = bind(ListenSocket, result->ai_addr, (int) result->ai_addrlen);
if (rc == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
rc = listen(ListenSocket, 1);
if (rc == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
// Accept an incoming connection request
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
printf("Client Accepted...\n");
// Make sure the SendOverlapped struct is zeroed out
SecureZeroMemory((PVOID) & SendOverlapped, sizeof (WSAOVERLAPPED));
// Create an event handle and setup the overlapped structure.
SendOverlapped.hEvent = WSACreateEvent();
if (SendOverlapped.hEvent == NULL) {
printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
closesocket(AcceptSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
for (i = 0; i < SEND_COUNT; i++) {
rc = WSASend(AcceptSocket, &DataBuf, 1,
&SendBytes, 0, &SendOverlapped, NULL);
if ((rc == SOCKET_ERROR) &&
(WSA_IO_PENDING != (err = WSAGetLastError()))) {
printf("WSASend failed with error: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &SendOverlapped.hEvent, TRUE, INFINITE,
TRUE);
if (rc == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents failed with error: %d\n",
WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(AcceptSocket, &SendOverlapped, &SendBytes,
FALSE, &Flags);
if (rc == FALSE) {
printf("WSASend failed with error: %d\n", WSAGetLastError());
break;
}
printf("Wrote %d bytes\n", SendBytes);
WSAResetEvent(SendOverlapped.hEvent);
}
WSACloseEvent(SendOverlapped.hEvent);
closesocket(AcceptSocket);
closesocket(ListenSocket);
freeaddrinfo(result);
WSACleanup();
return 0;
}
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 |