WSARecvFrom 函式 (winsock2.h)
WSARecvFrom函式會接收資料包並儲存來源位址。
語法
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
);
參數
[in] s
識別通訊端的描述項。
[in, out] lpBuffers
WSABUF結構的陣列指標。 每個 WSABUF 結構都包含緩衝區的指標和緩衝區的長度。
[in] dwBufferCount
lpBuffers陣列中的WSABUF結構數目。
[out] lpNumberOfBytesRecvd
如果 WSARecvFrom 作業立即完成,這個呼叫所接收位元組數目的指標。
如果lpOverlapped參數不是Null,則為此參數使用Null,以避免可能發生錯誤的結果。 只有當lpOverlapped參數不是 Null 時,此參數才能是Null。
[in, out] lpFlags
用來修改 WSARecvFrom 函式呼叫行為的旗標指標。 請參閱下面的<備註>。
[out] lpFrom
緩衝區的選擇性指標,會在重迭作業完成時保留來源位址。
[in, out] lpFromlen
只有在指定 lpFrom 時,才需要 「from」 緩衝區大小的指標,以位元組為單位。
[in] lpOverlapped
未重迭通訊端) 忽略 WSAOVERLAPPED 結構的指標 (。
[in] lpCompletionRoutine
類型:_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
當 WSARecvFrom 作業完成時呼叫的完成常式指標, (忽略未重迭的通訊端) 。
傳回值
如果沒有發生錯誤,而且接收作業已立即完成, WSARecvFrom 會傳回零。 在此情況下,完成常式已排程在呼叫執行緒處於可警示狀態之後呼叫。 否則,會傳回 SOCKET_ERROR 的值,並呼叫 WSAGetLastError來擷取特定的錯誤碼。 錯誤碼 WSA_IO_PENDING 指出重迭的作業已成功起始,且稍後會指出完成。 任何其他錯誤碼都表示重迭的作業未成功起始,而且不會發生任何完成指示。
錯誤碼 | 意義 |
---|---|
執行硬式或失敗關閉的遠端部分已重設此虛擬電路。 此通訊端無法再使用,應用程式應予以關閉。 針對 UPD 資料包通訊端,此錯誤會指出先前的傳送作業導致 ICMP「無法連線」訊息。 | |
lpBuffers、lpFlags、lpFrom、lpNumberOfBytesRecvd、lpFromlen、lpOverlapped或lpCompletionRoutine參數並未完全包含在使用者位址空間的有效部分中:lpFrom緩衝區太小而無法容納對等位址。 | |
封鎖的 Windows Sockets 1.1 呼叫正在進行中,或服務提供者仍在處理回呼函式。 | |
封鎖的 Windows Socket 1.1 呼叫已透過 WSACancelBlockingCall取消。 | |
通訊端 尚未系結 (系結,例如) 。 | |
訊息對於指定的緩衝區而言太大,而且 (不可靠的通訊協定,只會) 任何不符合緩衝區之訊息的尾端部分都已被捨棄。 | |
網路子系統失敗。 | |
如果是資料包通訊端,此錯誤表示已超過存留時間。 | |
通訊端未 (連線導向通訊端) 。 | |
Windows NT:
重迭的通訊端:有太多未處理的重迭 I/O 要求。 未重迭的通訊端:通訊端標示為非封鎖,而且無法立即完成接收作業。 |
|
使用這個函式之前,必須先進行成功的 WSAStartup 呼叫。 | |
已成功起始重迭的作業,稍後將會指出完成。 | |
因為通訊端關閉,所以已取消重迭的作業。 |
備註
WSARecvFrom函式提供三個重要領域的標準recvfrom函式以上功能:
- 它可以與重迭的通訊端搭配使用,以執行重迭的接收作業。
- 它允許指定多個接收緩衝區,使其適用于 I/O 的散佈/收集類型。
- lpFlags參數同時是輸入和輸出參數,可讓應用程式感知MSG_PARTIAL旗標位的輸出狀態。 請注意,所有通訊協定都不支援 MSG_PARTIAL 旗標位。
對於重迭的通訊端,此函式會用來張貼一或多個緩衝區,而傳入資料會在 (可能連線的) 通訊端上使用,之後應用程式指定的完成指示 (叫用事件物件) 。 如果作業未立即完成,則會透過完成常式或 WSAGetOverlappedResult擷取最終完成狀態。 此外, lpFrom 和 lpFromlen 所表示的值在完成本身表示之前不會更新。 應用程式在更新這些值之前,不得使用或干擾這些值;因此,應用程式不得使用自動 (,也就是這些參數的堆疊式) 變數。
對於未重迭的通訊端,封鎖語意與標準 WSARecv 函式的語意相同,並忽略 lpOverlapped 和 lpCompletionRoutine 參數。 傳輸已接收和緩衝處理的任何資料,都會複製到使用者緩衝區。 對於目前未接收和緩衝傳輸之資料的封鎖通訊端案例,呼叫會封鎖直到收到資料為止。
緩衝區會依它們出現在 lpBuffers所指示的陣列中的順序填入,而緩衝區會封裝在一起,因此不會建立任何漏洞。
如果以重迭的方式完成此函式,Winsock 服務提供者必須負責擷取 WSABUF 結構,然後再從這個呼叫傳回。 這可讓應用程式建置由 lpBuffers參數指向的堆疊型WSABUF陣列。
針對無連線通訊端類型,資料的來源位址會複製到 lpFrom所指出的緩衝區。 lpFromlen所指向的值會初始化為此緩衝區的大小,並在完成時修改,以指出儲存在該處的實際位址大小。 如先前針對重迭的通訊端所述, lpFrom 和 lpFromlen 參數在重迭 I/O 完成後才會更新。 因此,這些參數所指向的記憶體必須可供服務提供者使用,而且無法在應用程式堆疊框架上配置。 連接導向通訊端會忽略 lpFrom 和 lpFromlen 參數。
例如,針對位元組資料流程樣式通訊端 (輸入 SOCK_STREAM) ,傳入的資料會放在緩衝區中,直到:
- 緩衝區已填滿。
- 連接關閉。
- 內部緩衝的資料已耗盡。
lpFlags參數可用來影響函式調用的行為,超出為相關聯通訊端指定的選項。 也就是說,此函式的語意是由通訊端選項和 lpFlags 參數所決定。 後者是使用位 OR 運算子搭配下表所列的任何任何值來建構。
值 | 意義 |
---|---|
MSG_PEEK | 預覽傳入的資料。 資料會複製到緩衝區,但不會從輸入佇列中移除。 此旗標僅適用于未重迭的通訊端。 |
MSG_OOB | 處理 OOB 資料。 |
MSG_PARTIAL | 此旗標僅適用于訊息導向通訊端。 在輸出時,此旗標表示資料是傳送者所傳輸訊息的一部分。 後續接收作業中將會傳輸訊息的其餘部分。 已清除 MSG_PARTIAL 旗標的後續接收作業表示寄件者訊息的結尾。
作為輸入參數,這個旗標表示即使服務提供者只收到部分訊息,接收作業也應該完成。 |
對於訊息導向通訊端,如果收到部分訊息, MSG_PARTIAL 位就會在 lpFlags 參數中設定。 如果收到完整的訊息, MSG_PARTIAL 會在 lpFlags中清除。 在延遲完成的情況下, 不會更新 lpFlags 指向的值。 當指示完成時,應用程式應該呼叫 WSAGetOverlappedResult ,並檢查 lpdwFlags 參數所指向的旗標。
重迭的通訊端 I/O
如果重迭的作業立即完成, WSARecvFrom 會傳回值為零,而且 lpNumberOfBytesRecvd 參數會更新接收的位元組數目,而且 也會更新 lpFlags 參數所指向的旗標位。 如果已成功起始重迭的作業,且稍後會完成, WSARecvFrom 會 傳回SOCKET_ERROR ,並指出錯誤碼 WSA_IO_PENDING。 在此情況下, lpNumberOfBytesRecvd 和 lpFlags 不會更新。 當重迭的作業完成時,傳送的資料量會透過完成常式中的cbTransferred參數來表示,如果指定) ,或透過WSAGetOverlappedResult中的lcbTransfer參數,則表示 (。 旗標值是透過完成常式的dwFlags參數取得,或藉由檢查WSAGetOverlappedResult的lpdwFlags參數來取得。您可以從先前WSARecv、WSARecvFrom、WSASend或WSASendTo函式的完成常式內呼叫WSARecvFrom函式。 針對指定的通訊端,I/O 完成常式不會巢狀化。 這可讓時間敏感的資料傳輸完全發生在先占式內容中。
lpOverlapped參數在重迭作業期間必須有效。 如果同時處理多個 I/O 作業,每個作業都必須參考個別 的 WSAOVERLAPPED 結構。
如果lpCompletionRoutine參數為Null,當重迭的作業包含有效的事件物件控制碼時,lpOverlapped的hEvent參數會發出訊號。 應用程式可以使用 WSAWaitForMultipleEvents 或 WSAGetOverlappedResult 來等候或輪詢事件物件。
如果 lpCompletionRoutine 不是 Null, 則會忽略 hEvent 參數,而且可由應用程式用來將內容資訊傳遞至完成常式。 將非NulllpCompletionRoutine和更新版本針對相同重迭 I/O 要求的WSAGetOverlappedResult 呼叫 WSAGetOverlappedResult的呼叫端,可能不會將該WSAGetOverlappedResult叫用的fWait參數設定為TRUE。 在此情況下, 未定義 hEvent 參數的使用方式,而嘗試等候 hEvent 參數會產生無法預期的結果。
完成常式遵循與 Windows 檔案 I/O 完成常式規定相同的規則。 除非執行緒處於可警示的等候狀態,例如在叫用fAlertable參數設為TRUE的函式WSAWaitForMultipleEvents時,才會叫用完成常式。
如果使用 IO 完成埠,且 lpCompletionRoutine 參數和 hEvent 參數為 Null,作業的結果會排程在 IO 完成埠上。 不論作業是否立即完成,所有成功的作業都會發生這種情況。
傳輸提供者可讓應用程式從通訊端 I/O 完成常式的內容中叫用傳送和接收作業,並保證針對指定的通訊端,I/O 完成常式不會巢狀化。 這可讓時間敏感的資料傳輸完全發生在先占式內容中。
完成常式的原型如下所示。
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
CompletionRoutine是應用程式定義或程式庫定義函數名稱的預留位置。 dwError會指定重迭作業的完成狀態,如lpOverlapped所指出。 cbTransferred會指定收到的位元組數目。 dwFlags參數包含當接收作業立即完成時,會出現在lpFlags中的資訊。 此函式不會傳回值。
從此函式傳回允許叫用此通訊端的另一個擱置完成常式。 使用 WSAWaitForMultipleEvents時,所有等候完成常式都會在可警示執行緒等候符合WSA_IO_COMPLETION的傳回碼之前呼叫。 完成常式可以依任何順序呼叫,不一定以相同順序呼叫重迭作業完成。 不過,所張貼的緩衝區保證會以指定的相同順序填入。
範例程式碼
下列範例示範 如何使用 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: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 |
標頭 | winsock2.h |
程式庫 | Ws2_32.lib |
Dll | Ws2_32.dll |