最近在学习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 */
它的使用注意点是:
【学习程序】
我们可以通过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 <iostream>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
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;
}
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 <iostream>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
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;
}