darwin之socket消息获取与处理

来源:互联网 发布:nginx 开启hsts 编辑:程序博客网 时间:2024/06/07 06:55
关于获取socket消息其实就用了2个函数:
select_watchevent(select_modwatch):socket注册窗口消息(类型req->er_data)

select_waitevent:当窗口消息发生后,获取窗口消息。如果还想继续获取该socket其他消息,则需要重新调用select_watchevent注册。




在windows下,EventThread线程创建一个窗口,所有的socket事件都以windows消息的形式发送到这个窗口上。
EventThread内部有一个OSRefTable fRefTable,用来管理多个socket。key是: 消息id, value是:EventContext。
每一个实例化的socket注册窗口消息的id都不一样,每次收到socket注册都回累加。


void EventContext::RequestEvent(int theMask):调用select_watchevent注册socket消息,如果是第一次注册,则关联到EventThread::fRefTable表中。

virtual void EventContext::ProcessEvent(int /*eventBits*/) :处理消息,在EventThread线程内部,不断地调用select_waitevent函数,获取所有注册到fRefTable上发送的窗口消息,一旦获取到,则调用ProcessEvent处理。

注意ProcessEvent是一个虚函数,也就意味着派生类处理消息的方式可能会改变。在EventContext中,只是将其对应的task signal到taskthread中。









WSAAsyncSelect参考:
int WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent);
该函数会自动将套接字设置为非阻塞模式,并且把发生在该套接字上且是你所感兴趣的事件,以Windows消息的形式发送到指定的窗口,
你需要做的就是在传统的消息处理函数中处理这些事件。参数hWnd表示指定接受消息的窗口句柄;参数wMsg表示消息码值(这意味着你
需要自定义一个Windows消息码);参数IEvent表示你希望接受的网络事件的集合,它可以是如下值的任意组合:FD_READ, FD_WRITE, 
FD_OOB, FD_ACCEPT, FD_CONNECT, FD_CLOSE 之后,就可以在我们熟知的Windows消息处理函数中处理这些事件。如果在某一套接字s上
发生了一个已命名的网络事件,应用程序窗口hWnd会接收到消息wMsg。参数wParam即为该事件相关的套接字s;参数lParam的低字段指
明了发生的网络事件,lParam的高字段则含有一个错误码,事件和错误码可以通过下面的宏从lParam中取出:
#define WSAGETSELECTEVENT(lParam) LOWORD(lParam)
#define WSAGETSELECTERROR(lParam) HIWORD(lParam)
下面继续使用伪代码来帮助阐述如何将上一节的阻塞模式WinSock应用升级到非阻塞模式。
首先自定义一个Windows消息码,用于标识我们的网络消息。


#define WM_CUSTOM_NETWORK_MSG (WM_USER + 100) 
//服务器端,在监听之前,将监听套接字置为非阻塞模式,并且标明其感兴趣的事件为FD_ACCEPT。
WSAAsyncSelect(server, wnd, WM_CUSTOM_NETWORK_MSG, FD_ACCEPT); 
listen(server); 


//客户端,在连接之前,将套接字置为非阻塞模式,并标明其感兴趣的事件为FD_CONNECT。
WSAAsyncSelect(client, wnd, WM_CUSTOM_NETWORK_MSG, FD_CONNECT);
ServerAddress?server;
connect(client,?server);


//接着,在Windows消息处理函数中,我们将处理监听事件、连接事件、及读写事件,方便起见,这里将服务器和客户端的处理代码放在
了一起。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)    
{    
    switch (message)    
    {
    case WM_CUSTOM_NETWORK_MSG: // 自定义的网络消息码    
        {    
            SOCKET socket = (SOCKET)wParam; // 发生网络事件的套接字    
            long event = WSAGETSELECTEVENT(lParam); // 事件    
            int error = WSAGETSELECTERROR(lParam); // 错误码    
    
            switch (event)    
            {    
            case FD_ACCEPT: // 服务器收到新客户端的连接请求    
                {    
                    // 接收到客户端连接,分配一个客户端套接字    
                    SOCKET client = accept(socket);     
                    // 将新分配的客户端套接字置为非阻塞模式,并标明其感兴趣的事件为读、写及关闭    
                    WSAAsyncSelect(client, hWnd, message, FD_READ | FD_WRITE | FD_CLOSE);    
                }    
                break;    
            case FD_CONNECT: // 客户端连接到服务器的操作返回结果    
                {    
                    // 成功连接到服务器,将客户端套接字置为非阻塞模式,并标明其感兴趣的事件为读、写及关闭    
                    WSAAsyncSelect(socket, hWnd, message, FD_READ | FD_WRITE | FD_CLOSE);    
                }    
                break;    
            case FD_READ: // 收到网络包,需要读取    
                {    
                    // 使用套接字读取网络包    
                    recv(socket);    
                }    
                break;    
            case FD_WRITE:    
                {    
                    // FD_WRITE的处理后面会具体讨论    
                }    
                break;    
            case FD_CLOSE: // 套接字的连接方(而非本地socket)关闭消息    
                {    
                }    
                break;    
            default:    
                break;    
            }    
        }    
        break;    
    …    
    }    
    …    
}    
以上就是非阻塞模式WinSock的应用框架,WSAAsyncSelect模型将套接字和Windows消息机制很好地粘合在一起,为用户异步SOCKET应用提供
了一种较优雅的解决方案。

阅读全文
0 0
原创粉丝点击