Поделиться через


Функция 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 указывает, что перекрывающаяся операция была успешно инициирована и что завершение будет указано позже. Любой другой код ошибки указывает на то, что перекрывающаяся операция не была успешно инициирована и не будет никаких указаний завершения.

Код ошибки Значение
WSAECONNABORTED
Виртуальное подключение разорвано из-за тайм-аута или иного сбоя.
WSAECONNRESET
Для сокета потока виртуальная цепь была сброшена удаленной стороной. Приложение должно закрыть сокет, поскольку он больше не может использоваться. Для сокета датаграммы UDP эта ошибка указывает на то, что предыдущая операция отправки привела к сообщению ICMP "Порт недоступен".
WSAEFAULT
Параметр lpBuffers, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine не полностью содержится в допустимой части адресного пространства пользователя.
WSAEINTR
Блокирующий вызов Windows Socket 1.1 был отменен через WSACancelBlockingCall.
WSAEINPROGRESS
Выполняется блокирующий вызов Windows Sockets 1.1 или поставщик услуг по-прежнему обрабатывает функцию обратного вызова.
WSAEINVAL
Сокет не был привязан с помощью привязки или сокет не создан с перекрывающимся флагом.
WSAEMSGSIZE
Сокет ориентирован на сообщения, и сообщение больше максимального значения, поддерживаемого базовым транспортом.
WSAENETDOWN
Произошел сбой сетевой подсистемы.
WSAENETRESET
Для сокета потока подключение было разорвано из-за действия поддержания активности, обнаруживающего сбой во время выполнения операции. Для сокета датаграмм эта ошибка указывает на то, что срок жизни истек.
WSAENOBUFS
Поставщик сокетов Windows сообщает о взаимоблокировке буфера.
WSAENOTCONN
Сокет не подключен.
WSAENOTSOCK
Дескриптор не является сокетом.
WSAEOPNOTSUPP
MSG_OOB указано, но сокет не является потоковым, например тип SOCK_STREAM, данные OOB не поддерживаются в домене связи, связанном с этим сокетом, MSG_PARTIAL не поддерживаются, либо сокет является однонаправленным и поддерживает только операции получения.
WSAESHUTDOWN
Сокет был выключен; Невозможно выполнить WSASend в сокете после вызова завершения работы с параметром SD_SEND или SD_BOTH.
WSAEWOULDBLOCK
Windows NT:

Перекрывающиеся сокеты. Существует слишком много невыполненных перекрывающихся запросов ввода-вывода. Неперекрывающиеся сокеты. Сокет помечается как неблокируемый, и операция отправки не может быть завершена немедленно.

WSANOTINITIALISED
Перед использованием этой функции должен произойти успешный вызов WSAStartup .
WSA_IO_PENDING
Перекрываемая операция была успешно инициирована, и ее завершение будет указано позже.
WSA_OPERATION_ABORTED
Перекрывающаяся операция была отменена из-за закрытия сокета, выполнения команды "SIO_FLUSH" в WSAIoctl или из-за того, что поток, инициирующий перекрывающийся запрос, завершился до завершения операции. Дополнительные сведения см. в разделе «Примечания».

Комментарии

Функция WSASend предоставляет функции сверх стандартной функции отправки в двух важных областях:

  • Его можно использовать в сочетании с перекрывающимися сокетами для выполнения перекрывающихся операций отправки .
  • Он позволяет указать несколько буферов отправки , что делает их применимыми к типу точечной и сборной операций ввода-вывода.
Функция WSASend используется для записи исходящих данных из одного или нескольких буферов в сокете, ориентированном на подключение, указанном параметром s. Однако его также можно использовать в сокетах без подключения, у которых указан адрес однорангового узла по умолчанию, установленный с помощью функции connect или WSAConnect .

Сокет, созданный функцией сокета , будет иметь перекрывающийся атрибут по умолчанию. Сокет, созданный функцией WSASocket с параметром dwFlags, переданнымв WSASocket с WSA_FLAG_OVERLAPPED набором битов, будет иметь перекрывающийся атрибут. Для сокетов с перекрывающимся атрибутом WSASend использует перекрывающиеся операции ввода-вывода, если только параметры lpOverlapped и lpCompletionRoutine не имеют значения NULL. В этом случае сокет рассматривается как неперекрывающийся сокет. Если буферы были использованы транспортом, произойдет указание завершения подпрограммы или задания объекта события. Если операция не завершается немедленно, окончательное состояние завершения извлекается с помощью процедуры завершения или WSAGetOverlappedResult.

Если и lpOverlapped , и lpCompletionRoutine имеют значение NULL, сокет в этой функции будет рассматриваться как неперекрытый сокет.

Для неперекрывающихся сокетов два последних параметра (lpOverlapped, lpCompletionRoutine) игнорируются, а WSASend принимает ту же семантику блокировки, что и send. Данные копируются из буферов в буфер транспорта. Если сокет не блокируется и ориентирован на поток и в буфере транспорта недостаточно места, WSASend возвращает только часть буферов приложения. Учитывая ту же ситуацию с буфером и блокирующий сокет, WSASend будет блокироваться до тех пор, пока не будет занято все содержимое буфера приложения.

Примечание Параметры сокетов SO_RCVTIMEO и SO_SNDTIMEO применяются только к блокирующим сокетам.
 
Если эта функция выполняется в перекрывающемся режиме, поставщик службы Winsock отвечает за запись структур WSABUF перед возвращением из этого вызова. Это позволяет приложениям создавать массивы WSABUF на основе стека, на которые указывает параметр lpBuffers .

Для сокетов, ориентированных на сообщения, не следует превышать максимальный размер сообщения базового поставщика, который можно получить, получив значение параметра сокета SO_MAX_MSG_SIZE. Если данные слишком длинные для атомарной передачи через базовый протокол, возвращается ошибка WSAEMSGSIZE и данные не передаются.

Windows Me/98/95: Функция WSASend поддерживает не более 16 буферов.

Примечание Успешное завершение WSASend не означает, что данные были успешно доставлены.
 

Использование dwFlags

Параметр dwFlags можно использовать для влияния на поведение вызова функции за пределами параметров, указанных для связанного сокета. То есть семантика этой функции определяется параметрами сокета и параметром dwFlags . Последнее создается с помощью побитового оператора OR с любым из значений, перечисленных в следующей таблице.
Значение Значение
MSG_DONTROUTE Указывает, что данные не должны подвергаться маршрутизации. Поставщик службы Windows Sockets может игнорировать этот флаг.
MSG_OOB Отправлять данные OOB только в сокет в стиле потока, например SOCK_STREAM .
MSG_PARTIAL Указывает, что lpBuffers содержит только частичное сообщение. Имейте в виду, что код ошибки WSAEOPNOTSUPP будет возвращен транспортом, который не поддерживает частичную передачу сообщений.
 
Примечание При выполнении блокирующего вызова Winsock, например WSASend , с параметром lpOverlapped , имеющим значение NULL, Winsock может потребоваться дождаться сетевого события, прежде чем вызов сможет завершиться. В этой ситуации Winsock выполняет оповещенное ожидание, которое может быть прервано асинхронным вызовом процедуры (APC), запланированным в том же потоке. Выполнение другого блокирующего вызова Winsock внутри APC, который прервал текущий блокирующий вызов Winsock в том же потоке, приведет к неопределенному поведению, и клиенты Winsock никогда не должны пытаться его выполнять.
 

Перекрывающиеся сокеты ввода-вывода

Если перекрывающаяся операция завершается немедленно, WSASend возвращает нулевое значение, а параметр lpNumberOfBytesSent обновляется числом отправленных байтов. Если перекрывающаяся операция успешно инициирована и завершится позже, WSASend возвращает SOCKET_ERROR и указывает код ошибки WSA_IO_PENDING. В этом случае lpNumberOfBytesSent не обновляется. После завершения перекрывающейся операции объем передаваемых данных указывается либо с помощью параметра cbTransferred в подпрограмме завершения (если указано), либо с помощью параметра lpcbTransfer в WSAGetOverlappedResult.
Примечание Все операции ввода-вывода, инициированные данным потоком, отменяются при выходе из этого потока. Для перекрывающихся сокетов ожидающие асинхронные операции могут завершиться ошибкой, если поток будет закрыт до завершения операций. Дополнительные сведения см. в разделе ExitThread.
 
Функцию WSASend с использованием перекрывающихся операций ввода-вывода можно вызывать из подпрограммы завершения предыдущей функции WSARecv, WSARecvFrom, WSASend или WSASendTo . Это позволяет полностью выполнять передачу конфиденциальных во времени данных в контексте вытеснения.

Параметр 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

См. также раздел

WSABUF

WSACloseEvent

WSAConnect

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASocket

WSAWaitForMultipleEvents

Функции Winsock

Справочник по Winsock

connect;

send

Сокета