WSARecvFrom

WSARecvFrom 함수는 데이터그램을 수신하고, 데이터를 보내는 곳(source) 의 어드레스를 저장(store)하는 함수입니다.

int WSARecvFrom (
        SOCKET   
s,
        LPWSABUF   
lpBuffers,
        DWORD   
dwBufferCount,
        LPDWORD   
lpNumberOfBytesRecvd,
        LPDWORD  
 lpFlags,
        struct sockaddr FAR *  
 lpFrom,
        LPINT  
 lpFromlen,
        LPWSAOVERLAPPED   
lpOverlapped,
        LPWSAOVERLAPPED_COMPLETION_ROUTINE   
lpCompletionROUTINE
);

 

Parameters

s
[입력] 작업 대상 소켓 기술자

lpBuffers
[입력/출력] WSABUF 구조체의 배열 포인터로써, 각각의 WSABUF 구조체는 버퍼의 포인터와 이 버퍼의 길이를 가지게 됩니다.

dwBufferCount
[입력] lpBuffers 배열에 있는
WSABUF 엘리먼트의 개수

lpNumberOfBytesRecvd
[출력] 함수의 호출 후에 수신연산이 바로 종료될 경우, 수신된 바이트의 수치를 포인트 합니다.

lpFlags
[입력/출력] 플래그를 위한 포인터

lpFrom
[출력] 데이터를 보낸 출발지 어드레스를 포인트 하기위한
SOCKADDR 구조체의 포인터

lpFromlen
[입력/출력] lpFrom 매개변수가 지정되었을 때만 사용되는 매개변수로 lpFrom의 크기를 위한 포인터

lpOverlapped
[입력]
WSAOVERLAPPED 구조체의 포인터 (넌-오버랩 소켓에서는 무시됩니다.)

lpCompletionRoutine
[입력] 수신 연산이 완료되었을 때 호출되는 완료루틴의 포인터 (넌-오버랩 소켓에서는 무시됩니다.)

 

Remarks

WSARecvFrom 함수는 표준 recvfrom 함수와 비교할 때 아래의 3가지 면에서 볼 때 더 많은 기능을 제공합니다.

1. 오버랩 수신 연산을 수행하기 위해서 오버랩 소켓과 연동하여 사용됩니다.

2. 이 함수는 수집/분산 형태의 I/O를 가능하게 하기위하여 여러개의 수신버퍼를 사용할 수 있습니다.

3. lpFlags 매개변수는 입력용과 출력용의 매개변수로 사용되어, MSG_PARTIAL 의 상태를 출력시 감지할 수 있게 됩니다. 하지만, MSG_PARTIAL 플래그 비트는 모든 프로토콜에 대해서 지원되지 않는다는점! 꼭 명심하시기 바랍니다.

WSARecvFrom 함수는 본질적으로 매개변수 s 에 지정된 비접속 지향형 소켓(SOCK_DGRAM)에 사용됩니다. 소켓의 로컬 어드레스는 확실히 알 수 있는 것이여야 하는데요. 서버 어플리케이션에서는 확실한 로컬어드레스를 바인딩 하기위해서 bind 함수를 사용해서 호출합니다. 이러게 명시적으로 bind 함수를 호출하는 방식은 클라이언트 프로그램에서는 무용지물이 될 수 있습니다. 일반적으로 클라이언트 어플리케이션에서는 sendto, WSASendTo, 또는 WSAJoinLeaf 함수를 사용해서 묵시적으로 로컬어드레스 지정하게 됩니다.

오버랩 소켓에서, 이 함수는 소켓으로 들어오는 데이터를 버퍼링 하기위해서 한 개 또는 그 이상의 버퍼를 사용 할 수 있습니다. 이렇게 데이터를 버퍼링 한 수에 어플리케이션에서 지정된 작업완료 루틴(or 신호)는 발생 됩니다. 여기서 말하는 작업완료 루틴(or 신호)란 완료함수(completion routine)나, 이벤트 오브젝트를 말하는 겁니다. 연산이 바로 완료되지 않는다면, 마지막 완료 상태는 위에서 언급한 완료루틴(completion routine)이나, WSAGetOverlappedResult 함수를 통해 반환됩니다. 또한, lpFrom 매개변수와 lpFromlen 매개변수의 값은 작업이 완료되어 완료 신호를 받을때 까지 업데이트 되지 않습니다. 어플리케이션에서는 이 값들이 업데이트 되기 전에 이 값들을 건드리면 안 됩니다.

lpOverlappedlpCompletionRoutine 매개변수가 둘 다 NULL 일 경우, 이 함수에 사용된 소켓은 넌-오버랩 소켓으로 간주되어 처리됩니다.

넌-오버랩 소켓에서의 블록킹 처리부분은 WSARecv 함수의 그것과 같습니다. 그리고 lpOverlappedlpCompletionRoutine 매개변수는 무시됩니다. 트랜스포트(계층)에서 이미 수신되고, 버퍼링된 데이터는 함수에 지정한 버퍼로 카피됩니다. 아무런 데이터가 들어오지 않은 상태에서 이 함수를 호출하게 되면, 다른 데이터가 들어올 때 까지 함수를 블록 합니다.

lpBuffers 매개변수로 지정되는 WSABUF 매개변수의 배열은 임시공간입니다. 오버랩 방식으로 이 함수가 호출되었다면, 함수가 반환하기전에 WSABUF 구조체를 캡쳐하는 일은 서비스 프로바이더의 몫입니다. 이렇게 함으로써 어플리케이션은 스택기반(쉽게 말해서 배열이죠)으로 WSABUF 배열을 사용할 수 있는 것입니다.

비접속 지향형 소켓타입에서, 데이터를 보내는 상대방의 어드레스는 lpFrom 매개변수에 의해서 지정된 버퍼로 카피됩니다. lpFromlen 매개변수는 함수를 호출할 때 넘겨주는 lpFrom 의 크기를 지정해 주고, 이 함수의 연산이 완료 되었을 때 lpFrom 매개변수로 실제로 저장된 데이터의 크기를 포인트 하게 됩니다. 오버랩 소켓에서 lpFromlpFromlen 매개변수는 오버랩 I/O 가 완료될 때 까지 업데이트 되어서는 절대로 안 됩니다. 그러므로, 이 매개변수로 포인트된 메모리는 서비스 프로바이더에서 사요가능하도록 남겨두어야 하면, 어플리케이션 스택 프레임에 할당하지 말아야 합니다. 결국 동적할당 하라는 말이겠죠. lpFromlpFromlen 매개변수는 접속지향형 소켓에서는 무시됩니다.

SOCK_STREAM 과 같은 바이트 스트림 소켓의 경우, 들어오는 데이터는 버퍼가 가득 찰 때 까지나, 접속이 끊길 때까지, 아니면, 내부버퍼 데이터(internally beffered data)를 다 써 버릴 때 까지 지정된 버퍼에 채워지게 됩니다. 오버랩 소켓에서 들어오는 데이터가 모든 버퍼에 채워지든 채워지지 않든간에, 작업이 완료 되었다는 알림은 발생합니다. SOCK_DGRAM 과 같은 메시지 지향형 소켓의 경우, 들어오는 메시지는 지정된 버퍼의 총 크기에 이르기 까지 지정된 버퍼에 채워지게 됩니다. 그리고 오버랩 소켓에 대해서 작업 완료 알림은 발생하게 됩니다. 만약 메시지가 지정된 버퍼보다 더 크다면, 버퍼엔 들어온 메시지중 처음부터 지정된 크기만큼만이 채워지게 됩니다.

MSG_PARTIAL 부분은 서비스 프로바이더를 기반으로 지원되는 플래그입니다. MSG_PARTIAL 플래그는 lpFlags 에 설정되고, 뒤 따라오는 수신 연산은 메시지의 rest(중간부분?)를 얻어낼 것입니다. 만약 MSG_PARTIAL 이 지원되지 않지만, 프로토콜이 믿을 만한 것이라면, WSARecvFrom 함수는 WSAEMSGSIZE 에러를 발생시키고, 더 큰 버퍼를 사용여, 뒤 따라오는 수신 연산은 전체의 메시지를 얻어내는데 사용될 수 있습니다. 이와 다른 경우(MSG_PARTIAL을 지원하지 않고, 프로토콜이 신뢰성이 없는 경우)는 초과된 데이터는 잘려 버리게 됩니다. 그리고, WSARecvFrom 함수는 WSAEMSGSIZE 에러를 발생합니다.

lpFlags 매개변수는 WSARecvFrom 함수가 동작하게될 구체적인 작업에 대해서 명시하는데 사용하는 플래그입니다. 이 값은 아래에 나열된 값을 OR 연산해서 설정하게 됩니다. 즉, 이 함수가 동작하는 내용은 소켓옵션과 lpFlags 매개변수에 의해서 결정된다고 볼 수 있습니다.

Value Meaning
MSG_PEEK 들어오는 데이터를 살짝 엿보기만 합니다. 데이터는 함수에서 지정한 버퍼로 카피되지만, 입력 큐 로부터 제거되지는 않습니다. 이 플래그는 넌-오버랩 소켓에서만 가능합니다.
MSG_OOB out-of-band 데이터를 처리하기 위해 사용됩니다.
MSG_PARTIAL 이 플래그는 메시지 지향형 소켓에서만 가능합니다. 수신받은 데이터는 전송한 데이터의 일부분입니다. 읽지 않고 남아있는 메시지의 일부분은 바로 뒤 따라오는 수신 연산에서 읽혀질 것입니다. 입력 매개변수로 사용될 때, 수신연산이 서비스 프로바이더에 의해서 메시지의 일부분만이 수신되었다 하더라도 수신 연산이 완료했다 라는 것을 알려주게 됩니다.

메시지 지향형 소켓에서, MSG_PARTIAL 플래그 비트는, 메시지중 일부분이 수신 되었다면, lpFlags 매개변수에 플래그가 설정되게 됩니다. 만약 완전한 메시지가 수신되었다면, MSG_PARTIAL 은 lpFlags 에서 사라지게 됩니다. 작업의 완료가 잠시 뒤로 미루어진 경우, lpFlags 매개변수에 의해서 포인트된 값은 업데이트 되지 않습니다. 작업의 완료가 알려졌을 때, 어플리케이션은 WSAGetOverlappedResult 함수를 호출해서 작업의 결과를 얻어낼 수 있고, lpdwFlags 매개변수로 작업완료 알림 플래그를 검색할 수 있습니다.

 

Overlapped socket I/O

오버랩 연산이 바로 완료 되었다면, WSARecvFrom 함수는 0 값을 반환하고, lpNumberOfBytesRecvd 매개변수는 읽어낸 바이트의 수를 가지고 업데이트 됩니다. 그리고, 플래그 비트는 lpFlags 매개변수로 또한 업데이트 됩니다. 오버랩 연산이 성공적으로 시작되고, 나중에 작업이 완료될 예정이라면, WSARecvFrom 함수는 SOCKET_ERROR를 반환하고, WSA_IO_PENDING 에러코드를 발생하게 됩니다. 이러한 경우에, lpNumberOfBytesRecvd 매개변수와 lpFlags 매개변수는 업데이트 되지 않습니다. 나중에 오버랩 연산이 완료 되었을 때, 수신받은 데이터의 크기는 완료루틴의 cbTransferred 매개변수나 WSAGetOverlappedResult 함수의 lpcbTransfer 매개변수에 의해서 알려지게 됩니다. 플래그 값은 WSAGetOverlappedResult 함수의 lpdwFlags 매개변수를 검사해서 얻어낼 수 있습니다.

WSARecvFrom 함수는 이전에 호출되었던 WSARecv, WSARecvFrom, WSASend, WSASendTo 함수의 완료 루틴의 내부에서 호출될 수 있습니다. 이러한 것이 가능 함으로써 선점형 흐름으로써 시간에 민감한 데이터의 전송은 가능하게 됩니다.

lpOverlapped 매개변수는 오버랩 연산이 일어나고 있는 동안 그값을 올바르게 유지해야 합니다. 만약 여러개의 I/O연산이 동시에 발생된다면, 각각의 연산은 각기 분리된 WSAOVERLAPPED 구조체를 참조해야 합니다.

만약 lpCompletionRoutine 매개변수가 NULL 이라면, lpOverlapped hEvent 필드는 오버랩 연산이 완료되었을 때 신호를 받게 됩니다. (물론 hEvent 필드는 제대로 된 이벤트 객체여야 하겠죠?) 어플리케이션은 이벤트객체로 대기하거나 폴링 하기 위해서 WSAWaitForMultipleEvents 함수나 WSAGetOverlappedResult 함수를 사용할 수 있습니다.

만약 lpCompletionRoutine 매개변수가 NULL이 아니라면, hEvent 필드는 무시되고, 어플리케이션은 완료루틴을 위해서 흐름정보를 넘줄 수 있습니다.

lpCompletionRoutine 매개변수를 NULL이 아닌 값으로 넘겨주고, 나중에 같은 오버랩 I/O 요청을 위해 WSAGetOverlappedResult 함수를 호출하는 콜러는 WSAGetOverlappedResult 함수의 결과를 TRUE로 하기위해 fWait 매개변수를 설정하지 않습니다. 이러한 경우 hEvent 필드의 사용법은 정의되어 있지 않습니다. 그리고, hEvent 이벤트 객체에 대해서 대기하려고 하는 시도는 예기지 않은 결과를 초래 할 수도 있습니다.

완료루틴(completion routine)은 Win32 파일 I/O에서 규정된 것과 같은 방식을 따릅니다. 완료루틴은 WSAWaitForMultipleEvents 함수가 fAlertable 매개변수를 TRUE로 하여 호출될 때 발생되는 것과 같이 쓰레드의 대기상태를 감지할 수 있는(alertable) 상태가 될 때까지 호출되지 않습니다.

완료루틴의 프로토타입은 아래와 같습니다.

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

CompletionRoutine 함수는 어플리케이션 지정 또는 라이브러리 지정 함수 이름을 가집니다. dwError 매개변수는 lpOverlapped 매개변수에 의해서 나타낸 오버랩 연산에 대한 완료 상태를 명시합니다. cbTransferred 매개변수는 전송한 바이트의 수를 명시합니다. 일반적으로 flag 값은 정의되어 있지 않고, dwFlags 는 0을 사용합니다.

 

Return Values

에러가 발생하지 않고, 전송연산이 바로 완료되었다면, WSARecvFrom 함수는 0을 반환 합니다. 이러한 경우에 완료루틴은 호출쓰레드가 반응할 수 있는(alertable) 상태로 호출되기 위한 준비를 이미 같추었다고 볼 수 있습니다. 에러가 발생한 경우 SOCKET_ERROR 값이 반환 됩니다. 그리고, WSAGetLastError 함수를 이용해서 특정한 에러코드를 얻어낼 수 있습니다.

 

Error Codes

WSANOTINITIALISED

이 함수를 사용하기 이전에 WSAStartup 함수를 성공적으로 호출해야 합니다.

WSAENETDOWN

네트웍 서브 시스템에 에러가 발생했습니다.

WSAEFAULT lpBuffers, lpFlags, lpFrom, lpNumberOfBytesRecvd, lpFromlen, lpOverlapped, 또는 lpCompletionRoutine 매개변수가 제대로된 사용자 어드레스 공간을 가지고 있지 않습니다 : lpFrom 버퍼가 상대방 어드레스를 담기에 너무 작은 경우에도 이 에러코드를 발생합니다.
WSAEINTR 블럭킹 윈속 v1.1 이 WSACancelBlockingCall 함수에서 취소되었습니다
WSAEINPROGRESS

블럭킹 윈속 v1.1 이 현재 진행 중입니다.

WSAEINVAL 소켓이 바이드 되지 않았습니다.
WSAEISCONN 소켓이 접속되어 있습니다. 이 함수는 접속지향형 소켓이건, 비접속 지향 소켓이건 접속된 소켓을 허용하지 않습니다.
WSAENETRESET 작업이 진행되고 있는 도중에 에러가 검출되어 접속이 깨져버렸습니다.
WSAENOTCONN 소켓이 접속되지 않았습니다. ( 접속 지향형 소켓일 경우만 )
컥~~~ 이건 또 무슨 소리냐... WSAEISCONN 에서는 접속된 소켓을 허용하지 않는다면서... ㅠㅠ
WSAEOPNOTSUPP MSG_OOB 플래그가 지정되었으나, 소켓이 SOCK_STREAM 과 같은 타입의 스트림 형태의 소켓이 아닌 경우 이거나, 소켓이 out-of-band 데이터를 지원하지 않는 형태의 소켓입니다. 그리고, MSG_PARTIAL 형태가 지원되지 않거나, 소켓이 단방향 이어서 데이터 수신 연산만을 지원하는 형태입니다.
WSAESHUTDOWN 소켓이 셧다운 되었습니다. 소켓에 대해서 shutdown 함수를 호출한 후에는 WSARecvFrom 함수를 사용할 수 없습니다.
WSAEWOULDBLOCK 오버랩 소켓      : 너무많은 오버랩 I/O가 발생했습니다.
넌-오버랩 소켓 : 소켓이 비동기 소켓일 경우 전송 연산이 바로 완료될 수 없습니다. ( 언젠가는 완료가 될 것이므로 확실한 에러상황이라고 볼 수 없죠.)
WSAEMSGSIZE 메시지가 지정된 버퍼에 들어가기에 너무 큽니다. 그리고, 신뢰성없은 프로콜의 경우에, 버퍼에 저장되지 않은 나머지 데이터는 잃어 버리게 됩니다.
WSAECONNRESET 가상 연결망이 원격지 상대방에 의해서 리셋 되었습니다.
WSAEDISCON 소켓 s가 메시지 지향형 소켓이고, 가상 연결망이 원격지에 의해서 우아하게 종료 되었습니다.
WSA_IO_PENDING 오버랩 연산이 성공적으로 시작되었고, 작업은 지금 완료될 수 없지만, 곧 완료될 것입니다.
WSA_OPERATION_ABORTED 오버랩 연산이 소켓의 종료 때문에 취소 되었습니다.

 

QuickInfo

Windows NT : 사용가능
Windows : 사용가능
Windows CE : 지원되지 않음
Header :
          Win16/32 : winsock.h
          Win32-II : winsock2.h
Import Library :
          Win16 : winsock.lib
          Win32 : wsock32.lib
          Win32-II : ws2_32.lib

See Also

overview, WSACloseEvent, WSACreateEvent, WSAGetOverlappedResult, WSASocket, WSAWaitForMultipleEvents