• WSAAsyncSelect 模型


    WSAAsyncSelect模型是winsock编程模型的一种,它提供了socket异步编程的方便,其实现是基于Windows消息机制的,最主要的就是下面这个函数:

    1 int PASCAL FAR WSAAsyncSelect (SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);

    s 标识一个需要事件通知的套接口的描述符.
    hWnd 标识一个在网络事件发生时需要接收消息的窗口句柄.
    wMsg 在网络事件发生时要接收的消息.
    lEvent位屏蔽码,用于指明应用程序感兴趣的网络事件集合.

    1、服务器端

    因此首先需要自定义一个消息

    #define WM_SOCKET WM_USER + 1

    并定义消息处理函数,以及做映射

    1 // 声明消息处理函数
    2 afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);
    3 // 映射
    4 ON_MESSAGE(WM_SOCKET,OnSocket)

    初始化socket

     1 BOOL CSocketSeverDlg::InitNetwork()
     2 {
     3     WSADATA wsaData;
     4     //初始化TCP协议
     5     BOOL ret = WSAStartup(MAKEWORD(2,2), &wsaData);
     6     if(ret != 0)
     7     {
     8         MessageBox("初始化网络协议失败!");
     9         return FALSE;
    10     }
    11     //创建服务器端套接字
    12     ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    13     if(ServerSock == INVALID_SOCKET)
    14     {
    15         MessageBox("创建套接字失败!");
    16         closesocket(ServerSock);
    17         WSACleanup();
    18         return FALSE;
    19     }
    20     //绑定到本地一个端口上
    21     sockaddr_in localaddr;
    22     localaddr.sin_family = AF_INET;
    23     localaddr.sin_port = htons(8888); file://端口号不要与其他应用程序冲突
    24     localaddr.sin_addr.s_addr = 0;
    25     if(SOCKET_ERROR = = bind(ServerSock ,(struct sockaddr*)&localaddr,sizeof(sockaddr)))
    26     {
    27         MessageBox("绑定地址失败!");
    28         closesocket(ServerSock);
    29         WSACleanup();
    30         return FALSE;
    31     }
    32     //将SeverSock设置为异步非阻塞模式,并为它注册各种网络异步事件,其 中 m_hWnd
    33     //为应用程序的主对话框或主窗口的句柄
    34     if(SOCKET_ERROR == WSAAsyncSelect(ServerSock, m_hWnd, WM_SOCKET,
    35     FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE))
    36     {
    37         MessageBox("注册网络异步事件失败!");
    38         WSACleanup();
    39         return FALSE;
    40     }
    41     //设置侦听模式
    42     listen(ServerSock, 5);
    43     return TRUE;
    44 }

    定义自定义消息处理函数

     1 LRESULT CSocketSeverDlg::OnSocket(WPARAM wParam, LPARAM lParam)
     2 {
     3     //调用Winsock API函数,得到网络事件类型
     4     int iEvent = WSAGETSELECTEVENT(lParam);
     5     //调用Winsock API函数,得到发生此事件的客户端套接字
     6     SOCKET CurSock= (SOCKET)wParam;
     7     switch(iEvent)
     8     {
     9         case FD_ACCEPT:
    10             //客户端连接请求事件
    11             OnAccept(CurSock);
    12             break;
    13         case FD_CLOSE:
    14             //客户端断开事件:
    15             OnClose(CurSock);
    16             break;
    17         case FD_READ:
    18             //网络数据包到达事件
    19             OnReceive(CurSock);
    20             break;
    21         case FD_WRITE:
    22             //发送网络数据事件
    23             OnSend(CurSock);
    24             break;
    25         default: break;
    26     }
    27         return 0;
    28 }

    2、客户端

    用同样的方法建立一个客户端应用程序,初始化网络部分,不需要将套接字设置为监听模式。注册网络事件时没有FD_ACCEPT,但增加了FD_CONNECT事件,因此没有OnAccept函数,但增加了OnConnect函数,向服务器发出连接请求时,使用connect函数,连接成功后,会相应到OnConnect函数中。下面是OnConnect函数的定义,传进来的参数是客户端Socket和服务器端发回来的连接是否成功的标识。

     1 void CSocketClientDlg::OnConnect(SOCKET CurSock, int error)
     2 {
     3     if(0 == error)
     4     {
     5         if(CurSock == ClientSock)
     6         {
     7             MessageBox("连接成功!");
     8         }
     9     }
    10 }

    定义OnReceive函数,处理网络数据到达事件

    定义OnSend函数,处理发送网络数据事件

    定义OnClose函数,处理服务器socket关闭事件

    以上就是用基于windows消息机制的异步I/O模型实现服务器/客户端应用程序的基本方法。

    3、我的疑问

    我有一点不是很明白,那就是这个发送网络数据事件是什么意思?什么时候发生?是我们使用send函数发送数据时发生么,

    未完待续。。。

  • 相关阅读:
    ndarray数据类型
    创建ndarray
    SqlHelper
    插入订单并且输出订单号的sql存储过程
    JQury自动切换图片
    设计模式--责任链模式
    设计模式--模板方法模式
    设计模式--观察者模式
    设计模式--享元模式
    设计模式--组合模式
  • 原文地址:https://www.cnblogs.com/lit10050528/p/3662781.html
Copyright © 2020-2023  润新知