Condividi tramite


Funzione WSASendTo (winsock2.h)

La funzione WSASendTo invia dati a una destinazione specifica, usando le operazioni di I/O sovrapposte, se applicabile.

Sintassi

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
);

Parametri

[in] s

Descrittore che identifica un socket (possibilmente connesso).

[in] lpBuffers

Puntatore a una matrice di strutture WSABUF . Ogni struttura WSABUF contiene un puntatore a un buffer e la lunghezza del buffer, in byte. Per un'applicazione Winsock, una volta chiamata la funzione WSASendTo , il sistema possiede questi buffer e l'applicazione potrebbe non accedervi. Questa matrice deve rimanere valida per la durata dell'operazione di invio.

[in] dwBufferCount

Numero di strutture WSABUF nella matrice lpBuffers .

[out] lpNumberOfBytesSent

Puntatore al numero di byte inviati da questa chiamata se l'operazione di I/O viene completata immediatamente.

Usare NULL per questo parametro se il parametro lpOverlapped non è NULL per evitare risultati potenzialmente errati. Questo parametro può essere NULL solo se il parametro lpOverlapped non è NULL.

[in] dwFlags

Flag utilizzati per modificare il comportamento della chiamata di funzione WSASendTo .

[in] lpTo

Puntatore facoltativo all'indirizzo del socket di destinazione nella struttura SOCKADDR .

[in] iTolen

Dimensione, in byte, dell'indirizzo nel parametro lpTo .

[in] lpOverlapped

Puntatore a una struttura WSAOVERLAPPED (ignorata per i socket non sovrapposti).

[in] lpCompletionRoutine

Tipo: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

Puntatore alla routine di completamento chiamata quando l'operazione di invio è stata completata (ignorata per i socket non sovrapposti).

Valore restituito

Se non si verifica alcun errore e l'operazione di invio è stata completata immediatamente, WSASendTo restituisce zero. In questo caso, la routine di completamento sarà già stata pianificata per essere chiamata dopo che il thread chiamante si trova nello stato di avviso. In caso contrario, viene restituito un valore di SOCKET_ERROR e è possibile recuperare un codice di errore specifico chiamando WSAGetLastError. Il codice di errore WSA_IO_PENDING indica che l'operazione sovrapposta è stata avviata correttamente e che il completamento verrà indicato in un secondo momento. Qualsiasi altro codice di errore indica che l'operazione sovrapposta non è stata avviata correttamente e non si verificherà alcuna indicazione di completamento.

Codice di errore Significato
WSAEACCES
L'indirizzo richiesto è un indirizzo broadcast, ma il flag appropriato non è stato impostato.
WSAEADDRNOTAVAIL
L'indirizzo remoto non è un indirizzo valido, ad esempio ADDR_ANY.
WSAEAFNOSUPPORT
Impossibile utilizzare gli indirizzi della famiglia specificata con questo socket.
WSAECONNRESET
Per un socket datagram UDP, questo errore indica che un'operazione di invio precedente ha generato un messaggio ICMP "Port Unreachable".
WSAEDESTADDRREQ
È necessario un indirizzo di destinazione.
WSAEFAULT
I parametri lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent o lpCompletionRoutine non fanno parte dello spazio indirizzi utente o il parametro lpTo è troppo piccolo.
WSAEHOSTUNREACH
Tentativo di operazione del socket verso un host non raggiungibile.
WSAEINPROGRESS
È in corso una chiamata di Windows Sockets 1.1 bloccante oppure il provider di servizi sta ancora elaborando una funzione di callback.
WSAEINTR
Una chiamata di Windows Socket 1.1 bloccata è stata annullata tramite WSACancelBlockingCall.
WSAEINVAL
Il socket non è stato associato con binding o il socket non viene creato con il flag sovrapposto.
WSAEMSGSIZE
Il socket è orientato ai messaggi e il messaggio è maggiore del massimo supportato dal trasporto sottostante.
WSAENETDOWN
Il sottosistema di rete non è riuscito.
WSAENETRESET
Per un socket di datagramma, questo errore indica che la durata (TTL) è scaduta.
WSAENETUNREACH
Impossibile raggiungere la rete da questo host in questo momento.
WSAENOBUFS
Il provider Windows Sockets segnala un deadlock del buffer.
WSAENOTCONN
Il socket non è connesso (solo socket orientati alla connessione).
WSAENOTSOCK
Il descrittore non è un socket.
WSAESHUTDOWN
Il socket è stato arrestato; non è possibile WSASendTo in un socket dopo che è stato richiamato l'arresto con come impostare su SD_SEND o SD_BOTH.
WSAEWOULDBLOCK
Windows NT:

Socket sovrapposti: sono presenti troppe richieste di I/O sovrapposte in sospeso. Socket non sovrapposti: il socket è contrassegnato come non bloccante e l'operazione di invio non può essere completata immediatamente.

WSANOTINITIALISED
Prima di usare questa funzione, è necessario che venga eseguita una chiamata WSAStartup riuscita.
WSA_IO_PENDING
Un'operazione sovrapposta è stata avviata correttamente e il completamento verrà indicato in un secondo momento.
WSA_OPERATION_ABORTED
L'operazione sovrapposta è stata annullata a causa della chiusura del socket o dell'esecuzione del comando SIO_FLUSH in WSAIoctl.

Commenti

La funzione WSASendTo offre funzionalità avanzate sulla funzione sendto standard in due aree importanti:

  • Può essere usato in combinazione con socket sovrapposti per eseguire operazioni di invio sovrapposte.
  • Consente di specificare più buffer di invio, rendendoli applicabili al tipo di I/O a dispersione/raccolta.
La funzione WSASendTo viene in genere usata in un socket senza connessione specificato da s per inviare un datagram contenuto in uno o più buffer a un socket peer specifico identificato dal parametro lpTo . Anche se il socket senza connessione è stato precedentemente connesso tramite la funzione connect a un indirizzo specifico, lpTo esegue l'override dell'indirizzo di destinazione solo per quel datagramma specifico. In un socket orientato alla connessione i parametri lpTo e iToLen vengono ignorati; in questo caso, WSASendTo equivale a WSASend.

Per i socket sovrapposti (creati usando WSASocket con flag WSA_FLAG_OVERLAPPED) l'invio dei dati usa operazioni di I/O sovrapposte, a meno che sia lpOverlapped che lpCompletionRoutine siano NULL nel qual caso il socket viene considerato come un socket non sovrapposto. Si verificherà un'indicazione di completamento (richiamando la routine di completamento o l'impostazione di un oggetto evento) quando i buffer sono stati utilizzati dal trasporto. Se l'operazione non viene completata immediatamente, lo stato di completamento finale viene recuperato tramite la routine di completamento o WSAGetOverlappedResult.

Nota Se viene aperto un socket, viene effettuata una chiamata setsockopt e viene eseguita una chiamata sendto , Windows Sockets esegue una chiamata di funzione di associazione implicita.
 
Se sia lpOverlapped che lpCompletionRoutine sono NULL, il socket in questa funzione verrà considerato come un socket non sovrapposto.

Per i socket non sovrapposti, gli ultimi due parametri (lpOverlapped, lpCompletionRoutine) vengono ignorati e WSASendTo adotta la stessa semantica di blocco dell'invio. I dati sono copiati dai buffer nel buffer di trasporto. Se il socket non blocca e orientato al flusso e non è disponibile spazio sufficiente nel buffer del trasporto, WSASendTo restituisce solo parte dei buffer dell'applicazione che sono stati utilizzati. Data la stessa situazione del buffer e un socket di blocco, WSASendTo verrà bloccato fino a quando non viene utilizzato tutto il contenuto del buffer dell'applicazione.

Se questa funzione viene completata in modo sovrapposto, è responsabilità del provider di servizi Winsock acquisire le strutture WSABUF prima di restituire da questa chiamata. Ciò consente alle applicazioni di compilare matrici WSABUF basate su stack a cui punta il parametro lpBuffers .

Per i socket orientati ai messaggi, è necessario prestare attenzione a non superare le dimensioni massime del messaggio del trasporto sottostante, che può essere ottenuto ottenendo il valore dell'opzione socket SO_MAX_MSG_SIZE. Se i dati sono troppo lunghi per passare atomicamente tramite il protocollo sottostante, viene restituito l'errore WSAEMSGSIZE e non vengono trasmessi dati.

Se il socket non è associato, i valori univoci vengono assegnati all'associazione locale dal sistema e il socket viene quindi contrassegnato come associato.

Se il socket è connesso, la funzione getsockname può essere usata per determinare l'indirizzo IP locale e la porta associati al socket.

Se il socket non è connesso,
La funzione getsockname può essere usata per determinare il numero di porta locale associato al socket, ma l'indirizzo IP restituito è impostato sull'indirizzo con caratteri jolly per il protocollo specificato( ad esempio, INADDR_ANY o "0.0.0.0" per IPv4 e IN6ADDR_ANY_INIT o "::" per IPv6).

Il completamento riuscito di un WSASendTo non indica che i dati sono stati recapitati correttamente.

Il parametro dwFlags può essere usato per influenzare il comportamento della chiamata alla funzione oltre le opzioni specificate per il socket associato. Vale a dire, la semantica di questa funzione è determinata dalle opzioni socket e dal parametro dwFlags . Quest'ultimo viene costruito usando l'operatore OR bit per bit con uno qualsiasi dei valori elencati nella tabella seguente.

Valore Significato
MSG_DONTROUTE Specifica che i dati non devono essere soggetti al routing. Un provider di servizi Windows Socket può scegliere di ignorare questo flag.
MSG_OOB Inviare dati OOB (socket in stile flusso, ad esempio SOCK_STREAM solo).
MSG_PARTIAL Specifica che lpBuffers contiene solo un messaggio parziale. Tenere presente che il codice di errore WSAEOPNOTSUPP verrà restituito dai trasporti che non supportano le trasmissioni di messaggi parziali.
 
Nota Quando si emette una chiamata Winsock di blocco, ad esempio WSASendTo con il parametro lpOverlapped impostato su NULL, Winsock potrebbe dover attendere un evento di rete prima che la chiamata possa completare. Winsock esegue un'attesa avvisabile in questa situazione, che può essere interrotta da una chiamata di routine asincrona pianificata nello stesso thread. L'emissione di un'altra chiamata winsock bloccata all'interno di un APC che ha interrotto una chiamata winsock in corso sullo stesso thread comporterà un comportamento non definito e non deve mai essere tentato dai client Winsock.
 

I/O del socket sovrapposto

Se un'operazione sovrapposta viene completata immediatamente, WSASendTo restituisce un valore pari a zero e il parametro lpNumberOfBytesSent viene aggiornato con il numero di byte inviati. Se l'operazione sovrapposta viene avviata correttamente e verrà completata in un secondo momento, WSASendTo restituisce SOCKET_ERROR e indica il codice di errore WSA_IO_PENDING. In questo caso, lpNumberOfBytesSent non viene aggiornato. Quando l'operazione sovrapposta completa la quantità di dati trasferiti viene indicato tramite il parametro cbTransferred nella routine di completamento (se specificato) o tramite il parametro lpcbTransfer in WSAGetOverlappedResult.
Nota Tutti gli I/O avviati da un determinato thread vengono annullati quando il thread viene chiuso. Per i socket sovrapposti, le operazioni asincrone in sospeso possono non riuscire se il thread viene chiuso prima del completamento delle operazioni. Per altre informazioni, vedere ExitThread .
 
La funzione WSASendTo con I/O sovrapposta può essere chiamata dall'interno della routine di completamento di una funzione WSARecv precedente, WSARecvFrom, WSASend o WSASendTo. In questo modo, le trasmissioni di dati sensibili al tempo vengono eseguite interamente all'interno di un contesto preemptive.

Il parametro lpOverlapped deve essere valido per la durata dell'operazione sovrapposta. Se più operazioni di I/O sono in sospeso contemporaneamente, ognuna deve fare riferimento a una struttura WSAOVERLAPPED separata.

Se il parametro lpCompletionRoutine è NULL, il parametro hEvent di lpOverlapped viene segnalato quando l'operazione sovrapposta viene completata se contiene un handle di oggetto evento valido. Un'applicazione può usare WSAWaitForMultipleEvents o WSAGetOverlappedResult per attendere o eseguire il polling nell'oggetto evento.

Se lpCompletionRoutine non è NULL, il parametro hEvent viene ignorato e può essere usato dall'applicazione per passare le informazioni di contesto alla routine di completamento. Un chiamante che passa una richiesta non NULLlpCompletionRoutine e versioni successive chiama WSAGetOverlappedResult per la stessa richiesta di I/O sovrapposta potrebbe non impostare il parametro fWait per tale chiamata di WSAGetOverlappedResult su TRUE. In questo caso l'utilizzo del parametro hEvent non è definito e il tentativo di attendere il parametro hEvent genera risultati imprevedibili.

La routine di completamento segue le stesse regole previste per le routine di completamento di I/O file di Windows. La routine di completamento non verrà richiamata finché il thread non si trova in uno stato di attesa avvisabile, ad esempio quando viene richiamata la funzione WSAWaitForMultipleEvents con il parametro fAlertable impostato su TRUE .

I provider di trasporto consentono a un'applicazione di richiamare operazioni di invio e ricezione dall'interno del contesto della routine di completamento di I/O socket e garantire che, per un determinato socket, le routine di completamento di I/O non verranno annidate. In questo modo, le trasmissioni di dati sensibili al tempo vengono eseguite interamente all'interno di un contesto preemptive.

Il prototipo della routine di completamento è il seguente.


void CALLBACK CompletionROUTINE(
  IN DWORD dwError,
  IN DWORD cbTransferred,
  IN LPWSAOVERLAPPED lpOverlapped,
  IN DWORD dwFlags
);

La funzione CompletionRoutine è un segnaposto per un nome di funzione definito dall'applicazione o dalla libreria. Il parametro dwError specifica lo stato di completamento dell'operazione sovrapposta, come indicato da lpOverlapped. Il parametro cbTransferred specifica il numero di byte inviati. Attualmente non sono presenti valori di flag definiti e dwFlags saranno zero. Questa funzione non restituisce un valore.

La restituzione da questa funzione consente la chiamata di un'altra routine di completamento in sospeso per questo socket. Tutte le routine di completamento in attesa vengono chiamate prima che l'attesa del thread avvisabile sia soddisfatta con un codice restituito di WSA_IO_COMPLETION. Le routine di completamento possono essere chiamate in qualsiasi ordine, non necessariamente nello stesso ordine in cui vengono completate le operazioni sovrapposte. Tuttavia, i buffer pubblicati devono essere inviati nello stesso ordine specificato.

Codice di esempio

Nell'esempio seguente viene illustrato l'uso della funzione WSASendTo usando un oggetto evento.
#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: questa funzione è supportata per le app Windows Phone Store in Windows Phone 8 e versioni successive.

Windows 8.1 e Windows Server 2012 R2: questa funzione è supportata per le app di Windows Store in Windows 8.1, Windows Server 2012 R2 e versioni successive.

Requisiti

Requisito Valore
Client minimo supportato Windows 8.1, Windows Vista [app desktop | App UWP]
Server minimo supportato Windows Server 2003 [app desktop | App UWP]
Piattaforma di destinazione Windows
Intestazione winsock2.h
Libreria Ws2_32.lib
DLL Ws2_32.dll

Vedi anche

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSASocket

WSAWaitForMultipleEvents

Funzioni Winsock

Informazioni di riferimento su Winsock