WSAAsyncSelect模型允许应用程序以Windows消息的形式接收网络事件通知.这个模型是为了适应Windows的消息驱动环境而设置的,现在许多对性能要求不高的网络应用程序都采用WSAAsyncSelect模型.MFC中的CSocket类也使用了它.
示例图片:------------------------------------------------------------------------------------------------
以下示例还是实现和前两篇文章(之一&之二)一样的功能:Client端连接Server端,向Server端发送数据。Server端接受Client端发送过来的数据并输出。Server端还是单线程处理多Client端连接的情况。
Server.cpp-----------------------------------------------------------------------------------------
1、在main中创建窗口但不调用ShowWindow即隐藏了窗口。由于是控制函程序,所以还是有控制函窗口的。
2、在ServerSocketProc中去初始化Windows Socket库、创建Socket、绑定Socket、监听Socket。
3、在窗口函数中处理Socket相关的消息
4、Client端通过closesocket关闭套接字会进入到以下的FD_CLOSE事件输出:"FD_CLOSE"
而直接关闭Client端会使WSAGETSELECTERROR(lParam)为真,也就会输出:"WSAGETSELECTERROR get error"
#include <windows.h>
#include <iostream>
using namespace std;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int ServerSocketProc(HWND);
#pragma comment(lib, "Ws2_32.lib")
#define WM_SOCKET WM_USER + 100
#define PORT_NO 6000
#define BACKLOG 10
// 全局变量
SOCKET gSockSrv;
int main()
{
static TCHAR lpszAppName[] = TEXT("TestWin");
HWND hwnd;
MSG msg;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = NULL;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszAppName;
// 注册窗口类
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
lpszAppName, MB_ICONERROR);
return 0;
}
// 创建应用程序主窗口
hwnd = CreateWindow(lpszAppName,
TEXT("Server"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
NULL,
NULL);
if (NULL == hwnd)
{
MessageBox(NULL, TEXT("CreateWindow failed."),
lpszAppName, MB_ICONERROR);
return 0;
}
// 创建Socket服务
int ret = ServerSocketProc(hwnd);
if (0 != ret)
{
MessageBox(NULL, TEXT("ServerSocketProc failed."),
lpszAppName, MB_ICONERROR);
return 0;
}
// 消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 清理资源------
closesocket(gSockSrv);
WSACleanup();
return msg.wParam;
}
//
// 窗口过程函数
//
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SOCKET: // 处理Socket信息
{
int ret;
SOCKET sock = wParam;
// 查看是否出错
if(WSAGETSELECTERROR(lParam))
{
closesocket(sock);
cout << "WSAGETSELECTERROR get error" << endl;
if (sock == gSockSrv)
{
DestroyWindow(hwnd);
}
return 0;
}
// 处理发生的事件
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT: // 监听中的套接字检测到有连接进入
{
int len=sizeof(SOCKADDR);
SOCKADDR_IN addrClient;
SOCKET sockConn = accept(sock, (SOCKADDR*)&addrClient, &len);
if (INVALID_SOCKET == sockConn)
{
cout << "accept() failed:" << WSAGetLastError() << endl;
return 0;
}
cout << "接受到新连接:" << inet_ntoa(addrClient.sin_addr) << endl;
WSAAsyncSelect(sockConn, hwnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
}
break;
case FD_WRITE:
{
}
break;
case FD_READ:
{
char recvBuffer[MAX_PATH] = {0};
ret = recv(sock, recvBuffer, sizeof(recvBuffer), 0);
if (ret == 0)
{
cout << "Connection has been gracefully closed." << endl;
closesocket(sock);
return 0;
}
else if (ret == SOCKET_ERROR)
{
cout << "Connection has been closed ungracefully." << endl;
closesocket(sock);
return 0;
}
cout << "Receive Data from Client:" << recvBuffer << endl;
}
break;
case FD_CLOSE:
{
cout << "FD_CLOSE" << endl;
closesocket(sock);
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int ServerSocketProc(HWND hwnd)
{
cout << "ServerSocketProc-----------------------------------------BEG" << endl;
WSADATA wsaData;
int ret;
WORD wVersionRequested = MAKEWORD(2, 2);
SOCKET sockSrv;
SOCKADDR_IN addrSrv;
HANDLE hThread = NULL;
// 初始化Windows Socket------
ret = WSAStartup(wVersionRequested, &wsaData);
if (ret != 0)
{
cout << "WSAStartup() failed:" << WSAGetLastError() << endl;
return -1;
}
// 创建Socket------
sockSrv = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockSrv)
{
cout << "socket() failed:" << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
gSockSrv = sockSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(PORT_NO);
// Bind Socket------
ret = bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (SOCKET_ERROR == ret)
{
cout << "bind() failed:" << WSAGetLastError() << endl;
closesocket(sockSrv);
WSACleanup();
return -1;
}
// 监听------
ret = listen(sockSrv, BACKLOG);
if (SOCKET_ERROR == ret)
{
cout << "listen() failed:" << WSAGetLastError() << endl;
closesocket(sockSrv);
WSACleanup();
return -1;
}
// WSAAsyncSelect------
WSAAsyncSelect(sockSrv, hwnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE);
cout << "ServerSocketProc-----------------------------------------END" << endl;
cout<< "Server started......" << endl;
return 0;
}
#include <iostream>
#include <windows.h>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
#define PORT_NO 6000
#define SRV_IP_ADDR "127.0.0.1"
int main(int argc, char* argv[])
{
int ret;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
SOCKET sockClient;
SOCKADDR_IN addrSrv;
// 初始化Windows Socket------
ret = WSAStartup(wVersionRequested, &wsaData);
if (ret != 0)
{
cout << "WSAStartup() failed:" << WSAGetLastError() << endl;
return -1;
}
// 创建Socket------
sockClient = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockClient)
{
cout << "socket() failed:" << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
addrSrv.sin_addr.S_un.S_addr = inet_addr(SRV_IP_ADDR);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(PORT_NO);
// 连接------
ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (SOCKET_ERROR == ret)
{
cout << "connect() failed:" << WSAGetLastError() << endl;
closesocket(sockClient);
WSACleanup();
return -1;
}
else
{
cout << "connect() successfully." << endl;
}
// 发送数据------
char sendBuf[MAX_PATH] = {0};
while (1)
{
cin.getline(sendBuf, sizeof(sendBuf));
if (strcmp(sendBuf, "exit") == 0)
{
break;
}
ret = send(sockClient, sendBuf, strlen(sendBuf)+1, 0);
if (SOCKET_ERROR == ret)
{
cout << "send() failed:" << WSAGetLastError() << endl;
closesocket(sockClient);
WSACleanup();
return -1;
}
}
// 清理资源-------
closesocket(sockClient);
WSACleanup();
cout << "exit..." << endl;
return 0;
}
示例图片:------------------------------------------------------------------------------------------------