WSAAsyncSelect模型允许程序以windows消息的形式接受网络事件通知
WSAAsyncSelect函数自动把套接字设为非阻塞模式,并且为套接字绑定一个窗口句柄,当有网络事件发生时,便向这个窗口发送消息
int WSAAsyncSelect(
SOCKET s, //套接字句柄
HWND hWnd,//指定一个窗口句柄
u_int wMsg,//网络事件到来的消息ID
long lEvent//指定那些需要发送
);
FD_READ:接收对方发送的数据包
FD_WRITE:继续发送数据
FD_ACCEPT:有连接进入
FD_CONNECT:连接对方主机
FD_CLOSE:连接被关闭
调用WSAAsyncSelect函数监听套接字
::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);
成功调用后,应用程序开始以windows消息形式在窗口函数接受网络事件通知
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT uMsg,
WPARAM wParam,//发送网络事件的套接字句柄
LPARAM lParam//指定了发生的网络事件
);
下面是简单的TCP服务器程序,接受客户端的连接请求,打印出接收的数据。
// WSATCPSERVER.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"WS2_32")
class CInitSock
{
public:
CInitSock(BYTE minorVer=2,BYTE majorVer=2)
{
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer,majorVer);
if(::WSAStartup(sockVersion,&wsaData)!=0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};
CInitSock initSock;
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
int _tmain(int argc, _TCHAR* argv[])
{
char szClassName[] = "MainWClass";
WNDCLASSEX wndclass;
//用描述主窗口的参数填充WNDCLASSEX结构
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = WindowProc;
wndclass.cbWndExtra = 0;
wndclass.cbClsExtra = 0;
wndclass.hInstance = NULL;
wndclass.hIcon = ::LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor = ::LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szClassName;
wndclass.hIconSm = NULL;
::RegisterClassEx(&wndclass);
//创建主窗口
HWND hWnd = ::CreateWindowEx(
0,
szClassName,
"",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
NULL,
NULL);
if(hWnd == NULL)
{
::MessageBox(NULL,"创建窗口出错!","error",MB_OK);
return -1;
}
USHORT nPort = 4567;
SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if(::bind(sListen,(sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR)
{
printf("Failed bind()\n");
return -1;
}
//套接字设为窗口通知消息类型
::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);
::listen(sListen,5);
//消息队列中取出消息
MSG msg;
while(::GetMessage(&msg,NULL,0,0))
{
::TranslateMessage(&msg);//转化键盘消息
::DispatchMessage(&msg);//将消息发送到相应窗口函数
}
return msg.wParam;//当GETMESSAGE返回0时结束
}
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_SOCKET:
{
SOCKET s=wParam;
//查看是否出错
if(WSAGETSELECTERROR(lParam))
{
::closesocket(s);
return 0;
}
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
SOCKET client = ::accept(s,NULL,NULL);
::WSAAsyncSelect(client,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);
}
break;
case FD_WRITE:
{
}
break;
case FD_READ:
{
char szText[1024]={0};
if(::recv(s,szText,1024,0) == -1)
::closesocket(s);
else
printf("接收数据:%s",szText);
}
break;
case FD_CLOSE:
{
::closesocket(s);
}
break;
}
}
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
}
//不处理的消息交给系统默认处理
return ::DefWindowProc(hWnd,uMsg,wParam,lParam);
}
好多错误啊...首先 char 不能转成LPSZ 其次,WM_SOCKET不认,为什么......哎