inet_ntop(), inet_pton() inet_ntoa(), inet_aton(), inet_addr, htons(), htonl(), ntohs(), ntohl() struct hostent ,struct sockaddr_in

http://xuxiaozhao163.blog.163.com/blog/static/3793592200810182506818/

#include <arpa/inet.h> const char *inet_ntop(int af, const void *src,char *dst, socklen_t size); int inet_pton(int af, const char *src, void *dst);

Example

// IPv4 demo of inet_ntop() and inet_pton()

struct sockaddr_in sa;
char str[INET_ADDRSTRLEN];

// store this IP address in sa:
inet_pton(AF_INET, "192.0.2.33", &(sa.sin_addr));

// now get it back and print it
inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN);

printf("%s\n", str); // prints "192.0.2.33"
// IPv6 demo of inet_ntop() and inet_pton()
// (basically the same except with a bunch of 6s thrown around)

struct sockaddr_in6 sa;
char str[INET6_ADDRSTRLEN];

// store this IP address in sa:
inet_pton(AF_INET6, "2001:db8:8714:3a90::12", &(sa.sin6_addr));

// now get it back and print it
inet_ntop(AF_INET6, &(sa.sin6_addr), str, INET6_ADDRSTRLEN);

printf("%s\n", str); // prints "2001:db8:8714:3a90::12"
// Helper function you can use:

//Convert a struct sockaddr address to a string, IPv4 and IPv6:

char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
{
    switch(sa->sa_family) {
        case AF_INET:
            inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
                    s, maxlen);
            break;

        case AF_INET6:
            inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
                    s, maxlen);
            break;

        default:
            strncpy(s, "Unknown AF", maxlen);
            return NULL;
    }

    return s;
}

inet_ntoa(), inet_aton(), inet_addr

#include <sys/socket.h>  
#include <netinet/in.h>
#include <arpa/inet.h>
// ALL THESE ARE DEPRECATED! Use inet_pton() or inet_ntop() instead!!
char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);

Example

struct sockaddr_in antelope;  char *some_addr;    
inet_aton("10.0.0.1", &antelope.sin_addr); // store IP in antelope
some_addr = inet_ntoa(antelope.sin_addr); // return the IP
printf("%s\n", some_addr); // prints "10.0.0.1"
// and this call is the same as the inet_aton() call, above:
antelope.sin_addr.s_addr = inet_addr("10.0.0.1");

htons(), htonl(), ntohs(), ntohl()

在网络上传输数据时,由于数据传输的两端可能对应不同的硬件平台,采用的存储字节顺序也可能不一致,因此 TCP/IP 协议规定了在网络上必须采用网络字节顺序(也就是大端模式
通过对大小端的存储原理分析可发现,对于 char 型数据,由于其只占一个字节,所以不存在这个问题,这也是一般情况下把数据缓冲区定义成 char 类型 的原因之一。对于 IP 地址、端口号等非 char 型数据,必须在数据发送到网络上之前将其转换成大端模式,在接收到数据之后再将其转换成符合接收端主机的存储模式。

Linux 系统为大小端模式的转换提供了 4 个函数,输入 man byteorder 命令可得函数原型:

 

#include <netinet/in.h>    
uint32_t htonl(uint32_t hostlong); //host to network long
uint16_t htons(uint16_t hostshort); //host to network short
uint32_t ntohl(uint32_t netlong); //network to host long
uint16_t ntohs(uint16_t netshort);//network to host short

Example

uint32_t some_long = 10;  
uint16_t some_short = 20;
uint32_t network_byte_order;
// convert and send
network_byte_order = htonl(some_long);
send(s, &network_byte_order, sizeof(uint32_t), 0);
some_short == ntohs(htons(some_short)); // this expression is true

用C语言写程序时需要知道是大端模式还是小端模式。
所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
为什么会有大小端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式
 
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址单元
x1=((char*)&x)[1]; //高地址单元

若x0=0x11,则是大端; 若x0=0x22,则是小端......

 

完整C代码如下:

int endian_test(void)
{
  char tmp[4]={1,0,0,0};
  return (*(int *)tmp)==1;
}
其中tmp[4]为测试数组,大小为4*8bit=32bit,刚好为一个int类型变量的存储大小
在函数中先把char类型的指针tmp强制转换为int类型,那么以前tmp数组中存放的4个char类型的数据则变为一个int类型的数据
如果小端存储方式的话,则函数返回1,否则返回0;由此可以判断是大端存储还是小端存储

struct hostent结构体

struct hostent { 
   char *h_name; 
   char **h_aliases; 
   int h_addrtype; 
   int h_length; 
   char **h_addr_list; 
   }; 

struct hostent 数据结构的详细资料: 
  h_name – 地址的正式名称。 
  h_aliases – 空字节-地址的预备名称的指针。 
  h_addrtype –地址类型; 通常是AF_INET。  
  h_length – 地址的比特长度。 
  h_addr_list – 零字节-主机网络地址指针。网络字节顺序。 
  h_addr – h_addr_list中的第一地址。 
printf("Host name : %s\n", h->h_name); 
printf("IP Address : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr))); 

h->h_addr 是一个 char *, 但是 inet_ntoa() 需要的是 struct in_addr。因此,我转换 h->h_addr 成 struct in_addr *,然后得到数据。 

 

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

struct in_addr {
    unsigned long s_addr;          // load with inet_pton()
};

 

posted on 2013-12-08 15:36  anfflee  阅读(1135)  评论(0编辑  收藏  举报

导航