sockaddr_in结构体中那些折磨人的类型转换

发布时间 2023-04-21 16:40:23作者: 不喝可乐k

  对于初学者来说,在对sockaddr_in结构体结构体仍不熟悉的状态下,看到各种htonl、htons、inet_addr等函数肯定各种头大。

  首先,我们需要明确,sockaddr_in结构体中的各个成员的数据类型。

struct sockaddr_in {
  sa_family_t    sin_family; /* 协议族,通常为AF_INET */
  in_port_t      sin_port;   /*网络字节序的端口号 */
  struct in_addr sin_addr;   /* IP地址结构体 */
};

/* Internet address. */
struct in_addr {
  uint32_t          s_addr;     /* 网络字节序的IP地址 */
};

  其中,sa_family_tuint32_t意为32位无符号整形,in_port_t为unsigned short无符号短整形。

  其次,当我们编写socket时,需要清楚自己的主机采用何种CPU存储方式,是大端序还是小端序。

  所谓大端序,就是高字节高地址,小端序则反过来。

  例如数据0x0102,这是一个16进制的数字,我们说,从左往右,01是低字节,02是高字节。

  在存储器中,假设从左往右地址由低变高,则在大端序中,存储顺序为01 02,也就是高字节高地址,在小端序中则相反,高字节在低地址,所以存储为02 01。

  网络字节序通常都指大端序,所以在不确定主机是否采用大端序的情况下,还是老老实实转换为网络字节序以防出错。

  在转换之前,我们仍需知道一点知识才能正确地使用转化函数,那就是网络中TCP/UDP协议各自首部的各项长度,因为假如TCP首部中IP地址的长度只有16位,当然只是假设,你将IP地址转换为32位整形就进行通信,那将造成信息丢失。

  socketaddr_in结构体中,只有sin_port和sin_addr.s_addr两项需要了解,分别是端口号和IP地址。

  先讨论端口号。

  TCP/IP数据包中,端口号分别有源端口号、目的端口号,分别占16位。

  我们的in_port_t类型为unsigned short无符号短整形,占16位,在不确定主机采用何种序列的情况下,使用相应的函数进行转换为网络字节序。

  所以我们的主角就来啦,分别是htonl()、htons()、ntohl()、ntohs()四个函数,觉得名字很难记,看得晕乎乎的是不是?下面来好好介绍这四个函数你就记得很清楚啦。

  1、htonl  

uint32_t htonl(uint32_t hostlong);

  该函数将32位的主机字节顺序转换为网络字节顺序,即大端字节序。其中hostlong参数是待转换的32位整数。

  函数名字是host to network unsigned long的缩写,h to n l 首字母。

  2、htons

uint16_t htons(uint16_t hostshort);

  该函数将16位的主机字节顺序转换为网络字节顺序,即大端字节序。其中hostshort参数是待转换的16位整数。

  所以当我们写下以下语句时,

struct sockaddr_in addr;//声明套接字里地址结构体变量
addr.sin_port=8080//给出指定通信端口为8080

  要将端口号转换为网络字节序,所以使用htons函数,改写为

addr.sin_port=htons(8080);

  3、ntohl

uint32_t ntohl(uint32_t netlong);

  该函数将32位的网络字节顺序转换为主机字节顺序,即根据系统架构确定大端还是小端字节序。其中netlong参数是待转换的32位整数。

  4、ntohs

uint16_t ntohs(uint16_t netshort);

  该函数将16位的网络字节顺序转换为主机字节顺序,即根据系统架构确定大端还是小端字节序。其中netshort参数是待转换的16位整数。

  总结:后面两个函数ntohl、ntohs就是前面两个函数的倒转,掌握了前面两个也就记住了后面两个。所以显而易见,明确待转换的数据的类型的位数以及网络字节序和需要的位数,我们就清楚,我们该在什么情况下使用这些函数。

  

  说完了端口号,我们来说说IP地址的转换。

  我们熟悉的IP地址,是这样写的,例如192.168.0.1,这种格式称为点分十进制,是我们书写沟通常用的表达方式,但计算机并不接受这种数据类型,没有任何一种基本的数据类型叫做点分十进制,但好在我们有万能的字符串,可以把任何类型的数据嘎嘎往里写,不过这样一来,就需要使用函数来进行转换,毕竟计算机也不知道这串符号代表啥呀!

  所以引出下面的主角,inet_xxxx函数群,有inet_aton、inet_ntoa、

  这也是初学者看了名字就觉得很晕的几个函数,如前面介绍端口时的四个函数是进行整形到整形的转换,改变的是字节序,那么inet_xxxx这几个函数则是字符串到整形、整形到字符串,同时改变了字节序

  写到这里已经太长了,就放下我觉得写的很详细的介绍这四个函数的另一篇博客地址:https://www.cnblogs.com/0xfffffff0/p/10362127.html ,各位可以看这个。

  套接字初始化就说这么多。