} } }

    化繁为简系列原创教程 - 通信专题 - C++套接字类CxUdpSocket的设计

    添加时间:2013-7-19 点击量:

      这是一个小巧的C++套接字类,类名、函数名和变量名均采取匈牙利定名法。小写的x代表我的姓氏首字母(谢欣能),小我习惯罢了,如有类似,纯属偶合。


    CxUdpSocket的定义如下:



    class XIOCTRL_CLASS CxUdpSocket : public CxSocket
    
    {
    public:
    CxUdpSocket();
    virtual ~CxUdpSocket();
    void operator=(SOCKET s) { m_socket = s; }

    public:
    BOOL Bind(
    int nPort);
    BOOL Disbind();
    BOOL IsBinded();

    BOOL SendTo(LPCSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize);
    BOOL RecvFrom(LPSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize);

    protected:
    int m_nPort;
    };


      因为这个类被封装在动态库里面,所以类名前应用了导出标记XIOCTRL_CLASS,读者在应用时完全可以去掉。类的定义被放在一个包含很多类定义的头文件中,没有零丁为它写头文件,所以它的定义项目组代码看上去没有高低文。


      CxUdpSocket的实现如下:



    CxUdpSocket::CxUdpSocket()
    
    : m_nPort(
    0
    {

    }

    CxUdpSocket::
    ~CxUdpSocket()
    {

    }

    BOOL CxUdpSocket::Bind(
    int nPort)
    {
    Disbind();

    if (m_socket == INVALID_SOCKET)
    m_socket
    = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (m_socket == INVALID_SOCKET)
    return FALSE;

    sockaddr_in addr
    = {0};
    addr.sin_family
    = AF_INET;
    addr.sin_addr.s_addr
    = htonl(INADDR_ANY);
    addr.sin_port
    = htons(nPort);

    int iRet = bind(m_socket, (SOCKADDR)&addr, sizeof(addr));
    if (iRet == SOCKET_ERROR)
    {
    Disbind();
    DWORD dwError
    = WSAGetLastError();
    return FALSE;
    }

    long lEvent = FD_WRITE | FD_READ | FD_CLOSE;
    SelectEvent(lEvent);
    m_nPort
    = nPort;

    return TRUE;
    }

    BOOL CxUdpSocket::IsBinded()
    {
    sockaddr_in saCur
    = {0};
    int nLen = sizeof(saCur);
    int iResult = getsockname(m_socket, (SOCKADDR)&saCur, &nLen);
    return (iResult != SOCKET_ERROR);
    }

    BOOL CxUdpSocket::SendTo(LPCSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize)
    {
    if (m_socket == INVALID_SOCKET)
    return FALSE;

    sockaddr_in addr
    = {0};
    addr.sin_family
    = AF_INET;
    addr.sin_addr.s_addr
    = inet_addr(lpszIPAddr);
    addr.sin_port
    = htons(m_nPort);

    DWORD nMaxSize
    = MAX_MSG_SIZE, nCount = 0, nToSend;
    int iRet;
    LPBYTE lpbtIterator;

    while (nCount != dwSize)
    {
    nToSend
    = min((dwSize - nCount), nMaxSize);
    lpbtIterator
    = &lpbtData[nCount];
    iRet
    = sendto(m_socket, (const char)lpbtIterator, nToSend, 0
    (SOCKADDR
    )&addr, sizeof(addr));
    if (iRet > 0
    nCount
    += iRet;
    else
    break;
    }

    return (nCount == dwSize);
    }

    BOOL CxUdpSocket::RecvFrom(LPSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize)
    {
    if (m_socket == INVALID_SOCKET)
    return FALSE;

    sockaddr_in addrRemote
    = {0};
    int nSize = sizeof(addrRemote);
    DWORD nMaxSize
    = MAX_MSG_SIZE;
    DWORD nCount
    = 0;
    DWORD nToReceive;
    int iRet;
    LPBYTE lpbtIterator;

    while (nCount != dwSize)
    {
    nToReceive
    = min((dwSize - nCount), nMaxSize);
    lpbtIterator
    = &lpbtData[nCount];
    iRet
    = recv(m_socket, (char)lpbtIterator, nToReceive, 0
    (SOCKADDR
    )&addrRemote, &nSize);
    if (iRet > 0
    nCount
    += iRet;
    else
    break;
    }

    strcpy(lpszIPAddr, inet_ntoa(addrRemote.sin_addr));
    return (nCount == dwSize);
    }

    BOOL CxUdpSocket::Disbind()
    {
    if (m_socket == INVALID_SOCKET)
    return TRUE;

    int nRet = closesocket(m_socket);
    if (nRet == SOCKET_ERROR)
    return FALSE;

    m_socket
    = INVALID_SOCKET;
    m_nPort
    = 0;
    return TRUE;
    }


      类的实现被放在一个包含很多类实现的CPP文件中,没有零丁为它写CPP文件,所以它的实现项目组代码看上去没有高低文(比如头文件包含、宏定义等等)。MAX_MSG_SIZE是一个定义为1024的宏,来自对另一个头文件的引用(将来的文章会向大师介绍)。这个类的实现项目组的代码不久不多,统共120多行。实现了(解)绑定地址与端口、发送接管数据以及侦听接管数据的功能(仅以消息响应的体式格式通知上层法度处理惩罚接管数据)。


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

    文艺不是炫耀,不是花哨空洞的文字堆砌,不是一张又一张的逆光照片,不是将旅行的意义转化为名牌包和明信片的物质展示;很多时候它甚至完全不美——它嘶吼、扭曲,它会痛苦地抽搐,它常常无言地沉默。——艾小柯《文艺是一种信仰》
    分享到: