网络编程:地址族与数据序列

39 阅读2分钟

网络地址

通常分为 IPv4 和 IPv6 IPv4地址分为网络地址和主机地址 传输数据时,先根据网络地址找到对应网络,然后在网络内找到对应主机。

B738EE54-8BF4-432C-924E-1CCC9532702A.png

表示 IPv4 的结构体

struct sockaddr_in {
  __uint8_t       sin_len;
  sa_family_t     sin_family;  //地址族
  in_port_t       sin_port;  //16位端口号
  struct  in_addr sin_addr;  //32位IP地址
  char            sin_zero[8]; //不使用
};

其中的struct in_addr如下:

/*
 * Internet address (a structure for historical reasons)
 */
struct in_addr {
  in_addr_t s_addr;
};

网络字节序与地址变换

不同 CPU 保存数值的方式不同,同样是 4 字节的整型 1,表示方式可以有以下两种方式: 00000000 00000000 00000000 00000001 00000001 00000000 00000000 00000000

字节序与网络字节序

  • 大端序:高位字节存放到低位地址
  • 小端序:高位字节存放到高位地址 比如在0x20号地址开始保存数据0x12345678 0x12是高位字节,0x78是低位字节

3BC7E50B-C603-45E7-B160-13993BF56B3A.png

EA9D443E-EF61-4CBA-93BD-647929C2D59B.png

不同端序的计算机互相收发信息会有问题,因此需要统一收发顺序 ::默认在网络中统一为大端序

字节序转换函数

// 前两个通常用于端口号转换,后两个用于 IP 地址转换
unsigned shorted htons(unsigned short);
unsigned shorted ntohs(unsigned short);
unsigned long ntohl(unsigned long);
unsigned long htonl(unsigned long);

h代表主机字节序,n 代表网络字节序,s 代表 short,l 代表 long

主机字节序转换为网络字节序

/**
     字节序转换
     */
    unsigned short host_prot = 0x1234;
    unsigned short net_port;
    unsigned long host_addr = 0x12345678;
    unsigned long net_addr;

    net_port = htons(host_prot);
    net_addr = htonl(host_addr);
    printf("net_port = %#x\n", net_port); //0x3412
    printf("net_addr = %#lx\n", net_addr); //0x78563412

Intel 和 AMD 用的都是小端序标准,因此这里能看到变化。

网络地址的初始化和分配

将字符串信息转换为网络字节序

struct sockaddr_in {
  __uint8_t       sin_len;
  sa_family_t     sin_family;  //地址族
  in_port_t       sin_port;  //16位端口号
  struct  in_addr sin_addr;  //32位IP地址
  char            sin_zero[8]; //不使用
};

可以看到,这里保存 IP 地址信息的是32 位整数型,因此需要进行转换

/**
     字符串转换为网络字节序
*/
    char *addr1 = "1.2.3.4";
    char *addr2 = "1.2.3.256";
	  
	  //inet_addr:成功时返回 32 位大端序整型数值
    unsigned long res = inet_addr(addr1);
    if (res == INADDR_NONE) {
        printf("invalid res");
    } else {
        printf("res = %#lx\n", res);
    }

    unsigned long res1 = inet_addr(addr2);
    if (res1 == INADDR_NONE) {
        printf("invalid res1\n");
    } else {
        printf("res1 = %#lx\n", res1);
    }
    return 0;
int inet_aton(const char *, struct in_addr * addr)
addr:保存转换结果的in_addr结构体变量的地址值
char *addr3 = "2.3.4.5";
    struct sockaddr_in addr_inet;
    if (!inet_aton(addr3, &addr_inet.sin_addr)) {
        printf("erro...");
    } else {
        printf("res = %#x", addr_inet.sin_addr.s_addr);
    }