Condividi tramite


Funzione WSARecvFrom (winsock2.h)

La funzione WSARecvFrom riceve un datagram e archivia l'indirizzo di origine.

Sintassi

int WSAAPI WSARecvFrom(
  [in]      SOCKET                             s,
  [in, out] LPWSABUF                           lpBuffers,
  [in]      DWORD                              dwBufferCount,
  [out]     LPDWORD                            lpNumberOfBytesRecvd,
  [in, out] LPDWORD                            lpFlags,
  [out]     sockaddr                           *lpFrom,
  [in, out] LPINT                              lpFromlen,
  [in]      LPWSAOVERLAPPED                    lpOverlapped,
  [in]      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

Parametri

[in] s

Descrittore che identifica un socket.

[in, out] lpBuffers

Puntatore a una matrice di strutture WSABUF . Ogni struttura WSABUF contiene un puntatore a un buffer e la lunghezza del buffer.

[in] dwBufferCount

Numero di strutture WSABUF nella matrice lpBuffers .

[out] lpNumberOfBytesRecvd

Puntatore al numero di byte ricevuti da questa chiamata se l'operazione WSARecvFrom 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, out] lpFlags

Puntatore ai flag usati per modificare il comportamento della chiamata di funzione WSARecvFrom . Vedere la sezione Note riportata di seguito.

[out] lpFrom

Puntatore facoltativo a un buffer che conterrà l'indirizzo di origine al completamento dell'operazione sovrapposta.

[in, out] lpFromlen

Puntatore alle dimensioni, in byte, del buffer "from" richiesto solo se lpFrom è specificato.

[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 WSARecvFrom è stata completata (ignorata per i socket non sovrapposti).

Valore restituito

Se non si verifica alcun errore e l'operazione di ricezione è stata completata immediatamente, WSARecvFrom restituisce zero. In questo caso, la routine di completamento sarà già stata pianificata per essere chiamata una volta che il thread chiamante si trova nello stato avvisabile. In caso contrario, viene restituito un valore di SOCKET_ERROR e un codice di errore specifico può essere recuperato 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
WSAECONNRESET
Circuito virtuale reimpostato dal lato remoto durante l'esecuzione di una chiusura definitiva o anomala. L'applicazione deve chiudere il socket che non è più utilizzabile. Per un socket di datagrammi UPD, questo errore indica che un'operazione di invio precedente ha generato un messaggio ICMP "Port Unreachable".
WSAEFAULT
Il parametro lpBuffers, lpFlags, lpFrom, lpNumberOfBytesRecvd, lpFromlen, lpOverlapped o lpCompletionRoutine non è totalmente contenuto in una parte valida dello spazio indirizzi utente: il buffer lpFrom era troppo piccolo per ospitare l'indirizzo peer.
WSAEINPROGRESS
Una chiamata windows Sockets 1.1 bloccata è in corso 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 (ad esempio con binding).
WSAEMSGSIZE
Il messaggio era troppo grande per il buffer specificato e (solo per protocolli non affidabili) qualsiasi parte finale del messaggio che non è stata adattata al buffer.
WSAENETDOWN
Il sottosistema di rete non è riuscito.
WSAENETRESET
Per un socket di datagramma, questo errore indica che la durata (TTL) è scaduta.
WSAENOTCONN
Il socket non è connesso (solo socket orientati alla connessione).
WSAEWOULDBLOCK
Windows NT:

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

WSANOTINITIALISED
Prima di usare questa funzione, è necessario eseguire 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.

Commenti

La funzione WSARecvFrom offre funzionalità oltre e superiori alla funzione recvfrom standard in tre aree importanti:

  • Può essere usato in combinazione con socket sovrapposti per eseguire operazioni di ricezione sovrapposte.
  • Consente di specificare più buffer di ricezione che lo rendono applicabile al tipo di I/O a dispersione/raccolta.
  • Il parametro lpFlags è sia un input che un parametro di output, consentendo alle applicazioni di percepire lo stato di output del flag MSG_PARTIAL . Tenere presente che il bit MSG_PARTIAL flag non è supportato da tutti i protocolli.
La funzione WSARecvFrom viene usata principalmente in un socket senza connessione specificato da s. L'indirizzo locale del socket deve essere noto. Per le applicazioni server, questa operazione viene in genere eseguita in modo esplicito tramite binding. L'associazione esplicita è sconsigliata per le applicazioni client. Per le applicazioni client che usano questa funzione il socket può diventare associato in modo implicito a un indirizzo locale tramite sendto, WSASendTo o WSAJoinLeaf.

Per i socket sovrapposti, questa funzione viene usata per pubblicare uno o più buffer in cui verranno inseriti i dati in ingresso in quanto diventa disponibile in un socket (possibilmente connesso), dopo il quale si verifica l'indicazione di completamento specificata dall'applicazione (chiamata della routine di completamento o dell'impostazione di un oggetto evento). Se l'operazione non viene completata immediatamente, lo stato di completamento finale viene recuperato tramite la routine di completamento o WSAGetOverlappedResult. Inoltre, i valori indicati da lpFrom e lpFromlen non vengono aggiornati fino a quando il completamento non è indicato. Le applicazioni non devono usare o disturbare questi valori fino a quando non sono stati aggiornati; pertanto l'applicazione non deve usare le variabili automatiche (ovvero basate su stack) per questi parametri.

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 .
 
Se sia lpOverlapped che lpCompletionRoutine sono NULL, il socket in questa funzione verrà considerato come socket non sovrapposto.

Per i socket non sovrapposti, la semantica di blocco è identica a quella della funzione WSARecv standard e i parametri lpOverlapped e lpCompletionRoutine vengono ignorati. Tutti i dati già ricevuti e memorizzati nel buffer dal trasporto verranno copiati nei buffer utente. Per il caso di un socket di blocco senza dati attualmente ricevuti e memorizzati nel buffer dal trasporto, la chiamata bloccherà fino alla ricezione dei dati.

I buffer vengono compilati nell'ordine in cui vengono visualizzati nella matrice indicata da lpBuffers e i buffer vengono compressi in modo che non vengano creati fori.

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 creare matrici WSABUF basate su stack puntate dal parametro lpBuffers .

Per i tipi di socket senza connessione, l'indirizzo da cui provengono i dati viene copiato nel buffer indicato da lpFrom. Il valore indicato da lpFromlen viene inizializzato per le dimensioni di questo buffer e viene modificato al completamento per indicare la dimensione effettiva dell'indirizzo archiviato. Come indicato in precedenza per i socket sovrapposti, i parametri lpFrom e lpFromlen non vengono aggiornati fino al completamento dell'I/O sovrapposto. La memoria puntata da questi parametri deve pertanto rimanere disponibile per il provider di servizi e non può essere allocata nel frame dello stack di applicazioni. I parametri lpFrom e lpFromlen vengono ignorati per i socket orientati alla connessione.

Per i socket in stile di flusso di byte (ad esempio, digitare SOCK_STREAM), i dati in ingresso vengono inseriti nei buffer fino a quando:

  • I buffer vengono riempiti.
  • La connessione è chiusa.
  • I dati memorizzati nel buffer interno vengono esauriti.
Indipendentemente dal fatto che i dati in ingresso riempiano tutti i buffer, l'indicazione di completamento si verifica per i socket sovrapposti. Per i socket orientati ai messaggi, un messaggio in ingresso viene inserito nei buffer fino alla dimensione totale dei buffer e l'indicazione di completamento si verifica per i socket sovrapposti. Se il messaggio è maggiore dei buffer, i buffer vengono riempiti con la prima parte del messaggio. Se la funzionalità MSG_PARTIAL è supportata dal provider di servizi sottostante, il flag di MSG_PARTIAL viene impostato in lpFlags e le operazioni di ricezione successive recuperano il resto del messaggio. Se MSG_PARTIAL non è supportato, ma il protocollo è affidabile, WSARecvFrom genera l'errore WSAEMSGSIZE e un'operazione di ricezione successiva con un buffer più grande può essere usato per recuperare l'intero messaggio. In caso contrario, il protocollo non è affidabile e non supporta MSG_PARTIAL, i dati in eccesso vengono persi e WSARecvFrom genera l'errore WSAEMSGSIZE.

Il parametro lpFlags 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 lpFlags . Quest'ultimo viene costruito usando l'operatore OR bit per bit con uno qualsiasi dei valori elencati nella tabella seguente.

Valore Significato
MSG_PEEK Visualizza in anteprima i dati in ingresso. I dati vengono copiati nel buffer, ma non vengono rimossi dalla coda di input. Questo flag è valido solo per i socket non sovrapposti.
MSG_OOB Elabora i dati OOB.
MSG_PARTIAL Questo flag è solo per socket orientati ai messaggi. Nell'output, questo flag indica che i dati sono una parte del messaggio trasmesso dal mittente. Le parti rimanenti del messaggio verranno trasmesse nelle operazioni di ricezione successive. Un'operazione di ricezione successiva con flag MSG_PARTIAL deselezionata indica la fine del messaggio del mittente.

Come parametro di input, questo flag indica che l'operazione di ricezione deve essere completata anche se è stata ricevuta solo parte di un messaggio dal provider di servizi.

 

Per i socket orientati ai messaggi, il bit di MSG_PARTIAL viene impostato nel parametro lpFlags se viene ricevuto un messaggio parziale. Se viene ricevuto un messaggio completo, MSG_PARTIAL viene cancellato in lpFlags. Nel caso di completamento ritardato, il valore puntato da lpFlags non viene aggiornato. Quando il completamento è stato indicato che l'applicazione deve chiamare WSAGetOverlappedResult ed esaminare i flag a cui punta il parametro lpdwFlags .

Nota Quando si emette una chiamata Winsock di blocco, ad esempio WSARecvFrom con il parametro lpOverlapped impostato su NULL, Winsock potrebbe dover attendere il completamento di un evento di rete. 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, WSARecvFrom restituisce un valore pari a zero e il parametro lpNumberOfBytesRecvd viene aggiornato con il numero di byte ricevuti e i bit di flag puntati dal parametro lpFlags vengono aggiornati anche. Se l'operazione sovrapposta viene avviata correttamente e verrà completata in un secondo momento, WSARecvFrom restituisce SOCKET_ERROR e indica il codice di errore WSA_IO_PENDING. In questo caso, lpNumberOfBytesRecvd e lpFlags 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. I valori del flag vengono ottenuti tramite il parametro dwFlags della routine di completamento oppure esaminando il parametro lpdwFlags di WSAGetOverlappedResult.

La funzione WSARecvFrom può essere chiamata dall'interno della routine di completamento di una funzione WSARecv, WSARecvFrom, WSASend o WSASendTo. 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 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 .

Se viene usata una porta di completamento I/O e il parametro lpCompletionRoutine e il parametro hEvent sono NULL, il risultato dell'operazione è pianificato sulla porta di completamento di I/O. Ciò avviene per tutte le operazioni riuscite, indipendentemente dal fatto che le operazioni vengano completate immediatamente o meno.

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

CompletamentoRoutine è un segnaposto per un nome di funzione definito dall'applicazione o dalla libreria. DwError specifica lo stato di completamento per l'operazione sovrapposta, come indicato da lpOverlapped. CbTransferred specifica il numero di byte ricevuti. Il parametro dwFlags contiene informazioni che sarebbero state visualizzate in lpFlags se l'operazione di ricezione era stata completata immediatamente. 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. Quando si usa WSAWaitForMultipleEvents, tutte le routine di completamento in attesa vengono chiamate prima che l'attesa del thread avvisabile venga soddisfatta con un codice restituito di WSA_IO_COMPLETION. Le routine di completamento possono essere chiamate in qualsiasi ordine, non necessariamente nello stesso ordine le operazioni sovrapposte vengono completate. Tuttavia, i buffer pubblicati sono garantiti di essere compilati nello stesso ordine specificato.

Codice di esempio

Nell'esempio seguente viene illustrato l'uso della funzione WSARecvFrom .
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

int __cdecl main()
{

    WSADATA wsaData;
    WSABUF DataBuf;
    WSAOVERLAPPED Overlapped;

    SOCKET RecvSocket = INVALID_SOCKET;
    struct sockaddr_in RecvAddr;
    struct sockaddr_in SenderAddr;

    int SenderAddrSize = sizeof (SenderAddr);
    u_short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;
    DWORD BytesRecv = 0;
    DWORD Flags = 0;

    int err = 0;
    int rc;
    int retval = 0;
    
    //-----------------------------------------------
    // Initialize Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != 0) {
        /* Could not find a usable Winsock DLL */
        wprintf(L"WSAStartup failed with error: %ld\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 == NULL) {
        wprintf(L"WSACreateEvent failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    RecvSocket = WSASocket(AF_INET,
                           SOCK_DGRAM,
                           IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

    if (RecvSocket == INVALID_SOCKET) {
        /* Could not open a socket */
        wprintf(L"WSASocket failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    rc = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (rc != 0) {
        /* Bind to the socket failed */
        wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        closesocket(RecvSocket);
        WSACleanup();
        return 1;
    }

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    DataBuf.len = BufLen;
    DataBuf.buf = RecvBuf;
    wprintf(L"Listening for incoming datagrams on port=%d\n", Port);
    rc = WSARecvFrom(RecvSocket,
                      &DataBuf,
                      1,
                      &BytesRecv,
                      &Flags,
                      (SOCKADDR *) & SenderAddr,
                      &SenderAddrSize, &Overlapped, NULL);

    if (rc != 0) {
        err = WSAGetLastError();
        if (err != WSA_IO_PENDING) {
            wprintf(L"WSARecvFrom failed with error: %ld\n", err);
            WSACloseEvent(Overlapped.hEvent);
            closesocket(RecvSocket);
            WSACleanup();
            return 1;
        }
        else {
            rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
            if (rc == WSA_WAIT_FAILED) {
                wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }

            rc = WSAGetOverlappedResult(RecvSocket, &Overlapped, &BytesRecv,
                                FALSE, &Flags);
            if (rc == FALSE) {
                wprintf(L"WSArecvFrom failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }
            else
                wprintf(L"Number of received bytes = %d\n", BytesRecv);
                
            wprintf(L"Finished receiving. Closing socket.\n");
        }
        
    }
    //---------------------------------------------
    // When the application is finished receiving, close the socket.

    WSACloseEvent(Overlapped.hEvent);
    closesocket(RecvSocket);
    wprintf(L"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

   
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

WSABUF

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASend

WSASendTo

WSASocket

WSAWaitForMultipleEvents

Funzioni Winsock

Informazioni di riferimento su Winsock

Sendto