关于从hostent到in_addr的IP地址转换

写一个小程序需要将hostent结构体中以网络字节序存储主机ip地址转换成点分十进制表示的IPv4地址。上网查了许多资料发现很多写的有问题,请教了大牛后这里总结一下。

hostent结构体在MSDN中的定义:

typedef struct hostent {
  char FAR      *h_name;
  char FAR  FAR **h_aliases;
  short         h_addrtype;
  short         h_length;
  char FAR  FAR **h_addr_list;
} HOSTENT, *PHOSTENT, FAR *LPHOSTENT;


在VS2015的库中的定义:

struct  hostent {
        char    FAR * h_name;                       /* official name of host */
        char    FAR * FAR * h_aliases;            /* alias list */
        short   h_addrtype;                           /* host address type */
        short   h_length;                               /* length of address */
        char    FAR * FAR * h_addr_list;         /* list of addresses */
#define h_addr  h_addr_list[0]                  /* address, for backward compat */
};

注意最后一行是多了一个宏定义的,但是网上很多文章中没提,自己一开始没搞明白h_addr这个字段是哪来的。

in_addr 结构体在MSDN中的定义:

typedef struct in_addr {
	union {
		struct {
			u_char s_b1, s_b2, s_b3, s_b4;
		} S_un_b;
		struct {
			u_short s_w1, s_w2;
		} S_un_w;
		u_long S_addr;
	} S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

in_addr 结构体在VS2015的库中的定义:

typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;
#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

在实际使用中需要注意两点,第一如果调用gethostbyname函数,根据VS2015的测试必须先用WSAStartup函数初始化网络库,否则gethostbyname返回的值肯定是NULL。但是网上很多文章是直接调用gethostbyname函数的,不知道他们是怎么能正常获取到返回值的。

其次是获取到hostent结构体后,转换为十进制的IP地址时调用inet_ntoa函数,必须赋值给addr.S_un.S_addr,用下面的方法是编译不了的

struct in_addr *in={h->h_addr};       // 报错:char* 类型的值不能用于初始化in_addr* 类型的实体
printf("%s\n",inet_ntoa(*in));

下面是例子代码:

#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")


int main(int argc, char** argv)
{
	WORD version = MAKEWORD(2, 2);
	WSADATA wd = { 0 };
	WSAStartup(version, &wd);

	hostent* he;
	he = gethostbyname("www.126.com");
	if (he == nullptr)
	{
		printf("gethostbyname error");
		return 0;
	}
	in_addr addr;
	addr.S_un.S_addr = *(ULONG*)he->h_addr;		//正确的转换方法

	printf("  official hostname : %s\n",he->h_name);
	printf("  alias: %s\n", he->h_aliases);
	printf("  Type: %d\n", he->h_addrtype);
	printf("  Length: %d\n", he->h_length);
	printf(" address: %s\n", inet_ntoa(addr));

	WSACleanup();
	return 0;
}
 

                
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值