Winsock 网络编程 Socket模型之WSAAsyncSelect模型

来源:互联网 发布:笔记本右下角网络红叉 编辑:程序博客网 时间:2024/04/19 22:25
前言:
讲一下套接字模式和套接字I/O模型的区别。先说明一下,只针对Winsock
套接字模式:阻塞套接字和非阻塞套接字。或是叫同步套接字和异步套接字。
套接字模型:描述如何对套接字的I/O行为进行管理
Winsock提供的I/O模式一共有五种:
Select模型,WSAAsyncSelect模型,WSAEventSelect模型,Overlapped模型(重叠IO),Completion模型(完成IO)

二、WSAAsyncSelect模型

/// WSAAsyncSelect模型(同步I/O模型)
///这里为什么说他是同步的,就是因为实际的数据的Copy是同步进行的,而不是

///异步的,只是相应的通知机制(通知数据已经准备好了),是异步的
/// 这个模型允许应用程序以Windows消息的形式可在一个套接字上,接收网络事件通知
/// 具体的做法是在建好一个套接字后,调用WSAAsyncSelect函数。
/// 在我看来,WSAAsyncSelect是最简单的一种Winsock I/O模型(之所以说它简单是
/// 因为一个主线程就搞定了)。
/// 这里,我们需要做的仅仅是:
/// 1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,
///   监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;
/// 2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上
///   发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET;
/// 3.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;
/// 4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除Windows Socket library
//////////////////////////////////////////////////////////////////////////
/// 老陈:服务器应用程序,微软:服务器操作系统
/// 老陈使用了微软公司的新式信箱。这种信箱非常先进,一旦信箱里有新的信件,盖茨就会给
/// 老陈打电话:喂,大爷,你有新的信件了!从此,老陈再也不必频繁上下楼检查信箱了,牙
// 也不疼了,你瞅准了,蓝天......不是,微软...... 
/// 微软提供的WSAAsyncSelect模型就是这个意思。 
//////////////////////////////////////////////////////////////////////////
/// The WSAAsyncSelect function requests Windows message-based notification of network
/// events for a socket.
//////////////////////////////////////////////////////////////////////////


#pragma once 
#include <winsock.h>
#include <tchar.h>
#define PORT 5150
#define MSGSIZE 1024
#define WM_SOCKET WM_USER+0
#pragma comment(lib, "ws2_32.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = _T("AsyncSelect Model");
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass(&wndclass))
{
   MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName,MB_ICONERROR) ;
  return 0 ;
}
hwnd = CreateWindow (szAppName, 
// window class name

   TEXT ("AsyncSelect Model"), 
// window caption

   WS_OVERLAPPEDWINDOW, 
// window style

   CW_USEDEFAULT, 
// initial x position

   CW_USEDEFAULT, 
// initial y position

   CW_USEDEFAULT, 
// initial x size

   CW_USEDEFAULT, 
// initial y size

  NULL, 
// parent window handle

  NULL, 
// window menu handle

   hInstance, 
// program instance handle

  NULL) ; 
// creation parameters

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
   TranslateMessage(&msg) ;
   DispatchMessage(&msg) ;
}
return msg.wParam;
}
LRESULT CALLBACK WndProc (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:
  
// 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);
  return 0;
case WM_DESTROY:
   closesocket(sListen);
   WSACleanup();
   PostQuitMessage(0);
  return 0;
case WM_SOCKET:
  if (WSAGETSELECTERROR(lParam))
  {
    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);
   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); 
   break;
  }
  return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}


原创粉丝点击