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不认,为什么......哎