网络地址相关函数一网打尽

news2024/11/15 23:39:14

这块的函数又多又乱,今天写篇日志,以后慢慢补充 

1. 网络地址介绍

1.1  ipv4 

1.1.1   点、分十进制的ipv4 

你对这个地址熟悉吗?  192.168.10.100,这可以当做一个字符串。被十进制数字、 “ . ”分开。IP地址的知识就不再多讲了,什么A类B类C类等等。但是你见过300.401.299.299这样的网络地址吗?为什么这4个数字每个最大只有255呢

1.1.2  32位无符号、整数型的ipv4 

在电脑中,所有的数据都是二进制存储的,ipv4的地址,由4个数字组成,每个数字都有8位(8个二进制位),那么最大就是11111111 ,转化成十进制就是255 。所以ipv4 每个数字最大只能是255.

192.168. 10.100转化为二进制( 用你win10电脑上自带的计算器,左上角选择(程序员))就得到结果“

1100 0000   。1010 1000 。 00001010  。  0110 0100  把我用来分割的句号去掉就是32位短整数;

还有64位长整数,后面用到再说

1.1.3 字节序

这个词应该是前辈们直接翻译的man手册。

本机字节序:host byte order数据在你的电脑上的存放方式。

网络字节序: network byte order 。要跟别人的终端打交道,所有数据都得放到网上传输。网上的传输格式。

字节序有两种,大端字节序,小端字节序。不管哪种、都是二进制!!

先来弄明白内存中,有一块 叫做 “栈 ”,栈的增长方向是从下到上,就跟你摞砖头一样,

比方说,

你先定义了一个变量int   a   =10  ,

你又定义了int b =20,

b 和a的值就存放在栈上。你先定义了a  ,a 就放0x0001这块内存,b 就在0x0002这块内存  

仅仅是举例而已,!这个例子别当真其实一个int就要占4个字节的,,相当于8位十六进制)

(    0x表示16进制,16进制的一位相当于二进制4位。)

假设现在有一个 十六进制的数字   0x1234  (转化为十进制是 4660)它需要上图中4个空抽屉才能存下他, 如果4放在 最低的抽屉,1放在最上面的抽屉,那就是 “小端”字节序。如果相反,那么就是大端字节序。

大端 : 高位数据,放在低位内存。

小端:高位数据,放在高位内存。低位数据,放在低位内存

你的主机,是怎么存放很长的一个数据的呢?参考另一个博主的文章

验证你的本机字节序,是大端还是小端

 网络字节序可不能随心所欲,因为所有上网的人都用这一种格式。网络字节序采用 大端字节序格式。想象一下可以理解,别人给你发“我们去春游”,你的电脑肯定先收到 “我” ,最后一个收到“游” ,(网络传输是字节流)“我”先存起来肯定在低位内存,而这个短语当成随便一个整数 2603来看的话,2 “ 我”是高位数据,放低位内存 ()(这个比喻恰当不?)

1.2 ipv6

IPv6的地址长度为128位,是IPv4地址长度的4倍。ipv6的地址不是切成4段,而是切成8段,每两个冒号之间相当于16位二进制。

于是IPv4点分十进制格式不再适用,采用十六进制表示。两个冒号之间16位二进制正好用4位十六进制表示

IPv6有3种表示方法。(摘自百度百科)

1.2.1 冒分十六进制表示法

格式为 X: X: X: X:X:X:X:X,其中每个X表示地址中的16b,以十六进制表示,例如:

ABCD:EF01:2345:6789:ABCD:EF01:2345:6789

这种表示法中,每个X的前导0是可以省略的,例如:

2001:0DB8:0000:0023:0008:0800:200C:417A→ 2001:DB8:0:23:8:800:200C:417A

另外两种表示方法自学一下 不重要

2. IP地址结构体分析

当我们说网络地址时,必须包括ip地址和一个16位的端口号,我们平时在浏览器输入网址,从来没输入过端口号,www.baidu.com : 80 没打过吧。是因为服务器上什么协议(服务)对应什么端口都是默认的。

sockaddr_in结构体包含3个成员:

  struct sockaddr_in {
           sa_family_t         sin_family; /* address family: AF_INET */
           in_port_t             sin_port;   /* port in network byte order */
           struct in_addr     sin_addr;   /* internet address */
           };

 注意:port端口是 IP协议的上层---TCP  /UDP协议里的内容,IP协议就只管IP地址。 sin_family一般就是AF_INET(个别函数里特殊的话一会儿再说),也不用转换成网络字节序,因为它不在网络上传播,只是本地电脑关心这个值。

sin_port和sin_addr必须转换成网络字节序,才能在网络上传播。注意IP地址结构体 in_addr 的成员:s_addr就是Ip 地址的网络字节序。

           /* Internet address. */
           struct in_addr {
                 uint32_t       s_addr;     /* address in network byte order */
           };

uint32_t 不就是无符号32位整数吗! 所以应该是ipv4 。然后在inet_aton的帮助手册中,你发现它还有另外一个名字in_addr_t 

 in <netinet/in.h> as:

           typedef    uint32_t     in_addr_t;

           struct    in_addr {
                  in_addr_t       s_addr;
           };

还有一个叫做sockaddr的结构体,因为它的字节数需要填充所以一般不用它。

3.相关函数

三大类,就是网络字节序,本机字节序,字符串这3种格式来回转换。然后这3类函数,每类再细分2小种,你要的结果在返回值里,还是你要的结果在传出参数里。

3.1 字符串格式  “127.0.0.1 ”-- --  》      网络字节序格式

3.1.1 结果在返回值里

3.1.1.1  inet_addr

#include <arpa/inet.h>

in_addr_t    inet_addr(const char * string);

 将一个点、数字格式的ipv4地址,转为二进制的网络字节序格式

返回值:

        成功:32位大端序整数型值,注意unsigned int ,不是long unsigned int

     失败:函数可以检测你的输入格式是否正确,你输入的不正确的话,函数返回值是 INADDR_NONE (usually -1)

man手册上说的:   Use of this function is problematic because -1 is a valid address (255.255.255.255). 别用这个函数。尽量去用 inet_aton(), inet_pton(3), or getaddrinfo(3), which provide a cleaner way to indicate error return.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

int main() {   
    //定义一个地址mytest
    struct sockaddr_in mytest;
    bzero(&mytest, sizeof(mytest));
    mytest.sin_family =AF_INET;
    //mytest.sin_port =htons(8888);
    const char* str = "127.0.0.1";
    in_addr_t result111 = inet_addr(str);
    mytest.sin_addr.s_addr = result111;
   printf("网络地址是%u\n", result111);
 
return 0;
}

结果

 网络地址是16777343

用你的计算器 二进制是   0001。 0000 0000。 0000 0000    。0111 1111  

哦? 1.0.0.127 ??对了,网络字节序是大端的,所以127放在最低位了

3.1.1.2 inet_network

in_addr_t     inet_network(const char *cp);

将一个点、数字形式的ipv4的字符串,转化为 本机字节序格式,但是仍可以作为网络地址,进行网络传输 (???)

返回值:成功:转换成的网络地址。

            失败: -1

3.1.2 结果在参数里

3.1.2.1   inet_aton 

#include <arpa/inet.h>

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

 将一个本机(host ,本地的)的点、数字格式的ipv4地址,转为二进制的网络字节序格式

参数1 : 有const ,是传入参数。需转换的IP地址信息的字符串,例如“127.0.0.1””

参数2: 传出参数, in_addr结构体的指针里,现在存着你想要的in_addr的信息了。(看清楚是谁的指针!!!)

返回值:成功 1  失败 0

//inet_aton    
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

int main() {
    //定义一个地址mytest
    struct sockaddr_in mytest;
    bzero(&mytest, sizeof(mytest));
    mytest.sin_family =AF_INET;
    //mytest.sin_port =htons(8888);
    const char* str = "127.0.0.1";
    inet_aton( str, &(mytest.sin_addr));
    printf("网络地址是%u\n", mytest.sin_addr.s_addr); 
return 0;
}

 结果跟上面那个一样     网络地址是16777343

3.1.2.2    inet_pton

#include <arpa/inet.h>

       int   inet_pton  (int af, const char *src, void *dst);

 将字符串转为网络地址结构体,ipv4   ipv6都实用  结果复制到dst指针指向的内容里。

参数1 : af 填写AF_INET时,参数2 应该是点分十进制的ipv4格式

              af填写 AF_INET6 时,参数2应该是 冒号切好的,8个十六进制的ipv6 (这种写法最稳妥)。后面太复杂了不讨论ipv6 情况。。。

参数2 :格式对应好。

参数3: 你可以传任何指针进去,反正void* 是万用指针。。看一下最后面那个man手册子带例子,作者就是传了unsigned char buf[ sizeof( struct  in6_addr) ] 字符数组指针buf进去。

返回值:

成功:返回1 

失败:你写的参数2格式不对,返回0

          你写的af参数不对,返回-1

例子:这个还没想好。。待补充

3.2  网络字节序格式   -- --  》  字符串格式

3.2.1 结果在返回值里

3.2.1.1  inet_ntoa 函数

#include <sys/socket.h> 

#include <netinet/in.h>

#include <arpa/inet.h>

        char * inet_ntoa   (struct in_addr  in);

  将一个网络字节序格式的网络主机地址 in,   转化为数字+点的字符串格式的ipv4地址。这里是服务器端代码,客户端不需要代码,直接开启一个新终端,nc 127.0.0.1   8888命令,然后服务器那边就

请求连接的客户网络地址是127.0.0.1

//inet_ntoa   
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
int main() {
    int sfd = socket (AF_INET, SOCK_STREAM, 0);
    if (sfd <0){
        printf("socket fun error/n");
        return -1;
    }
    struct sockaddr_in myad;
    bzero(&myad, sizeof(myad));
    myad.sin_family =AF_INET;
    myad.sin_port =htons(8888);
    myad.sin_addr.s_addr = htonl (INADDR_ANY);
 
    int ret = bind(sfd, (struct sockaddr *)&myad, sizeof(myad));
    if (ret<0) {
        printf("bind error/n");
        return -1;
    }
    listen( sfd,128);  

    //把连接的客户端的地址打出来
    struct sockaddr_in clientad;
    bzero(&clientad, sizeof(clientad));
    clientad.sin_family =AF_INET;
    clientad.sin_port =htons(8888);
    socklen_t clilen = sizeof(clientad);
    //有客户连接啦
    int newfd= accept(sfd,(struct sockaddr*)&clientad,&clilen);
    char* str = {0};
    str = inet_ntoa(clientad.sin_addr);
   printf("请求连接的客户网络地址是%s\n",str);
 
return 0;
}
3.2.1.2   inet_ntop 函数

#include <arpa/inet.h>

       const char *  inet_ntop  (int af,   const void *src,    char *dst, socklen_t size);

 将网络地址结构体src ,转化为字符串,复制到dst指针中。dst必须不是NULL

看一下这篇文章最后的代码

用到了inet_ntop函数

char addstring[128];
    memset(addstring, 0x00,128);
     printf("服务器端,get connect,客户端地址是:\n");
    printf("IP:%s,PORT: %d\n", inet_ntop(AF_INET, &dst.sin_addr.s_addr,addstring,sizeof(addstring)), ntohs(dst.sin_port));

 

3.2.2 结果在传出参数里 

还没找到

3.3 本机字节序  -- 》 网络字节序相互转化

。。后续补充 

3.4 废弃的3个函数

网络地址结构体,这个结构体里唯一成员(32位无符号整型网络地址)来回转换的3个函数

in_addr_t     inet_lnaof  (struct in_addr   in);

将in 结构体里的一部分 ---本地网络地址返回,格式是本机字节序。

in_addr_t     inet_netof  (struct in_addr   in);

将in 结构体里的一部分 ---网络号码返回,格式是本机字节序。

??? 难道这个in里面不就一个成员吗

struct    in_addr    inet_makeaddr (in_addr_t net,    in_addr_t host);

为啥废弃了呢:在传统x86架构的电脑里(大家用的都是吧) ,主机字节序是小端Least Significant Byte first (little endian) ,最没地位的字节站最前面

网络字节序是大端(big endian) Most Significant Byte first 最重要的字节最前面

这三个函数是跟过去的A B C 三类IP地址相关的。

A类IP 地址:一个重要的字节当网络地址  ,剩下三个字节当本地的机器们的地址。最重要的1个二进制,值是  0 

B类IP 地址: 2个重要的字节当网络地址  ,剩下2个字节当本地的机器们的地址。最重要的2个二进制的1  0 

C类IP 地址: 3个字节当网络地址  ,1个字节当本地的机器们的地址。最重要的3个二进制位,值是 11 0 

传统的这个模式太死板了,现在已经是CIDR (无类别间域路由))

4.例子解析

EXAMPLES
       The program below demonstrates the use of inet_pton() and inet_ntop(3).  Here are some example runs:

           $ ./a.out i6 0:0:0:0:0:0:0:0
           ::
           $ ./a.out i6 1:0:0:0:0:0:0:8
           1::8
           $ ./a.out i6 0:0:0:0:0:FFFF:204.152.189.116
           ::ffff:204.152.189.116

   Program source

       #include <arpa/inet.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>

       int
       main(int argc, char *argv[])
       {
           unsigned char buf[sizeof(struct in6_addr)];
           int domain, s;
           char str[INET6_ADDRSTRLEN];
if (argc != 3) {
               fprintf(stderr, "Usage: %s {i4|i6|<num>} string\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           domain = (strcmp(argv[1], "i4") == 0) ? AF_INET :
                    (strcmp(argv[1], "i6") == 0) ? AF_INET6 : atoi(argv[1]);

           s = inet_pton(domain, argv[2], buf);
           if (s <= 0) {
               if (s == 0)
                   fprintf(stderr, "Not in presentation format");
               else
                   perror("inet_pton");
               exit(EXIT_FAILURE);
           }

           if (inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == NULL) {
               perror("inet_ntop");
               exit(EXIT_FAILURE);
           }

           printf("%s\n", str);
 exit(EXIT_SUCCESS);
       }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1420596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于MyBatis和JVM的最常见的十道面试题

ORM项目中类属性名和数据库字段名不一致会导致什么问题&#xff1f;它的解决方案有哪些&#xff1f; 在ORM项目中&#xff0c;如果类的属性名称和数据库字段名不一致会场导致插入、修改时设置的这个不一致字段为null&#xff0c;查询的时候即使数据库有数据&#xff0c;但是查…

Jenkins如何从GIT下拉项目并启动Tomcat

一、先添加服务器 二、添加视图 点击控制台输出&#xff0c;滑到最下面&#xff0c;出现这个就说明构建成功了&#xff0c;如果没有出现&#xff0c;说明构建有问题&#xff0c;需要解决好问题才能启动哦~

Python 九九乘法表的7种实现方式

Python 九九乘法表的7种实现方式 九九乘法表是初学者学习编程的必要练手题目之一&#xff0c;因此各种语言都有对应的实现方式&#xff0c;而 Python 也不例外。在 Python 中&#xff0c;我们可以使用多种方式来生成一个简单的九九乘法表。 实现方式一&#xff1a;双重循环 f…

使用 Node.js 和 Cheerio 爬取网站图片

写一个关于图片爬取的小案例 爬取效果 使用插件如下&#xff1a; {"dependencies": {"axios": "^1.6.0","cheerio": "^1.0.0-rc.12","request": "^2.88.2"} }新建一个config.js配置文件 // 爬取图片…

Android T 远程动画显示流程(更新中)

序 本地动画和远程动画区别是什么? 本地动画&#xff1a;自给自足。对自身SurfaceControl矢量动画进行控制。 远程动画&#xff1a;拿来吧你&#xff01;一个app A对另一个app B通过binder跨进程通信&#xff0c;控制app B的SurfaceControl矢量动画。 无论是本地动画还是远程…

F5负载均衡有何技术优势?为你详细解读

当今数字化时代&#xff0c;网络应用的性能对于企业的成功至关重要。负载均衡建立在现有网络结构之上&#xff0c;提供了有效的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。F5负载均衡技术则成为了许多企业实现高可用性和高…

原生table样式

HTML <div><table style"width: 100%;"><thead><tr><th style"width:25%;">董事会</th><th style"width:25%;">监事会</th><th style"width:25%;">股东</th><th sty…

物理信息神经网络PINN2024最新改良方案汇总(含复现代码)

传统的数值方法在处理复杂问题时可能需要大量的计算资源和时间&#xff0c;而改良后的PINN可以通过更有效的算法减少计算成本&#xff0c;使得求解过程更加高效。 在写论文时&#xff0c;我们也可以通过改进PINN减少数据需求、加速模型收敛、提高预测准确性、增强可解释性&…

linux -- 内存管理 -- SLAB分配器

SLAB分配器&#xff08;slab allocator&#xff09; SLAB分配器用于小内存空间管理&#xff0c;基本思想是&#xff1a;先利用页面分配器分配出单个或多个连续的物理页面&#xff0c;然后再此基础上将整块页面分割为多个相等的小内存单元&#xff0c;来满足小内存空间分配的需…

kerberos+kafka(2.13)认证(单节点ubuntu)

一&#xff1a;搭建kerberos。 1. 运行安装命令 apt-get install krb5-admin-server krb5-kdc krb5-user krb5-config2. 检查服务是否启动。 systemctl status krb5-admin-server systemctl status krb5-kdcsystemctl start krb5-admin-server systemctl startkrb5-kdc3. 修…

网络安全知识和华为防火墙

网络安全 网络空间安全 ---Cyberspace 2003年美国提出的网络空间概念 ---一个由信息基础设施组成的互相依赖的网络。 我国官方文件定义&#xff1a;网络空间为继海、陆、空、天以外的第五大人类互动领域。 通信保密阶段 --- 计算机安全阶段 --- 信息系统安全 --- 网络空间安…

校园教学气象站是什么

TH-XQ3在当今社会&#xff0c;气象科学的重要性日益凸显。它不仅关系到农业、交通、航空等多个领域的安全&#xff0c;更对人类的生活产生深远影响。因此&#xff0c;许多学校纷纷开设气象学相关课程&#xff0c;帮助学生了解气象知识&#xff0c;培养他们的科学素养。而在这其…

【数据结构:顺序表】

文章目录 线性表顺序表1.1 顺序表结构的定义1.2 初始化顺序表1.3 检查顺序表空间1.4 打印1.5 尾插1.6 头插1.7 尾删1.8 头删1.9 查找1.10 指定位置插入1.11 删除指定位置数据1.12 销毁顺序表 数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在一…

termux 玩法(一)

termux基础 termux基础玩法推荐国光写的手册&#xff1a;Termux 高级终端安装使用配置教程 | 国光 (sqlsec.com) termux安装 个人使用F-Droid安装的termux&#xff1a;Termux | F-Droid - Free and Open Source Android App Repository 基础知识 这些基础知识简单了解一下…

HDFS Federation前世今生

一 背景 熟悉大数据的人应该都知道&#xff0c;HDFS 是一个分布式文件系统&#xff0c;它是基于谷歌的GFS实现的开源系统&#xff0c;设计目的就是提供一个高度容错性和高吞吐量的海量数据存储解决方案。在经典的HDFS架构中有2个NameNode和多个DataNode&#xff0c;如下 从上面…

【C/C++ 02】希尔排序

希尔排序虽然是直接插入排序的升级版本&#xff0c;和插入排序有着相同的特性&#xff0c;即原始数组有序度越高则算法的时间复杂度越低&#xff08;预排序机制&#xff09;&#xff0c;但是是不稳定排序算法。 为了降低算法的时间复杂度&#xff0c;所以我们需要在排序之前尽…

3D效果图加树进去太卡,渲染太慢怎么办?

周末的时候&#xff0c;有个朋友私信来问&#xff1a;3dmax模型加树进去打开时特别的卡&#xff0c;是怎么回事。 不知道有没有朋友遇上这么个情况。 3dmax加树建议就用代理&#xff0c;这样相比于直接加而言&#xff0c;会流畅许多。 在3D效果图中&#xff0c;“树代理”是…

计网Lesson11 - 虚拟机网络环境及socket概述

文章目录 虚拟机的简述socket概述 虚拟机的简述 放张图在这&#xff0c;根本没明白是啥对啥&#xff0c;以后学了Linux再来吧 &#x1f626; socket概述 s o c k e t socket socket 是一种用于应用层的用户态与应用层以下的内核态交互的工具&#xff0c;本意为“插座”。 也就是…

AI新工具(20240130) Code Llama 70B-开源代码生成模型;海螺问问

Code Llama 70B-开源代码生成模型 Code Llama 70B是一个大型语言模型&#xff0c;通过对自然语言指令进行微调&#xff0c;可以生成有用且安全的答案。它提供了三个版本&#xff0c;分别是基础代码模型、专门针对Python的版本&#xff0c;以及针对理解自然语言指令进行微调的版…

电气自动化行业,全面数字化工作流程

电气自动化行业数字化转型所需流程软件&#xff0c;与大家分享如下&#xff1a; D-Hub企业数字化协同平台、SuperHarness数字线束软件、SuperPanel母排设计软件、D-Hub生产管理系统&#xff0c;全面的数字化工作流程&#xff0c;智能降本增效&#xff01; D-Hub D-Hub是一款…