谢欣伦 - 化繁为简系列原创教程 - 通信专题 - 服务端套接字类CxServerSocket

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

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

一、声明服务端套接字对象实例。

CxServerSocket m_ssLocalHost;

 二、设置服务端套接字事件通知方式。消息响应或回调函数,任选其一。服务端套接字事件有:接收到客户端的连接请求。

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);

    m_csRemoteHost.SetWindowMessage(&msg);

    m_ssLocalHost.SetWindowMessage(&msg);



    if (m_btCSMode == CSM_SERVER)

        ListenRemoteHost();



    CStatic::PreSubclassWindow();

}

 三、侦听客户端连接请求

BOOL CSomeClass::ListenRemoteHost()

{

    char szIPAddr[MAX_IPV6];

    if (CxSocket::GetLocalHost(szIPAddr))

        return m_ssLocalHost.Listen(szIPAddr, NETPORT_NETWORK_COMM);

    else

        return FALSE;

}

  NETPORT_NETWORK_COMM是一个自定义的TCP端口值,只要不与公用端口冲突就行。

 四、处理消息响应或函数回调。
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()



/////////////////////////////////////////////////////////////////////////////

// CSomeClass message handlers



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::OnSocketAccept(WPARAM wParam)

{

    if ((SOCKET)wParam == m_ssLocalHost.GetSocket())

    {

        CxClientSocket xcs; xcs =m_ssLocalHost.Accept(); if (xcs.GetSocket() != INVALID_SOCKET)

        {

            char szIPAddr[MAX_IPV6];

            xcs.GetRemoteHost(szIPAddr);

            

            if (strcmp(szIPAddr, m_ipapRemoteHost.szAddr) == 0)

                m_csRemoteHost = xcs.GetSocket();

       else

            {

                xcs.DisConnect();

                

                CString str;

                str.Format("unknown socket %s disconnect.\n", szIPAddr);

                OutputDebugString(str);

            }

        }

    }    

}

2.回调函数

LRESULT CALLBACK CSomeClass::SocketProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    LRESULT lRet = 0;

    CSomeClass* pThis = (CSomeClass*)hwnd;

    if (pThis != 0)

        lRet = pThis->OnSocketEvent(wParam, lParam);



    return lRet;

}

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

MSG msg = {(HWND)this, WM_SOCKET_EVENT};

m_ssRemoteHost.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();

}

  至于服务端如何与客户端交换数据,很简单:将服务端接受的客户端连接赋给一个客户端套接字对象实例,然后让这个客户端套接字对象实例在需要处完成数据交换就可以了(客户端套接字类CxClientSocket如何使用?请查阅往期文章)。

CxClientSocket xcs;

xcs = m_ssLocalHost.Accept();

//  Save the expected socket and disconnect the unexpected socket

m_csRemoteHost = xcs.GetSocket();

  精练的代码不需要过多解释,你们懂的。To be continued...

你可能感兴趣的:(ServerSocket)