关键函数:
WSAAsyncSelect (SOCKET s,HWND hWnd,
unsigned
int wMsg,long lEvent);
具体注释:http://baike.baidu.com/view/573396.htm
疑问:所以只能是在windows窗口应用程序中应用?有局限性?为何不能发送到线程消息队列里?
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return PostWndProc(hWnd, message, wParam, lParam);
}
return PostWndProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK PostWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WSADATA wsd;
static SOCKET sListen;
SOCKET sClient;
SOCKADDR_IN local, client;
int ret, iAddrSize = sizeof(client);
char szMessage[MSGSIZE];
switch (message)
{
case WM_CREATE: //窗口创建初始化时,创建socket
// Initialize Windows Socket library
WSAStartup(0x0202, &wsd);
// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Bind
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (struct sockaddr *)&local, sizeof(local));
// Listen
listen(sListen, 3);
// Associate listening socket with FD_ACCEPT event
WSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT); //监听FD_ACCEPT事件,并以WM_SOCKET窗口消息传递进来
return 0;
case WM_DESTROY: //窗口销毁时,关闭监听套接字
closesocket(sListen);
WSACleanup();
PostQuitMessage(0);
return 0;
case WM_SOCKET:
if (WSAGETSELECTERROR(lParam)) //有错误发生,关闭该socket
{
closesocket(wParam);
break;
}
switch (WSAGETSELECTEVENT(lParam)) //取低位字节,网络事件
{
case FD_ACCEPT: //有连接进来
// Accept a connection from client
sClient = accept(wParam, (struct sockaddr *)&client, &iAddrSize);
// Associate client socket with FD_READ and FD_CLOSE event
WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ | FD_CLOSE); //对新建立的连接,读,关闭,监听
break;
case FD_READ:
ret = recv(wParam, szMessage, MSGSIZE, 0); //recv() 调用之后,自动重新通知函数
if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
{
closesocket(wParam);
}
else
{
szMessage[ret] = '\0';
send(wParam, szMessage, strlen(szMessage), 0); //原样返回
}
break;
case FD_CLOSE:
closesocket(wParam);
WSAAsyncSelect(wParam, hwnd, 0, 0); //清除所有该套接字的事件监听
break;
}
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam); //窗口
}
此处,将关于socket的事件响应,都放到基本窗口消息处理之后了。