• linux网络编程---IP地址


    目录

    一、Linux下IP地址的表示方式

    1.1、通用套接字的地址类型定义如下:

    1.2、以太网中的地址类型表示

    1.3、结构sockaddr和结构sockaddr_in的关系

    1.4、本地socket中使用的地址类型

    二、IP地址的转换

    ? 2.1 字符串IP与二进制IP地址的转换

    2.2 IP转换函数之通用的版本


    一、Linux下IP地址的表示方式

    在socket编程中,地址结构通常都是以sockaddr_开头的,不同的协议族有不同的地址后缀定义方式

    1.1、通用套接字的地址类型定义如下:

    struct sockaddr
    {
        sa_family_t sa_family;	/* Common data: address family and length.  */
        char sa_data[14];		/* Address data.  */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上述结构中,定义在头文件中,sa_family_t实际上是 unsigned short int类型,故该结构的共占用16个字节。

    1.2、以太网中的地址类型表示

    从上面可以看出,在以太网编程中,使用struct sockaddr结构并不是很方便,没法直观的标示IP地址和端口等相关的信息,为此在以太网编程中,使用struct sockaddr_in来描述网络地址信息,其结构如下:

    struct sockaddr_in
      {
        sa_family_t sin_family;
        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)];
      };
    
    /* Internet address.  */
    typedef uint32_t in_addr_t;
    struct in_addr
      {
        in_addr_t s_addr;
      };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    上述结构中,struct in_addr是使用一个uint32_t 网络字节序描述的IP地址信息,我们在转换成点分式的IP信息时,就是使用的该结构体中in_addr_t进行转换的。

    1.3、结构sockaddr和结构sockaddr_in的关系

    上面两节描述了通用的socket地址和以太网中使用的地址,那么,这两种结构有啥关系呢,其实,通过上面的结构体介绍,已经可以看到一个大概,sockaddr和sockaddr_in是一个同样大小的结构,其对应关系如下图:

    在sockaddr_in中,只使用了前面的8个字节,为了和sockaddr中保持结构大小一直,其后面的8个字节填充保留。

    在使用bind等相关函数时,通常都是使用的地址sockaddr,这样,我们在实际以太网编程使用的过程中,都是利用结构sockaddr_in进行地址信息的设置,然后使用强转为sockaddr类型

    1.4、本地socket中使用的地址类型

    在进程间通信中,也可以使用socket进行通信,与网络编程类似,其也有一个地址描述信息结构体,其结构体说明如下:

    typedef unsigned short __kernel_sa_family_t;
    #define UNIX_PATH_MAX	108
    
    struct sockaddr_un {
    	__kernel_sa_family_t sun_family; /* AF_UNIX */
    	char sun_path[UNIX_PATH_MAX];	/* pathname */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其中,sun_family的取值一般使用AF_UNIX或者AF_LOCAL,sun_path是一个路径名。

    二、IP地址的转换

    上一章中,介绍了在网络编程中常用的几个与ip地址相关的数据结构,看完上面的一章,我们可能有这样的疑问,上面提到的IP地址都是用一个uint32_t 表示的,但是我们在实际中,见到的一般都是192.168.1.xx这种点分式的表示方法,那么,这两者之间如何转换?linux提供了一系列的函数,来完成这个工作。

    2.1 字符串IP与二进制IP地址的转换

    Linux系统中提供了一组函数用于网络地址的字符串形式和二进制形式之间的转换,其形式为inet_xxx(),函数具体如下:

    #include 
    #include 
    #include 
    
    int inet_aton(const char *cp,struct in_addr *inp);
    in_addr_t inet_addr(const char * cp);
    char * inet_ntoa(struct in_addr in);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    inet_aton()函数

    该函数将cp中的十进制字符串类型的IP地址,转换为二进制的IP地址,转换成功后的值,保存在指向结构体 struct in_addr 中,由上一章可以知道,该结构中为 struct sockaddr_in中的一个变量。当转换成功时,返回一个非0值,当转换失败或者传入的一个非法地址时,返回值为0。

    inet_addr()函数

    该函数与inet_aton()函数类似,也是将字符串形式的字符串转换为二进制的IP地址,转换成功返回IP地址,这个IP地址时网络字节序的表达,如果转换失败或者参数非法,返回-1,因为-1的存储形式为(111111111111111),而IP地址255.255.255.255也是这个值,故不能使用这个函数对这个地址进行转换。

    inet_ntoa()函数

    该函数是将一个struct in_addr表示的一个IP地址转换为点分十进制的字符串IP地址,返回值是转换后的字符串指针,这个指针是该函数返回的,该函数会用一个静态区域保存该返回结果,有可能结果会被其他线程调用覆盖这个结果,故该函数并不是线程安全的,使用时需要注意。

    2.2 IP转换函数之通用的版本

    在2.1节中,描述了常用的几个IP地址各种形式之间的转换函数,通过描述,可以知道,这几个函数或多或少存在缺陷,如只支持IPV4,或者不是线程安全的。下面介绍一对安全的与协议无关的地址转换函数,这两个函数都是可以重入支持多线程的,且这些函数支持IPv4和IPv6。

    int inet_pton (int af, const char *src,void *dst);
    const char *inet_ntop (int af, const void *src,char *dst, socklen_t size);
    
    • 1
    • 2

    inet_pton()函数

    该函数是将字符串类型的IP地址转换为二进制类型,第一个参数af表示网络类型的协议族,在IPv4下的值为AF_INET,第二个参数src表示需要转换的字符串,第三个参数表示转换后的结构,在IPv4中,dst指向的是一个struct in_addr的结构体指针。该函数的返回值为-1的时候,通常是第一个参数af指定的协议族不支持造成的。当函数的返回值为0时,表示src指向的值不是合法的IP地址,当返回值为正值时,表示转换成功。

    inet_ntop()函数

    该函数是将二进制的网络IP地址转换为字符串,第一个参数af表示网络类型的协议族,在IPv4下的值为AF_INET,第二个参数src为需要转换的二进制IP地址,在IPv4中,src指向的是一个struct in_addr的结构体指针,第三个参数dst是保存结果的缓存区指针,第四个参数size是dst缓冲区的大小。当发生错误时,返回NULL,如af设置的协议族不支持,或者size参数设置的缓存区大小过小。

  • 相关阅读:
    输入学生成绩(最多不超过40),输入为负值时表示输入结束,统计成绩高于平均成绩的学生人数
    Python基础学习笔记【最好拥有一定Java基础】
    动静态链接&&动静态库制作与使用
    虚幻引擎5:增强输入的使用方法
    Radius OTP完成堡垒机登录认证 安当加密
    Kali Linux基础篇(一) 信息收集
    webpack5 使用cache对Eslint和Babel缓存提升打包构建速度
    UG\NX二次开发 设置视图中心 UF_VIEW_set_center
    实战:kubeadm方式搭建k8s集群(containerd)-2022.12.5(成功测试-超详细)【荐】
    简述linux系统中软件包管理系统
  • 原文地址:https://blog.csdn.net/m0_67401761/article/details/126434677