网络地址相关结构体,函数

1、字节序:
多字节数据在内存中数据内字节存储顺序,或者是在网络中数据内字节的传输顺序。
分为:主机字节序和网络字节序(网络字节序定死为大端格式)
大端:高字节低地址

2、主机字节序,网络字节序转换函数
htonl:host to network long (32bit),将32bit的数据从 主机字节序 转换为 网络字节序
ntohl:network to host long (32bit),将32bit的数据从 网络字节序 转换为 主机字节序
htons:host to network short (16bit),将16bit的数据从 主机字节序 转换为 网络字节序
ntohs:network to host short (16bit),将16bit的数据从网络字节序 转换为 主机字节序

// 32位数据类型从host(主机字节序)转换为network(网络字节序,大端)
uint32_t htonl(uint32_t hostlong);
// 32位数据从network(网络字节序)转换为host(主机字节序)
uint32_t ntohl(uint32_t netlong);

// 16位数据类型从host(主机字节序)转换为network(网络字节序,大端)
uint16_t htons(uint16_t hostshort);
// 16位数据从network(网络字节序)转换为host(主机字节序)
uint16_t ntohs(uint16_t netshort);

字节序转换函数转换的是ip地址(htonl, ntohl),端口号(htons, ntohs)。
而不是传输的内容。因为传输的内容已经被序列化为一个个字符了,不存在多字节数据内的字节序。

jl@jl-virtual-machine:~/test$ gcc test.c 
jl@jl-virtual-machine:~/test$ cat test.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char** argv) 
{
    int a = 0x12345678;
    int b;
    b = htonl(a);

    printf("a=%#x\n", a);
    printf("htonl(a)=%#x\n", htonl(a));

    return 0;
}
jl@jl-virtual-machine:~/test$ ./a.out 
a=0x12345678
htonl(a)=0x78563412
jl@jl-virtual-machine:~/test$ 

3、struct sockaddr,struct sockaddr_in 和 struct sockaddr_un

struct sockaddr {
unsigned  short  sa_family;     /* address family, AF_xxx */
char  sa_data[14];                 /* 14 bytes of protocol address */
};

sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET,表示使用 ipv4。
sa_data是14字节协议地址。
此数据结构用做bind、connect、accept、recvfrom、sendto等函数的参数,指明地址信息。

但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构,struct sockaddr_in。
struct sockaddr 是通用的套接字地址,而 struct sockaddr_in 则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。
二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。
一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。

sockaddr_in(在netinet/in.h中定义):
struct  sockaddr_in {
// 协议族,在网络socket编程中一般是AF_INET,表示 ipv4
short  int  sin_family;                      /* Address family */
// 端口号(注意使用网络字节顺序)
unsigned  short  int  sin_port;       /* Port number */
// 此结构体用来存储ip地址,详见下
struct  in_addr  sin_addr;              /* Internet address */
// 此数组用来让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节
unsigned  char  sin_zero[8];         /* Same size as struct sockaddr */
};

// 此结构体用来保存ip地址
struct  in_addr {
// 32bit, 等价于 in_addr_t
unsigned  long  s_addr;
};

具体用法示例,以及 sockaddr_un 相关见:struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系

4、字符串表示的点分十进制ip地址 与 struct in_addr
两个函数:

int inet_aton(const char *cp, struct in_addr *inp);

用于将cp指向的字符串,转换成为 in_addr 对应的ip地址
如:将字符串“192.168.1.66”转换成in_addr类型的ip地址
返回1表示成功,0表示失败

char *inet_ntoa(struct in_addr in);

将 in_addr 类型的ip地址转换成诸如 “192.168.1.66”格式的ip地址
The string is returned in a statically allocated buffer, which subsequent calls will overwrite.

jl@jl-virtual-machine:~/test$ cat test.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char** argv) 
{
    struct in_addr a;
    char b[16] = "192.168.1.6";
    char *c;
    char d[16];
    int e;
    e = inet_aton(b, &a);
    printf("ret val = %d\n", e);
    printf("%s\n", inet_ntoa(a));
    c = inet_ntoa(a);
    printf("c=%s\n", c);
    return 0;
}
jl@jl-virtual-machine:~/test$ gcc test.c 
jl@jl-virtual-machine:~/test$ ./a.out 
ret val = 1
192.168.1.6
c=192.168.1.6

返回的是一个静态分配的buffer,只能用指针接收

jl@jl-virtual-machine:~/test$ cat test.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char** argv) 
{
    struct in_addr a;
    char b[16] = "192.168.1.6";
    char *c;
    char d[16];
    int e;
    e = inet_aton(b, &a);
    printf("ret val = %d\n", e);
    printf("%s\n", inet_ntoa(a));
    d = inet_ntoa(a);
    printf("c=%s\n", d);
    return 0;
}
jl@jl-virtual-machine:~/test$ gcc test.c 
test.c: In function ‘main’:
test.c:18:7: error: assignment to expression with array type
     d = inet_ntoa(a);
       ^
jl@jl-virtual-machine:~/test$ 

5、hostname 与 in_addr 相互转换
先介绍:域名&网络地址结构体

struct hostent
{
    char *h_name;  //主机名,即官方域名
    char **h_aliases;  //主机所有别名构成的字符串数组,同一IP可绑定多个域名
    int h_addrtype; //主机IP地址的类型,例如IPV4(AF_INET)还是IPV6
    int h_length;  //主机IP地址长度,IPV4地址为4,IPV6地址则为16
    char **h_addr_list;  /* 主机的ip地址,以网络字节序存储。若要打印出这个IP,需要调用inet_ntoa()。*/
    //上面这个二级指针相当于一个字符串数组,每个元素(就是char *)对应一个 struct in_addr*
};
#define h_addr h_addr_list[0];

域名转ip地址函数

struct hostent *gethostbyname(const char *name)

例程:获取域名www.baidu.com的ip地址

jl@jl-virtual-machine:~/test$ cat test.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char** argv) 
{
    int i;
    struct in_addr my_addr;
    struct hostent *myhost;
    myhost = gethostbyname("www.baidu.com");
    printf("www.baidu.com ip:\n");
    for(i=0; myhost->h_addr_list[i]; i++)
    {
        printf("%s\n", inet_ntoa(*(struct in_addr *)myhost->h_addr_list[i]));
    }
    return 0;
}
jl@jl-virtual-machine:~/test$ gcc test.c
jl@jl-virtual-machine:~/test$ ./a.out 
www.baidu.com ip:
36.152.44.95
36.152.44.96
jl@jl-virtual-machine:~/test$ 
jl@jl-virtual-machine:~/test$ ping 36.152.44.95
PING 36.152.44.95 (36.152.44.95) 56(84) bytes of data.
64 bytes from 36.152.44.95: icmp_seq=1 ttl=58 time=8.30 ms
64 bytes from 36.152.44.95: icmp_seq=2 ttl=58 time=8.90 ms
^C
--- 36.152.44.95 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 8.308/8.604/8.900/0.296 ms
jl@jl-virtual-machine:~/test$ 
jl@jl-virtual-machine:~/test$ 
jl@jl-virtual-machine:~/test$ ping 36.152.44.96
PING 36.152.44.96 (36.152.44.96) 56(84) bytes of data.
64 bytes from 36.152.44.96: icmp_seq=1 ttl=58 time=14.7 ms
64 bytes from 36.152.44.96: icmp_seq=2 ttl=58 time=13.2 ms
64 bytes from 36.152.44.96: icmp_seq=3 ttl=58 time=18.9 ms
64 bytes from 36.152.44.96: icmp_seq=4 ttl=58 time=18.5 ms
^C
--- 36.152.44.96 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 13.223/16.369/18.954/2.465 ms
jl@jl-virtual-machine:~/test$ 

另一个示例见:域名和网络地址结构体—struct hostent

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值