[00024]-[2015-09-19]-[02]-[WSAEventSelect 模型]

套接字WSAEventSelect模型
WSAEventSelect模型和WSAAsyncSelect模型相似,他们的区别是:
网络事件发生时系统通知应用程序的形式不同,WSAAsyncSelect模型以消息的形式通知应用程序,而WSAEventSelect模型以事件的形式通知应用程序;

WSAAsyncSelect模型和WSAEventSelect模型 相同点:
【一】这两个模型都是异步模型
【二】当网络事件发生时,应用程序都可以接受到网络通知

[WSAEventSelect]函数

int WSAEventSelect(
  SOCKET s,
  WSAEVENT hEventObject,
  Long lNetWorkEvens
);

 

return 0 OR SOCKET_ERROR(调用WSAGetLastError()函数查看具体的错误代码)

    FD_READ     //有数据可读
    FD_WRITE    // 可以写数据
    FD_ACCEPT    // 接受连接
    FD_CONNECT    // 连接完成
    FD_CLOSE    // 套接字关闭
    FD_OOB     // 什么玩意儿    
    FD_QOS     // 什么玩意儿
    FD_GROUP_QOS     // 什么玩意儿
    FD_ROUTING_INTERFACE_CHANHE     // 什么玩意儿
    FD_ADDRESS_LIST_CHANGE     // 什么玩意儿

 

[WSACreateEvent]函数

WSAEVENT WSACreateEvent(void);    // 创建一个事件对象 创建一个以手动方式工作的事件对象,初始为无信号

 

[WSAResetEvent]函数

BOOL WSAResetEvent(WSAEVENT hEvent);    // 设置事件对象为无信号

 

[WSACloseEvent]函数

BOOL WSACloseEvetn(WSAEVENT hEvent);    // 释放事件对象占有的系统资源

 


[WSAWaitForMultipleEvents]函数

DWORD WSAWaitForMultipleEvents(
  DWORD cEvent,     // 事件对象句柄数量 WSA_MAXIMUM_WAIT_EVENTS = 64
  const WSAEVENT FAR* lphEvents,     // 事件对象指针    
  BOOL fWaitAll,     // 是否等待所有的事件对象都有“信号”才函数返回, ----> FALSE    
  DWORD dwTimeOut,     // 函数等待时间(阻塞) 0 ---》 立即返回 WSA_INFINITE ---》 无限等待
  BOOL fAlertable     // FALSE
);

 


egcode:

#define WAIT_TIME 1000    // 等待1000ms
SOCKET socketArray[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
int nTotal = 0;

DWORD dwIndex = WSAWaitForMultipleEvents(nTotal, eventArray, FALSE, WAIT_TIME, FALSE);

WSAEVENT curEvent = eventArray[deIndex - WSA_WAIT_EVENT_0];
SOCKET curSocket = socketArray[deIndex - WSA_WAIT_EVENT_0];

 

[WSAEnumNetWorkEvent]函数

int WSAEnumNetWorkEvent(
  SOCKET s,
  WSAEVENT hEventObject,
  LPWSANETWORKEVENT lpNetworkEvents,
);

typedef struct _WSANETWORKEVENTS{
  long lNetworkEvents,     // 发生的网络事件
  int iErrorCode[FD_MAX_EVENTS]     // 包含网络事件错误代码的数组
}WSANETWORKEVENTS, FAR *LPWSANETWORKEVENTS;

egproject:
// 构建CClient类

#define MAX_SIZE 1024
class CClient
{
public:
    CClient(SOCKET s){ m_s = s; }
    virtual ~CClient();

public:
    void RecData(void);
    void SendData(void);
    SOCKET GetSocket(void);
    void ProcessData(void);

private:
    SOCKET m_s;
    char m_recvBuf[MAX_SIZE];
    char m_sendBuf[MAX_SIZE];
}

 

// 创建客户端套接字管理的列表

typedef struct _socktnode
{
    CClient* pClient;
    _socktnode* pNext;
}SOCKETNODE, *PSOCKETNODE;

 

// 相关操作列表的API函数

PSOCKETNODE HeadNode = NULL;
void AddNode(SOCKET s);     // 添加节点 为什么以SOCKET s 为参数 在添加节点过程中
/*
void AddNode(SOCKET s)
{
    CClient* pClient = new CClient(s);
    // .... 添加该客户端拍Client
    return;
}
*/
void DeleteNode(SOCKET s);     // 删除节点
void DeleteAllNode(void);     // 删除所有节点 清空列表
CClient* GetClient(SOCKET s);     // 查找节点

 

// 定义相关变量

DWORD eventTotal = 0;
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET socketArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sListen;     // 监听套接字

//

WSAStartup(....);
sListen = socket(AF_INET, .....);
// sListen ===> socketArray[0]
eventArray[eventTotal] = WSACreateEvent();
WSAEventSelect(sListen, eventArray[eventTotal], FD_ACCEPT|FD_CLOSE);
bind(sListen, ....);
listen(sListen, 5);
eventTotal++;

//

while(m_bRunning)
{
    dwIndex = WSAWaitForMultipleEvents(eventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);

    WSANETWORKEVENTS networkEvents;
    WSAEnumNetworkEvents(socketArray[dwIndex - WSA_WAIT_EVENT_0], 
                 eventArray[dwIndex - WSA_WAIT_EVENT_0],
                 &networkEvents    
            );

    if(networkEvents.lNetworkEvents & FD_ACCEPT)    // 有客户端连接请求
    {
        if(networkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)    // 检查是否发生网络错误
        {
            // error handle
        }
        ::SendMessage(m_hMainDlg, WM_USER_ACCEPT, dweIndex, NULL);
    }

    if(networkEvents.lNetworkEvents & FD_READ)    // 有客户端连接请求
    {
        if(networkEvents.iErrorCode[FD_READ_BIT] != 0)    // 检查是否发生网络错误
        {
            // error handle
        }
        ::SendMessage(m_hMainDlg, WM_USER_READ, dweIndex, NULL);
    }

    if(networkEvents.lNetworkEvents & FD_CLOSE)    // 有客户端连接请求
    {
        if(networkEvents.iErrorCode[FD_CLOSE_BIT] != 0)    // 检查是否发生网络错误
        {
            // error handle
        }
        ::SendMessage(m_hMainDlg, WM_USER_CLOSE, dweIndex, NULL);
    }
}


#define WM_USER_ACCEPT    WM_USER+100
#define WM_USER_READ    WM_USER+101
#define WM_USER_CLOSE    WM_USER+102

BEGIN_MESSAGE_MAP(CMainWnd, ....)
    ON_MESSAGE(WM_USER_ACCEPT, OnAccept) 
    ON_MESSAGE(WM_USER_READ, OnRead) 
    ON_MESSAGE(WM_USER_CLOSE, OnClose)
END_MESSAGE_MAP() 

afx_msg LRESULT OnAccept(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnRead(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnClose(WPARAM wParam, LPARAM lParam);


// 处理客户端连接请求
LRESULT OnAccept(WPARAM wParam, LPARAM lParam)
{
    SOCKET sAccept;
    sAccpet = accept(m_arrSocekt[wParam - WSA_WAIT_EVENT_0], NULL, NULL);
    m_arrEvent[m_nEventTotal] = WSACreateEvent(void);
    m_arrSocket[m_nEventTotal] = sAccpet;
    AddNode(sAccpet);
    return 0;
}

// 处理数据接收消息
LRESULT OnRead(WPARAM wParam, LPARAM lParam)
{
    CClient* pClient = GetClient(m_arrSocket[wParam - WSA_WAIT_EVENT_0]);
    pClient->RecData();
    return 0;
}

// 处理套接字关闭消息
LRESULT OnClose(WPARAM wParam, LPARAM lParam)
{
    
    return 0;
}

 

posted @ 2015-09-19 17:43  Auris  阅读(301)  评论(0编辑  收藏  举报