化繁为简系列原创教程

这是一个小巧的C++无连接套接字类,类名、函数名和变量名均采用匈牙利命名法。小写的x代表我的姓氏首字母(谢欣能),个人习惯而已,如有雷同,纯属巧合。

CxUdpSocket的使用如下(以某个叫做CSomeClass的类的相关代码为例):

一、声明无连接套接字对象实例。

CxUdpSocket m_usRemoteHost;

二、设置无连接套接字接收缓冲区事件通知方式。消息响应或回调函数,任选其一。

void CSomeClass::PreSubclassWindow() 
{
    // TODO: Add your specialized code here and/or call the base class
    HWND hwnd = GetSafeHwnd();
    MSG msg = {hwnd, WM_SOCKET_EVENT};
    m_usRemoteHost.SetWindowMessage(&msg, NULL);
    m_csRemoteHost.SetWindowMessage(&msg, NULL);
    m_ssLocalHost.SetWindowMessage(&msg, NULL);

    if (m_btCSMode == CSM_SERVER)
        ListenRemoteHost();

    CStatic::PreSubclassWindow();
}

三、绑定无连接套接字

BOOL CSomeClass::BindToLocalHost()
{
    if (m_usRemoteHost.IsBinded())
        m_usRemoteHost.Disbind();
        
    BOOL bRet = m_usRemoteHost.Bind(m_nUdpPort);

    CString str;
    if (!bRet)
        str.Format("Bind to %d failed. err code [%d].\n", m_nUdpPort,
                    CxSocket::WSAGetLastError());
    else
        str.Format("Bind to %d succeed.\n", m_nUdpPort);
    OutputDebugString(str);

    return bRet;
}

四、处理消息响应或函数回调。
1.消息响应

BEGIN_MESSAGE_MAP(CSomeClass, CStatic)
    //{{AFX_MSG_MAP(CSomeClass)
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
    ON_MESSAGE(WM_SOCKET_EVENT, OnSocketEvent)
END_MESSAGE_MAP()

LRESULT    CSomeClass::OnSocketEvent(WPARAM wParam, LPARAM lParam)
{
    if (WSAGETSELECTERROR(lParam) != 0)
        return 1;
    
    int nEvent = WSAGETSELECTEVENT(lParam);
    switch (nEvent)
    {
        case FD_ACCEPT: OnSocketAccept(wParam); break;
        case FD_CLOSE: OnSocketClose(wParam); break;
        case FD_READ: OnSocketRead(wParam); break;
        default: break;
    }
    
    return 1;
}

void CSomeClass::OnSocketRead(WPARAM wParam)
{
    if (m_csRemoteHost.GetSocket() == (SOCKET)wParam)
    {
        m_csRemoteHost.SelectEvent(FD_CLOSE);
        SOME_DATA_STRUCT data = {0};
        if (m_csRemoteHost.Recv((LPBYTE)&data, sizeof(data)))
            FrameRecv(&data);
        m_csRemoteHost.SelectEvent(FD_READ | FD_CLOSE);
    }
    else if (m_usRemoteHost.GetSocket() == (SOCKET)wParam)
    {
        SOME_DATA_STRUCT data = {0};
        char szIPAddr[MAX_IPV6] = {'\0'};
        if (m_usRemoteHost.RecvFrom(szIPAddr, (LPBYTE)&data, sizeof(data)))
            FrameRecv(&data);
    }
}

2.回调函数

LRESULT CALLBACK CSomeClass::SocketProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRet = 0;
    CSomeClass* pThis = (CSomeClass*)hwnd;
    if (pThis != NULL)
        lRet = pThis->OnSocketEvent(wParam, lParam);

    return lRet;
}

注意,在使用回调函数时应设置无连接套接字接收缓冲区事件通知方式为回调函数,并且设法把this指针传入设置函数,方便在回调函数中调用成员函数。

MSG msg = {(HWND)this, WM_SOCKET_EVENT};
m_usRemoteHost.SetWindowMessage(&msg, SocketProc);

五、解绑定无连接套接字。

void CSomeClass::OnDestroy() 
{
    CStatic::OnDestroy();
    
    // TODO: Add your message handler code here
    TerminateWaitComm();

    m_csRemoteHost.DisConnect();
    m_ssLocalHost.DisListen();
    m_usRemoteHost.Disbind();
}

至于无连接套接字数据发送,很简单,在需要处调用以下函数:

m_usRemoteHost.Send((LPBYTE)pData, sizeof(SOME_DATA_STRUCT));

我写的很多实用类都非常简洁,一般都没有注释,有也是中英文混搭两句,大家习惯就好。To be continued...


你可能感兴趣的:(化繁为简系列原创教程)