소켓 이벤트를 윈도우 메시지로 비동기적으로 통보 받을 수 있기 때문에 IO 호출에 블록되는 것을 피할 수 있다.
비동기 데이타 송수신이 제공되는 것은 아니다.
FD_CLOSE
FD_ACCEPT
FD_READ
FD_WRITE
//
// Function: FindSocketObj
//
// Description:
// Search through the lsit of socket objects for the object matching
// the socket handle supplied. Return the object if found; NULL otherwise.
//
SOCKET_OBJ *FindSocketObj(SOCKET s)
{
SOCKET_OBJ *ptr=NULL;
ptr = gSocketList;
while (ptr)
{
if (ptr->s == s)
break;
ptr = ptr->next;
}
return ptr;
}
//
// Function: RemoveSocketObjByHandle
//
// Description:
// Remove the socket object structure from the list of objects that
// matches the socket handle.
//
void RemoveSocketObjByHandle(SOCKET s)
{
SOCKET_OBJ *obj;
obj = FindSocketObj(s);
if (obj)
{
RemoveSocketObj(obj);
}
return;
}
// Window message for the socket events
#define WM_SOCKET (WM_USER + 10)
//
// Function: WindowProc
//
// Description:
// This is the window procedure which handles the window messages for
// our hidden window. It handles all the WM_SOCKET messages and performs
// the correct actions for each message type (FD_READ, FD_WRITE, etc.).
//
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SOCKET_OBJ *sockobj=NULL,
*newsock=NULL;
int rc;
if (uMsg == WM_SOCKET)
{
// Check for an error on the socket
if (WSAGETSELECTERROR(lParam))
{
// An error occured on the socket, close it down
fprintf(stderr, "Socket failed with error %d\n", WSAGETSELECTERROR(lParam));
closesocket(wParam);
RemoveSocketObjByHandle(wParam);
}
else
{
// Find the socket object for this event
sockobj = FindSocketObj(wParam);
if (sockobj == NULL)
return 0;
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
// Get a new object for the client socket
newsock = GetSocketObj(INVALID_SOCKET);
case FD_READ:
rc = ReceivePendingData(sockobj);
if (rc == -1)
{
RemoveSocketObj(sockobj);
break;
}
else if (rc != WSAEWOULDBLOCK)
{
PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
}
//
// Don't break fall through and attempt to send data
//
case FD_WRITE:
//
// Send routine automatically tries to send all queued buffers.
//
rc = SendPendingData(sockobj);
if (rc == -1)
{
RemoveSocketObj(sockobj);
}
break;
case FD_CLOSE:
sockobj->closing = TRUE;
//
// Post an FD_READ message to force another receive
// This is to ensure we recv() until 0 is returned.
//
PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
break;
// bind the socket to a local address and port
rc = bind(sockobj->s, ptr->ai_addr, ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
return -1;
}