浅析gethostbyname函数

    最近在学习unix/linux的socket编程的时候,使用了struct hostent *gethostbyname(const char *name);虽然给我的程序移植性带来了一定的好处,但是与此同时可带了一些副作用。本片文章将主要描述使用此函数时候的注意点,希望能够网友带来一些启迪。
    gethostbyname将返回一个struct hostent的指针,这个结构定义如下:
struct hostent
 {
    char    *h_name;        /* official name of host */
    char    **h_aliases;    /* alias list */
    int     h_addrtype;     /* host address type */
    int     h_length;       /* length of address */
    char    **h_addr_list;  /* list of addresses */
};
#define h_addr  h_addr_list[0]  /* for backward compatibility */
它的使用注意点是:
  • 这个指针指向一个静态数据,它会被后继的调用所覆盖。简单的说,它是多线程或者多进程不安全的。
  • 我们最好使用h_addr代理直接使用h_addr_list,这样能够提高日后的兼容性。
  • h_addr是指向一个长度为h_length的主机地址,它不是网络格式,所以在赋值给struct in_addr时,应该通过htonl来转化。我们可以通过下面一个学习程序来说明这种情况。
  • 如果我们使用GNU环境,我们可以使用gethostbyname_r或者gethostbyname2_r来替换掉gethostbyname函数。它们能够良好的解决多线程或多进程安全性问题,并且提供选择地址族参数。

【学习程序】
我们可以通过inet_pton或者inet_ntop函数来解决从"ddd.ddd.ddd.ddd"《=》ddd ddd ddd ddd之间的有效转换,简化了日后对struct sockaddr_in中 sin_addr的设置。比如说:
对于IPV4而言
struct sockaddr_in in;
memset( &in, 0, sizeof( struct sockaddr_in ) );
in.sin_family = AF_INET;
in.sin_port    = htons( 13 );
inet_pton( AF_INET, "109.119.20.48", &in.sin_addr );
这里我们不需要使用 htonl来转化,因为 inet_pton已经帮助我们搞定它了 !
#include
#include

#include
#include
#include
#include

using namespace std;

#define GET_SOCK_OPT( socket, name, var )       do {                           /
                socklen_t __len = sizeof( var );                               /
                if ( getsockopt( socket, SOL_SOCKET, name, &(var), &__len  ) != 0 )     /
                        perror( "[study_getsockopt]:" );                       /
        } while ( 0 )

static const char *host_addr = "109.119.20.48";

static void study_inet_pton( int af, const char *src )
{
        assert( src != NULL );

        if ( af == AF_INET )
        {
                struct in_addr addr;

                int rs = inet_pton( af, src, &addr );
                if ( rs > 0 )
                {
                        for ( int i = 0; i < sizeof( addr.s_addr ); ++ i )
                                cout << ((addr.s_addr >> (24 - (i << 3))) & 0xFF) << endl;
                }
                else if ( rs == 0 )
                {
                        cout << "[study_inet_pton]: invalid addr = " << src
                                << " for IPV4" << endl;
                }
                else
                        perror( "[study_inet_pton]" );
        }
        else if ( af == AF_INET6 )
        {
                struct in6_addr addr;

                int rs = inet_pton( af, src, &addr );
                if ( rs > 0 )
                {
                        for ( int i = 0; i < sizeof( addr.in6_u ); ++ i )
                                cout << addr.s6_addr[ i ] << endl;
                }
                else if ( rs == 0 )
                {
                        cout << "[study_inet_pton]: invalid addr = " << src
                                << " for IPV6" << endl;
                }
                else
                        perror( "[study_inet_pton]" );
        }
        else
        {
                cout << "af = " << af << " is unknown!" << endl;
        }
}

static void study_inet_ntop( int af, const char *src )
{
        assert( src != NULL );

        if ( af == AF_INET )
        {
                struct in_addr addr;

                int rs = inet_pton( af, src, &addr );
                if ( rs > 0 )
                {
                        //for ( int i = 0; i < sizeof( addr.s_addr ); ++ i )
                        //      cout << ((addr.s_addr >> (24 - (i << 3))) & 0xFF) << endl;
                        char buf[ INET_ADDRSTRLEN ];
                        if ( inet_ntop( af, &addr, buf, sizeof( buf ) ) != NULL )
                        {
                                cout << buf << endl;
                        }
                        else
                                perror( "[study_inet_ntop]" );
                }
                else if ( rs == 0 )
                {
                        cout << "[study_inet_pton]: invalid addr = " << src
                                << " for IPV4" << endl;
                }
                else
                        perror( "[study_inet_pton]" );
        }
        else if ( af == AF_INET6 )
        {
                struct in6_addr addr;

                int rs = inet_pton( af, src, &addr );
                if ( rs > 0 )
                {
                        //for ( int i = 0; i < sizeof( addr.in6_u ); ++ i )
                        //      cout << addr.s6_addr[ i ] << endl;
                        char buf[ INET6_ADDRSTRLEN ];

                        if ( inet_ntop( af, &addr, buf, sizeof( buf ) ) != NULL )
                        {
                                cout << buf << endl;
                        }
                        else
                                perror( "[study_inet_ntop]" );
                }
                else if ( rs == 0 )
                {
                        cout << "[study_inet_pton]: invalid addr = " << src
                                << " for IPV6" << endl;
                }
                else
                        perror( "[study_inet_pton]" );
        }
        else
        {
                cout << "af = " << af << " is unknown!" << endl;
        }
}

static void study_gethostbyname( void )
{
#if 0
        struct hostent *entry = gethostbyname( host_addr );
#else
        char host_name[ 128 ];
        if ( gethostname( host_name, sizeof( host_name ) ) != 0 )
                return;
        struct hostent *entry = gethostbyname( host_name );
#endif

        if ( entry == NULL )
        {
                cout << "[study_gethostbyname]: fail to obtain host" << endl;

                return;
        }

        cout << "Official name of host: " << entry->h_name << endl;
        cout << "alias list: ";
        if ( entry->h_aliases != NULL )
        {
                cout << entry->h_aliases << endl;
                cout << entry->h_aliases[ 0 ] << endl;
        }
        else
                cout << "Unknown" << endl;
        cout << "host address type: ";
        if ( entry->h_addrtype == AF_INET )
                cout << "AF_INET" << endl;
        else if ( entry->h_addrtype == AF_INET6 )
                cout << "AF_INET6" << endl;
        else
                cout << "Unknown" << endl;
        cout << "length of address: " << entry->h_length << endl;
        cout << "list of address: ";
        for ( int i = 0; i < entry->h_length; ++ i )
        {
                cout << (int)entry->h_addr[ i ];
                if ( i != entry->h_length - 1 )
                        cout << ".";
        }
        //cout << "list of address: " << entry->h_addr << endl;
        cout << endl;
}

static void study_gethostname( void )
{
        char host_name[ 128 ];

        if ( gethostname( host_name, sizeof( host_name ) ) == 0 )
        {
                cout << "host name = " << host_name << endl;
        }
        else
        {
                perror( "[study_gethostname]" );
        }
}

static void study_getsockopt( int socket )
{
        int value;

        GET_SOCK_OPT( socket, SO_DEBUG, value );
        cout << "SO_DEBUG = " << (value ? "true" : "false") << endl;

        //GET_SOCK_OPT( socket, SO_ACCEPTIONN, value );
        //cout << "SO_ACCEPTIONN = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_BROADCAST, value );
        cout << "SO_BROADCAST = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_REUSEADDR, value );
        cout << "SO_REUSEADDR = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_KEEPALIVE, value );
        cout << "SO_KEEPALIVE = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_LINGER, value );
        cout << "SO_LINGER = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_OOBINLINE, value );
        cout << "SO_OOBINLINE = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_SNDBUF, value );
        cout << "SO_SNDBUF = " << value << endl;

        GET_SOCK_OPT( socket, SO_RCVBUF, value );
        cout << "SO_RCVBUF = " << value  << endl;

        GET_SOCK_OPT( socket, SO_ERROR, value );
        cout << "SO_ERROR = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_TYPE, value );
        cout << "SO_TYPE = " << (value == SOCK_STREAM ? "SOCK_STREAM" : "SOCK_DGRAM") << endl;

        GET_SOCK_OPT( socket, SO_DONTROUTE, value );
        cout << "SO_DONTROUTE = " << (value ? "true" : "false") << endl;

        GET_SOCK_OPT( socket, SO_RCVLOWAT, value );
        cout << "SO_RCVLOWAT = " << value << endl;

        GET_SOCK_OPT( socket, SO_RCVTIMEO, value );
        cout << "SO_RCVTIMEO = " << value << endl;

        GET_SOCK_OPT( socket, SO_SNDLOWAT, value );
        cout << "SO_SNDLOWAT = " << value << endl;

        GET_SOCK_OPT( socket, SO_SNDTIMEO, value );
        cout << "SO_SNDTIMEO = " << value << endl;
}

static void study_socket( void )
{
        int sfd;

        if ( (sfd = socket( AF_INET, SOCK_STREAM, 0 )) != -1 )
        {
                study_getsockopt( sfd );
                close( sfd );
        }
}

int main( void )
{
        cout << ">>>study gethostname" << endl;
        study_gethostname();

        cout << ">>>study pton" << endl;
        cout << "addr = " << host_addr << endl;
        study_inet_pton( AF_INET, host_addr );
        study_inet_pton( AF_INET6, host_addr );

        cout << ">>>study ntop" << endl;
        study_inet_ntop( AF_INET, host_addr );
        study_inet_ntop( AF_INET6, host_addr );

        cout << ">>>study gethostbyname" << endl;
        study_gethostbyname();

        cout << ">>>study socket" << endl;
        study_socket();

        return 0;
}

你可能感兴趣的:(Linux,C/C++)