• C++套接字类CxUdpSocket的设计


    C++套接字类CxUdpSocket的设计

    这是一个小巧的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 = recvfrom(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...

     
     
     
  • 相关阅读:
    JDBC JAVA数据库插入语句
    uri与url
    struts标签库
    jdbc使用
    mysql安装配置
    Json Web Token
    实现一个简单vue
    vue v2.5.0源码-双向数据绑定
    vue v2.5.0源码-初始化流程
    webpack
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3201671.html
Copyright © 2020-2023  润新知