IPv4地址的结构体与网络字节序

2021-12-24 11:40:03 浏览数 (1)

IPv4地址的结构体

代码语言:javascript复制
/* Fixed-size types, underlying types depend on word size and compiler.  */
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
#if __WORDSIZE == 64
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
#else
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
#endif


/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };


/* POSIX.1g specifies this type name for the `sa_family' member.  */
typedef unsigned short int sa_family_t;

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  */

#define	__SOCKADDR_COMMON(sa_prefix) 
  sa_family_t sa_prefix##family


/* Structure describing a generic socket address.  */
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);	/* Common data: address family and length.  */
    char sa_data[14];		/* Address data.  */
  };


/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;			/* Port number.  */
    struct in_addr sin_addr;		/* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr)
			   - __SOCKADDR_COMMON_SIZE
			   - sizeof (in_port_t)
			   - sizeof (struct in_addr)];
  };

sin_family: 每种协议族使用的地址族均不同,IPv4使用4字节地址族,IPv6使用16字节地族。

代码语言:javascript复制
 Name         Purpose                                    Man page
 AF_UNIX      Local communication                        unix(7)
 AF_LOCAL     Synonym for AF_UNIX
 AF_INET      IPv4 Internet protocols                    ip(7)
 AF_IPX       IPX - Novell protocols
 AF_INET6     IPv6 Internet protocols                    ipv6(7)
 AF_PACKET    Low-level packet interface                 packet(7)

sin_port: 用于以网络字节序保存16位端口号。 sin_addr: 用于以网络字节序保存32IP地址。同时观察结构体,in_addr。该结构体声明为uint32_t,因此只需要当作32位整数即可。

代码语言:javascript复制
/* Internet address.  */
typedef unsigned int __uint32_t;

typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };

sin_zero: 无特殊意义。只是为结构体sockaddr_in的大小与sockaddr结构体保持一致而插入的成员,必须填充为零。bind函数在第二个参数就得到sockaddr的结构体变量地址值。此结构体成员sa_data保存的地址信息中需包含IP地址和端口号剩余部分填充零。

代码语言:javascript复制
/* POSIX.1g specifies this type name for the `sa_family' member.  */
typedef unsigned short int sa_family_t;

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  */

#define	__SOCKADDR_COMMON(sa_prefix) 
  sa_family_t sa_prefix##family

/* Structure describing a generic socket address.  */
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);	/* Common data: address family and length.  */
    char sa_data[14];		/* Address data.  */
  };

# define __CONST_SOCKADDR_ARG	const struct sockaddr *

/* Give the socket FD the local address ADDR (which is LEN bytes long).  */
extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
     __THROW;

if (bind(listenfd, (struct sockaddr*) &servaddr, sizeof servaddr) < 0) {
	perror("bind");
}

字节序(Order)网络字节序

计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。举例来说,数值0x3322使用两个字节储存:高位字节是0x33,低位字节是0x22。网路字节序统一为大端字节序。

  • 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。
  • 小端字节序:低位字节在前,高位字节在后,即以0x2233形式储存。

字节序转换

代码语言:javascript复制
/* Functions to convert between host and network byte order.

   Please note that these functions normally take `unsigned long int' or
   `unsigned short int' values as arguments and also return them.  But
   this was a short-sighted decision since on different systems the types
   may have different representations but the values are always the same.  */

extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__));
extern uint16_t ntohs (uint16_t __netshort)
     __THROW __attribute__ ((__const__));
extern uint32_t htonl (uint32_t __hostlong)
     __THROW __attribute__ ((__const__));
extern uint16_t htons (uint16_t __hostshort)
     __THROW __attribute__ ((__const__));
  • htonl中的h表示主机(host)字节序。
  • htonl中的n表示网络(network)字节序。
  • htonl中的s表示short,l表示long。

通常s代表2字节short,因此用于端口号转换,l代表4字节long,因此用于IP地址转换。

字符串信息转化为网络字节序的整数型

代码语言:javascript复制
//成功时返回32位大端序整数型值,失败时返回INADDR_NONE,并且可以检测无效IP地址。
in_addr_t inet_addr(const char *__cp)
代码语言:javascript复制
//成功时返回1(true),失败时返回0(false)
int inet_aton(const char *__cp, struct in_addr *__inp)
  • __cp:含有需转换的IP地址信息的字符串地址值。
  • __inp:将保存结果的in_addr结构体变量的地址值。
代码语言:javascript复制
//成功时返回转换的字符串地址值,失败时返回-1
char *inet_ntoa(struct in_addr __in)

适用于IPv4地址和IPv6地址地址转换函数

代码语言:javascript复制
/* Convert from presentation format of an Internet number in buffer
   starting at CP to the binary network format and store result for
   interface type AF in buffer starting at BUF.  */
extern int inet_pton (int __af, const char *__restrict __cp,void *__restrict __buf) __THROW;

/* Convert a Internet address in binary network format for interface
   type AF in buffer starting at CP to presentation form and place
   result in buffer of length LEN astarting at BUF.  */
extern const char *inet_ntop (int __af, const void *__restrict __cp,char *__restrict __buf, socklen_t __len) __THROW;

inet_pton函数将用字符串表示的IP地址src(用点分十进制字符串表示的IPv4地址或用十六进制字符串表示的IPv6地址)转换成用网络字节序整数表示的IP地址,并把转换结果存储于dst指向的内存中。其中,af 参数指定地址族,可以是AF_ INET 或者AF_ INET6。inet_ pton 成功时返回1,失败则返回0并设置errno日。inet ntop 函数进行相反的转换,前三个参数的含义与inet pton的参数相同,最后一个参数cnt指定目标存储单元的大小。下面的两个宏能帮助我们指定这个大小(分别用于IPv4和IPv6):

代码语言:javascript复制
#include <netinet/in.h>
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46

inet_ ntop 成功时返回目标存储单元的地址,失败则返回NULL并设置ermo。

INADDR_ANY

代码语言:javascript复制
/* 自动获取服务端的计算机IP地址 */
#define	INADDR_ANY		((in_addr_t) 0x00000000)

0 人点赞