C++ Socket封装

来源:互联网 发布:单片机控制舵机程序 编辑:程序博客网 时间:2024/05/29 17:27
TC_Socket是一个socket的封装类,封装了socket的处理,该封装类的主要操作功能包括
  • 生成socket,根据指定的socket类型,调用socket系统调用,并进行异常处理,如果sock存在,则先关闭,打开新的描述符。
void TC_Socket::createSocket( int iSocketTypeint iDomain)
{
    assert (iSocketType == SOCK_STREAM || iSocketType == SOCK_DGRAM);
    close();

    _iDomain    = iDomain;
    _sock       = socket(iDomain, iSocketType , 0);

    if( _sock < 0)
    {
        _sock = INVALID_SOCKET;
        throw TC_Socket_Exception( "[TC_Socket::createSocket] create socket error! :" + string(strerror( errno)));
    }
}

  • 关闭sock;
void TC_Socket::close()
{
    if ( _sock != INVALID_SOCKET)
    {
        :: close(_sock );
        _sock = INVALID_SOCKET;
    }
}

  • 获取对点的ip和端口,对AF_INET的socket有效,构建sockaddr,利用getPeerName从sock描述符获取IP以及端口地址,通过inet_ntop把数值型地址转换为字符串,通过ntohs把端口的网络顺序转换成为主机顺序,sPeerAddress= sAddr是一个复制拷贝。
void TC_Socket:: getPeerName(string &sPeerAddress, uint16_t &iPeerPort)
{
    assert (_iDomain == AF_INET);

    struct sockaddr stPeer;
    bzero (&stPeer, sizeof ( struct sockaddr));
    socklen_t iPeerLen = sizeof (sockaddr );

    getPeerName (&stPeer, iPeerLen);

    char sAddr[ INET_ADDRSTRLEN] = "\0" ;
    struct sockaddr_in *p = ( struct sockaddr_in *)&stPeer;

    inet_ntop (_iDomain , &p->sin_addr, sAddr, sizeof(sAddr));

    sPeerAddress= sAddr;
    iPeerPort   = ntohs(p->sin_port);
}

  • 获取自己的ip和端口,对AF_INET的socket有效. 
void TC_Socket:: getSockName(string &sSockAddress, uint16_t &iSockPort)
{
    assert (_iDomain == AF_INET);

    struct sockaddr stSock;
    bzero (&stSock, sizeof ( struct sockaddr));
    socklen_t iSockLen = sizeof (sockaddr );

    getSockName (&stSock, iSockLen);

    char sAddr[ INET_ADDRSTRLEN] = "\0" ;
    struct sockaddr_in *p = ( struct sockaddr_in *)&stSock;

    inet_ntop (_iDomain , &p->sin_addr, sAddr, sizeof(sAddr));

    sSockAddress = sAddr;
    iSockPort = ntohs(p->sin_port);
}

  • 修改,获取socket选项值. 
int TC_Socket:: setSockOpt( int opt, const void *pvOptVal, socklen_t optLen, int level)
{
    return setsockopt(_sock , level, opt, pvOptVal, optLen);
}

int TC_Socket::getSockOpt( int opt, void *pvOptVal, socklen_t &optLen, int level)
{
    return getsockopt(_sock , level, opt, pvOptVal, &optLen);
}

  • accept服务端sock,accept是阻塞的操作,并是一个不可重入函数,会被信号处理等中断,此处需要重复操作,返回一个客户端TC_SOCK
int TC_Socket:: accept(TC_Socket &tcSock, struct sockaddr *pstSockAddr, socklen_t &iSockLen)
{
    assert (tcSock._sock == INVALID_SOCKET);

    int ifd;

    while ((ifd = :: accept(_sock , pstSockAddr, &iSockLen)) < 0 && errno == EINTR);

    tcSock. _sock    = ifd;
    tcSock. _iDomain = _iDomain;

    return tcSock. _sock;
}

  • bind操作,将sock绑定到指定的地址与端口
void TC_Socket:: bind( const char *sPathName)
{
    assert (_iDomain == AF_LOCAL);

    unlink (sPathName);

    struct sockaddr_un stBindAddr;
    bzero (&stBindAddr, sizeof ( struct sockaddr_un));
    stBindAddr. sun_family = _iDomain ;
    strncpy (stBindAddr.sun_path, sPathName, sizeof (stBindAddr.sun_path));

    try
    {
        bind(( struct sockaddr *)&stBindAddr, sizeof (stBindAddr));
    }
    catch(...)
    {
        throw TC_Socket_Exception( "[TC_Socket::bind] bind '" + string(sPathName) + "' error"errno);
    }
}

void TC_Socket::bind( struct sockaddr * pstBindAddrsocklen_t iAddrLen)
{
      //如果服务器终止后,服务器可以第二次快速启动而不用等待一段时间
      int iReuseAddr = 1;

    //设置
    setSockOpt (SO_REUSEADDR, ( const void *)&iReuseAddr, sizeof (int ), SOL_SOCKET);

    if(:: bind(_sock pstBindAddr, iAddrLen) < 0)
    {
        throw TC_Socket_Exception( "[TC_Socket::bind] bind error"errno );
    }
}

  • 连接其他服务,对AF_INET的socket有效(同步连接)
int TC_Socket::connect( struct sockaddr *pstServerAddr, socklen_t serverLen)
{
    return :: connect(_sock , pstServerAddr, serverLen);

}
  • 监听其他端口(同步连接),能收指定连接队列

void TC_Socket::listen( int iConnBackLog)
{
    if (:: listen(_sock , iConnBackLog) < 0)
    {
        throw TC_Socket_Exception( "[TC_Socket::listen] listen error"errno );
    }
}

  • 发送,接收数据(一般用于tcp). 
int TC_Socket::recv( void *pvBuf, size_t iLen, int iFlag)
{
    return :: recv(_sock , pvBuf, iLen, iFlag);
}

int TC_Socket::send( const void *pvBuf, size_t iLen, int iFlag)
{
    return :: send(_sock , pvBuf, iLen, iFlag);
}

  • 单向关闭连接
void TC_Socket:: shutdown( int iHow)
{
    if (:: shutdown(_sock , iHow) < 0)
    {
        throw TC_Socket_Exception( "[TC_Socket::shutdown] shutdown error"errno );
    }
}


  • 设置是否阻塞,利用fcntl,先F_GETFL操作,加上或者消除bBlock后F_SETFL
void TC_Socket:: setblock( int fd, bool bBlock)
{
    int val = 0;

    if ((val = fcntl(fd, F_GETFL, 0)) == -1)
    {
        throw TC_Socket_Exception( "[TC_Socket::setblockfcntl [F_GETFL] error"errno );
    }

    if(!bBlock)
    {
        val |= O_NONBLOCK;
    }
    else
    {
        val &= ~ O_NONBLOCK;
    }

    if ( fcntl(fd, F_SETFL, val) == -1)
    {
        throw TC_Socket_Exception( "[TC_Socket::setblockfcntl [F_SETFL] error"errno );
    }
}

  • 静态工具方法,生成管道,并且将管道设置的读写设置为指定的阻塞设置。
void TC_Socket:: createPipe( int fds[2], bool bBlock)
{
    if(:: pipe(fds) != 0)
    {
        throw TC_Socket_Exception( "[TC_Socket::createPipe] error"errno );
    }

    try
    {
        setblock(fds[0], bBlock);
        setblock(fds[1], bBlock);
    }
    catch(...)
    {
        :: close(fds[0]);
        :: close(fds[1]);
        throw;
    }
}

  • 静态工具方法,获取所有本地地址,主要借助于ioctl函数,不断的递增分配存储空间,直到空间能够容纳所有的地址为止,表示取到了所有的地址;
vector< stringTC_Socket:: getLocalHosts()
{
    vector <stringresult;

    TC_Socket ts;
    ts.createSocket (SOCK_STREAMAF_INET);

    int cmd = SIOCGIFCONF;

    struct ifconf ifc;

    int numaddrs = 10;

    int old_ifc_len = 0;

    while( true)
    {
        int bufsize = numaddrs * static_cast< int>( sizeof( struct ifreq));
        ifc. ifc_len = bufsize;
        ifc. ifc_buf = ( char*)malloc (bufsize);
        int rs = ioctl(ts.getfd(), cmd, &ifc);

        if(rs == -1)
        {
            free(ifc.ifc_buf );
            throw TC_Socket_Exception ("[TC_Socket::getLocalHosts] ioctl error" errno);
        }
        else if(ifc. ifc_len == old_ifc_len)
        {
            break;
        }
        else
        {
            old_ifc_len = ifc. ifc_len;
        }
   
        numaddrs += 10;
        free(ifc.ifc_buf);
    }

    numaddrs = ifc. ifc_len / static_cast< int>( sizeof( struct ifreq));
    struct ifreq* ifr = ifc. ifc_req;
    for( int i = 0; i < numaddrs; ++i)
    {
        if(ifr[i]. ifr_addr.sa_family == AF_INET)
        {
            struct sockaddr_in* addr = reinterpret_cast< struct sockaddr_in*>(&ifr[i]. ifr_addr);
         if(addr-> sin_addr.s_addr != 0)
         {
                char sAddr[ INET_ADDRSTRLEN] = "\0";
                inet_ntop(AF_INET , &(*addr).sin_addr, sAddr, sizeof (sAddr));
             result.push_back (sAddr);
         }
        }
    }

    free (ifc.ifc_buf);

    return result;
}

  • 静态工具方法,解析地址, 从字符串(ip或域名), 解析到in_addr结构.
void TC_Socket:: parseAddr( const string &sAddr, struct in_addr &stSinAddr)
{
    int iRet = inet_pton(AF_INET, sAddr. c_str(), &stSinAddr);
    if(iRet < 0)
    {
        throw TC_Socket_Exception( "[TC_Socket::parseAddr] inet_pton error"errno );
    }
    else if(iRet == 0)
    {
        struct hostent stHostent;
        struct hostent *pstHostent;
        char buf[2048] = "\0";
        int iError;

        gethostbyname_r(sAddr.c_str(), &stHostent, buf, sizeof (buf), &pstHostent, &iError);

        if (pstHostent == NULL)
        {
            throw TC_Socket_Exception( "[TC_Socket::parseAddr] gethostbyname_r error! :" + string(hstrerror(iError)));
        }
        else
        {
            stSinAddr = *( struct in_addr *) pstHostent-> h_addr;
        }
    }
}
0 0
原创粉丝点击