我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【网络层+数据链路层】深入理解IP协议和MAC帧协议的基本原理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【网络层+数据链路层】深入理解IP协议和MAC帧协议的基本原理

文章目录


前言

为什么经常将TCP/IP放在一起呢?这是因为IP层的核心工作就是通过IP地址来定位主机的,具有将一个数据报从A主机跨网络发送到B主机的能力,而TCP所提供的策略使IP层可靠的将一个数据报从A主机跨网络发送到B主机。

网络层作用:

在复杂的网络环境中确定一个合适的路径。

网络层主要负责地址管理和路由选择,例如在IP协议中,通过IP地址来标识一台主机,并通过路由表的方式规划出两台主机之间的数据传输的线路(路由),路由器工作在网络层。


一、IP协议

 1.路径选择中,目的IP非常重要,决定了我们的路径该如何走。

 2. ip = 目标网络 + 目标主机 (先有一个概念:ip地址被划分为目标网络和目标主机,ip地址是支撑我们在路上路由的。)

主机:配有ip地址    路由器:配有ip地址并且可以进行路由控制    节点:主机和路由器的统称

1.IP的协议报头

 我们之前说过,要学习协议首先要弄明白两个问题:

如何将报头和有效载荷分离?

如何交付?

 如上图,除了数据(数据就是我们经常说的有效载荷)都是报头,而选项一般不关心,所以IP的标准长度报头是20字节。

4位首部长度:4位首部长度的基本单位是4字节,表示IP报头的总长度问题。4位首部长度在TCP的报头中也有。既然是4位首部长度那么在0000 ~ 1111也就是【0,15】然后乘4->【0,60】

又因为标准长度报头是20字节,所以IP数据包的报头长度是【20,60】最小20字节,最大60字节,其中的40字节供IP选项使用。设4位首部长度为x,x*4 = 20,得到四位首部长度是5,二进制表示也就是0101.

16位总长度:代表了IP报文的总长度(也就是包头和数据包),由于占用其16个比特位所以IP数据包的最大值为65536,用16位总长度减去报头长度就是有效载荷的长度,这样我们就将报头和有效载荷分离了。

当我们做到将有效载荷和报头分离后,就该思考如何向上交付了。

8位协议:向上交付的时候如何知道自己交付的到底是TCP协议还是UDP协议呢?就是通过8位协议来控制的,所以这个字段表示IP下一步应当把这个数据包发往更高层的协议,如TCP为6,UDP为17.

16位首部校验和:对整个IP报头进行校验,如果校验不通过会直接将这个数据包丢弃。

8位生存空间:数据包到达目的地的最大报文跳数,这个字段主要是用来防止出现路由循环。因为数据包会在网络环境中从一个节点跳到另一个节点,每次跳都会减小生存时间,当时间减为0还没到目标主机这个报文就会被丢弃。

32位源IP地址:当报文从主机跳到路由器时,路由器怎么知道你从哪来呢?所以32位源IP地址表示发送端。

32位目的IP地址:源IP会在路由中多次改变,而目的IP只有一个,就像西游记中唐僧的最终目标是西天,代表目的IP。在从黑风岭到女儿国时,源IP就变成了黑风岭,但是目的IP还是西天。

4位版本:一般是IPV4。

8位服务类型:一般用于实现QoS的要求,我们现在一般捕获到的数据包中此值为一缺省值。

2.网段划分

网段划分是什么?为什么要网段划分?怎么做网段划分?

网段划分就是将IP地址分为两个部分,网络号和主机号。

网络号:保证相互连接的两个网段具有不同的标识。

主机号:在同一个网段内,主机之间具有相同的网络号,但是必须有不同的主机号。

网段划分可以大大提高数据包的查找和转发效率,比如中国有23个省,如果没有网段划分那么从北京发往西安的数据包就会依次将23个省遍历看哪个是西安,如果进行了网段划分那么直接查到这个数据包是发往西安的,直接转到西安即可。这就像大学中丢了学生证可以按照学号分辨你是哪个学院哪个专业哪个班级的。

所以互联网中的每一台主机都隶属于某一个子网,这是为了方便定位这个主机。这也就是为什么要有子网划分。

首先IP地址有32位,我们用前8位来标识各个国家,每个国家都有国际路由器所以每个国家内部都有自己的一套表示方式,比如再拿8个比特位表示中国的每一个省,所以IP地址就像我们的身份证一样。

不同的子网其实就是把网络号相同的主机放到一起. 如果在子网中新增一台主机, 则这台主机的网络号和这个子网的网络号一致, 但是主机号必须不能和子网中的其他主机重复. 通过合理设置主机号和网络号 , 就可以保证在相互连接的网络中 , 每台主机的 IP 地址都不相同 . 那么问题来了 , 手动管理子网内的 IP, 是一个相当麻烦的事情 . 有一种技术叫做DHCP, 能够自动的给子网内新增主机节点分配IP地址, 避免了手动管理IP的不便. 一般的路由器都带有DHCP功能. 因此路由器也可以看做一个DHCP服务器.

 如上图所示我们可以看到路由器这种设备必须至少桥接两个子网,所以路由器就必须既属于网段1,又属于网段2,而路由器也是一台主机,既然要属于两个网段,那么就必须在每个网段都有一个ip地址,一般路由器的ip都是网段标识.1。上图中我们可以把一个路由器构成的网络叫子网,当有很多这样的路由器并且我们把很多这样的路由器连接起来的时候可以叫公网。

划分方案CIDR

引入一个额外的子网掩码(subnet mask)来区分网络号和主机号; 子网掩码也是一个32位的正整数. 通常用一串 "0" 来结尾; 将IP地址和子网掩码进行 "按位与" 操作, 得到的结果就是网络号;

 一般在一个子网中,管理子网中IP的设备通常是路由器。目标网络和子网掩码,子网中的主机,都会被路由器管理。目标网络和子网掩码其实是在路由器内配置的。从上图中可以看到,网络号一般IP地址与子网掩码按位与后的结果,一般全0(.0)是网络号,全1(.255)是广播号.

例子一眼就能看出来,下面我们把例子2算一下:

 为什么子网掩码前面24个比特位是全1呢?因为前24个比特位是网络号,如果将网络号都修改了那么还怎么找呢从.65~.78就是所有能使用的主机号。

特殊的IP地址

将IP地址中的主机地址全部设为0, 就成为了网络号, 代表这个局域网; 将IP地址中的主机地址全部设为1, 就成为了广播地址, 用于给同一个链路中相互连接的所有主机发送数据包; 127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1

也就是说2的32次方个IP不是都是在公网使用的,还有一些特殊的IP地址,比如127.0.0.1就是本地环回。

IP地址的数量限制

我们知道 , IP 地址 (IPv4) 是一个 4 字节 32 位的正整数 . 那么一共只有 2 32 次方个 IP 地址 , 大概是 43 亿左右 . TCP/IP协议规定, 每个主机都需要有一个 IP 地址 . 这意味着 , 一共只有 43 亿台主机能接入网络么 ? 实际上 , 由于一些特殊的 IP 地址的存在 , 数量远不足 43 亿 ; 另外 IP 地址并非是按照主机台数来配置的 , 而是每一个网卡都需要配置一个或多个IP 地址 . CIDR 在一定程度上缓解了 IP 地址不够用的问题 ( 提高了利用率 , 减少了浪费 , 但是 IP 地址的绝对上限并没有增加 ), 仍然不是很够用. 这时候有三种方式来解决: 动态分配IP地址: 只给接入网络的设备分配IP地址. 因此同一个MAC地址的设备, 每次接入互联网中, 得到 的IP地址不一定是相同的; NAT技术(后面会重点介绍); IPv6: IPv6并不是IPv4的简单升级版. 这是互不相干的两个协议, 彼此并不兼容; IPv6用16字节128位来表 示一个IP地址; 但是目前IPv6还没有普及;

私有IP地址和公网IP地址

如果一个组织内部组建局域网 ,IP 地址只用于局域网内的通信 , 而不直接连到 Internet , 理论上使用任意的 IP 地址都可以, 但是 RFC1918 规定了用于组建局域网的私有 IP 地址如下: 10.*, 前8位是网络号,共16,777,216个地址。 172.16.到172.31.,前12位是网络号,共1,048,576个地址。 192.168.*,前16位是网络号,共65,536个地址。 包含在这个范围中的, 都成为私有IP, 其余的则称为全局IP(或公网IP)。 一个路由器可以配置两个IP地址, 一个是WAN口IP, 一个是LAN口IP(子网IP). 路由器LAN口连接的主机, 都从属于当前这个路由器的子网中. 不同的路由器, 子网IP其实都是一样的(通常都是192.168.1.1). 子网内的主机IP地址不能重复. 但是子网之间的IP地址就可以重复了. 每一个家用路由器, 其实又作为运营商路由器的子网中的一个节点. 这样的运营商路由器可能会有很多级,最外层的运营商路由器, WAN口IP就是一个公网IP了. 子网内的主机需要和外网进行通信时, 路由器将IP首部中的IP地址进行替换(替换成WAN口IP), 这样逐级替换, 最终数据包中的IP地址成为一个公网IP. 这种技术称为NAT(Network Address Translation,网络地址转换). 如果希望我们自己实现的服务器程序, 能够在公网上被访问到, 就需要把程序部署在一台具有外网IP的服务器上. 这样的服务器可以在阿里云/腾讯云上进行购买.

路由

在复杂的网络结构中,找出一条通往终点的路线。 IP 数据包的传输过程也和问路一样 . IP 数据包 , 到达路由器时 , 路由器会先查看目的 IP; 路由器决定这个数据包是能直接发送给目标主机 , 还是需要发送给下一个路由器 ; 依次反复 , 一直到达目标 IP 地址 ;

路由的过程就是通过目标ip获取目标主机所在的子网,所以在查找的时候一定会有一张路由表供我们查找,如下图:

路由表可以使用route命令查看

如果目的IP命中了路由表, 就直接转发即可;

路由表中的最后一行 , 主要由下一跳地址和发送接口两部分组成 , 当目的地址与路由表中其它地址都不匹配时, 就按缺省路由条目规定的接口发送到下一跳地址。

 下面我们查看一下路由表:

 首先destination表示目标网络,GateWay表示下一跳路由器,Genmask表示子网掩码(前面说过,每一个子网都必须有目标网络号和匹配的子网掩码),Flags就是标志,U后面的G表示默认网关也叫缺省路由,当目的ip在路由表查不到是就会进入缺省路由,Iface表示服务器和路由器的哪个接口连接。

这个目的地址例子不够多,我们用一个多的例子来演示:

这台主机有两个网络接口,一个网络接口连到192.168.10.0/24网络,另一个网络接口连到 192.168.56.0/24网络; 路由表的Destination是目的网络地址,Genmask是子网掩码,Gateway是下一跳地址,Iface是发送接 口,Flags中的U标志表示此条目有效(可以禁用某些 条目),G标志表示此条目的下一跳地址是某个路由器的地址,没有G标志的条目表示目的网络地址是与本机接口直接相连的网络,不必经路由器转发; 转发过程例1: 如果要发送的数据包的目的地址是192.168.56.3 跟第一行的子网掩码做与运算得 到192.168.56.0,与第一行的目的网络地址不符 再跟第二行的子网掩码做与运算得 到192.168.56.0,正是第二行的目的网络地址,因此从eth1接口发送出去; 由于192.168.56.0/24正是与eth1接口直接相连的网络,因此可以直接发到目的主机,不需要经路由器转发; 转发过程例2: 如果要发送的数据包的目的地址是202.10.1.2 依次和路由表前几项进行对比, 发现都不匹配; 按缺省路由条目, 从eth0接口发出去, 发往192.168.10.1路由器; 由192.168.10.1路由器根据它的路由表决定下一跳地址

当有一个数据包进入路由器后,首先拿数据包中的目的地址和路由表的第一个网络号的子网掩码按位与,按位与后就能确定该报文要去的目标网络,假如第二个192.168.56.0就是目标网络,当我们将按位与的结果和Destination做匹配时发现第二个就是我们要找的目标网络,这个时候直接通过eth1接口将数据包转发到192.168.56.0这个网络号的路由器,这就是我们上图中路由中一跳的实际过程。

假如现在进入路由器的数据包是202.10.1.2,遍历路由表和每个网络号的子网掩码按位与后发现都没有匹配的网络号,这个时候就会将数据包转到default也就是默认网关192.168.10.1,通过eth0接口发送。

下面我们讲解IP报头中剩下的三个部分:

要了解这三个标识,就要了解数据链路层,我们在路由器之间传递的确实是IP报文,但是在网线中跑的确是数据链路层的MAC帧,而在MAC帧协议中规定,自己的有效载荷不能超过1500字节(MTU最大传送单元,可以修改)。而把数据包给数据链路层的就是IP层,也就是说IP层必须将发送给MAC帧的数据大小控制在1500字节以内,这1500字节包括IP的报头,那么如何控制呢?实际上就是分片与组装,将原来超过1500字节的报文经过分片不就将每个报文控制在1500字节以内了吗,所以上图中这三个部分就是支持IP的分片与组装的,下面我们演示一下这个过程:

首先分片与组装是由IP层协议完成的,所以TCP协议,MAC帧协议都不会关心原来的报文是否被分片,这就是IP层协议自己的行为。注意:分片与组装不是主流!!!

下面我们根据组装与分片的四个问题来讲解上图中三个部分的作用:

如何知道一个报文被分片?

如何识别同一个报文的分片?

哪个分片是第一个,哪个分片是最后一个?有没有收全或者丢失?

哪个在前?哪个在后?如何正确的进行组装?

怎么保证合起来的报文是正确的?

16位标识:主机发送报文的唯一标识,如果IP报文在向数据链路层发送的时候被分片了,那么每一个片的16位标识ID都是相同的。

也就是说1个报文如果被分为3片,那么这3片报文中的16位标识都是相同的。这就解决了第二个如何识别一个报文的分片问题。

3位标志字段:第一位保留(保留的意思是现在还用不到第一位)。第二位为1表示禁止分片,这个时候如果报文长度超过MTU,则IP模块会直接将此报文丢弃。第三位表示更多分片,比如一个报文被分了3片,第一片的第三个标志位为1,其他标志位为0,第二片的第三个标志位为1其他为0,第三片的第三个标志位为0,其他标志位为1,第三片类似于一个结束标记,也就是说可以知道被分片的报文的结束。也就是说第三个标志位的意思是:如当前报文后面还有分片,那么第三个标志位为1,如果当前报文就是最后一个分片,那么第三个标志位为0作为一个结束位置。注意:被分片的每个报文前面都会加上IP报头。

由3位标志字段中的第三个字段可以得知一个报文是否被分片(如果第三个字段为1说明被分片),第三个字段可以得知哪个报文是分片的最后一个。

13位片偏移:分片相对于IP原始报文开始处的偏移,也可以理解为当前分片在原IP报文中的位置,实际偏移的字节数是这个值*8得到的,因此除了最后一个报文之外,其他报文的长度必须是8的整数倍(否则报文就不连续了)。

确定分片第一个很简单,只需要看3位标志字段中的第三位是否为1,并且13位片偏移量为0,如果满足第三位为1并且偏移量为0则是第一个分片。

要确定最后一个分片,只需要看3位标志字段的第三位是否为0,并且13位片偏移量大于0.

而我们组装这个报文也很简单,只需要按照片偏移进行升序排序,就可以将分片的报文组装起来。

对于第三个问题中的如何知道分片的报文收全或者丢失,实际上我们保证不了,但是组装之后我们可以进行简单的判断,只需要遍历每个报文看当前的起始位置+自身长度是否等于下一个报文中填充的偏移量大小。

如何保证合起来的报文是正确的呢?还记得我们IP报头中的16首部校验和和TCP报头中的16位首部校验和吗?16位首部校验和是使用CRC校验来鉴别头部是否损坏的。校验后如果发现报文头部损坏则直接丢弃。

分片是不好的,因为将一个报文拆成了多个,任意一个报文丢失就会造成拼接组装失败。一旦组装失败就会重发整个报文(对于TCP来讲是不知道IP如何分片的,所以重发的时候只能整个报文重新发送)。

下面我们自己分一下片:

 首先传输层TCP发了3000字节的报文给IP层,IP层对数据添加报头变成3020字节,然后我们以1500字节为一片进行分片,每一片都添加IP层的报头:

 如上图,第一次直接1500字节分片因为本身就有报头,第二次只能拿1480字节的数据,因为还有20字节作为IP报头,第三次拿最后40字节的数据,加上20字节的IP报头是60字节,最后组装的时候去掉报头就是1480 + 1480 +40刚好是TCP发送的3000字节的报文。

二、MAC帧协议

前面我们说过,因为IP是在网络层,IP报文是在路由器中跑的,当我们要拿目的IP去路由器中查找网络号的时候就是用的IP报文,而在网线中传输是在数据链路层,跑的实际上是MAC帧。我们之前说过IP提供了一种从A主机跨网络传输到B主机的能力,这个能力是通过目的IP + 子网划分 + 路由来完成的,但是要把数据跨网络传输到主机B,就得先将数据交给与主机A相连的下一跳主机(也叫节点),如下图:

 主机A要想给主机B发消息,首先要将数据发送给与主机A相连的下一跳节点(路由器A),而主机A要想发送数据给路由器A的前提一定是主机A和路由器A在同一个网段,所以我们所看到的跨网络传输的本质就是由无数个局域网(子网)转发的结果。

所以我们想要彻底理解跨网络转发就首先要理解局域网中报文的转发原理,而局域网中两个主机的通信就必须认识数据链路层的以太网协议。

1.以太网

"以太网" 不是一种具体的网络, 而是一种技术标准; 既包含了数据链路层的内容, 也包含了一些物理层的内容. 例如: 规定了网络拓扑结构, 访问控制方式, 传输速率等; 例如以太网中的网线必须使用双绞线; 传输速率有10M, 100M, 1000M等; 以太网是当前应用最广泛的局域网技术; 和以太网并列的还有令牌环网, 无线LAN等

之前我们将局域网的时候说过,在同一个局域网的主机是可以直接进行通信的,并且在同一个局域网的每个主机必须有自己唯一的标识符。

2.以太网帧(MAC帧)格式报头

首先MAC帧协议的报头是用蓝色圈出来的地方,分别是6位目的地址,6位源地址,2位类型,4位CRC校验校验码。

前面我们说过,学习协议首先理解两点:

MAC帧协议如何将报头和有效载荷分离?

MAC帧协议采用定长策略,前14位后4位都是固定的,所以可以直接将报头和有效载荷分离。

如何向上交付?

 还记得IP报头中的8位协议吗?8位协议可以知道上层交付的是TCP还是UDP,而我们的MAC帧协议也是这样解决的,在报头的2位帧协议类型中,可以确定上层交付的是什么类型。比如0800代表上层是IP数据报,其次还有ARP,RARP数据报。

还记得我们刚刚说局域网中的主机必须有唯一标识吗?我们的每个主机都有网卡,每张网卡都有唯一的一个sn码,这个sn码就是这个网卡的MAC地址,这个MAC地址在全球范围内具有唯一性。

那么我们如何查询自己的mac地址呢?通过ifconfig命令:

 ether的翻译就有以太的意思,后面就是MAC地址。

3.基于协议讲解局域网转发的原理

首先m1这个主机给m8发送了一个数据,这个数据是从应用层添加报头再到传输层添加报头在到网络层IP添加报头最后在数据链路层添加MAC帧报头,然后在MAC帧的报头中的目的地址是主机m8的MAC地址,因为从m1主机发出所以源地址是m1主机的mac地址,交付的时候上层协议为IP,所以类型是0800,这条消息发出后整个局域网的所有主机都会受到这条消息,但是每个主机都会对这条消息进行报头和有效载荷的分离,拿到报头后拿自己的MAC地址和报头的MAC地址对比,如果是发给自己的就将有效载荷向上交付,如果不是自己的则直接会被丢弃,而上层是不知道主机收到了这条消息并且将消息丢弃的。

 当m8主机收到m1主机发来的消息后,然后给m1主机响应,期间也是从应用层到数据链路层封装最后变成一个MAC帧,只不过MAC帧中的目的地址变成了m1,源地址变成了m8(因为是从m8主机发出),消息发出后同样局域网内的每个主机都会收到m8主机发送给m1主机的响应,但是最后只有m1主机保留这条消息。

 明白了上面的原理我们应该可以认识到局域网本质实际上就是临界资源, 这个资源是被所有局域网内的主机共享的,而在局域网中,任何时刻只允许一个主机发送消息,如果多个消息被同时发送,就会导致局域网内的数据发生碰撞。所以一个局域网就是一个碰撞域。那么如何让任何时刻只允许一个主机发送消息呢?这就要看网络策略的实现了,比如令牌环网中在一个局域网内只有获得令牌的主机才能发送消息,这就像锁一样。而以太网是依靠主机的碰撞检测和碰撞避免算法来实现的,并且由于光电传播非常快所以一个时刻产生碰撞的概率并不高,除非一个局域网内的主机非常多,但是我们学局域网都知道一个局域网内的主机并不会很多,这就像家里的WiFi,如果很多人连接使用就会很卡,只有两三个人用就不担心卡顿问题。

当然解决碰撞问题还有一个有效的办法就是交换机:

 交换机的作用就是,当m1给m6发送消息的时候m2给m1发送消息造成碰撞,这个时候交换机检测到左边发生碰撞那么这个时候就不会将左侧的消息转发到右侧直接将消息丢弃(如果将左侧碰撞的消息发送到右侧就会影响右侧的主机,右侧的主机都会触发碰撞检测和碰撞避免算法)。如果左侧没有发生碰撞并且m1要向m8发送消息,这个时候消息到交换机这里交换机就会将消息转发到右侧。

来源地址:https://blog.csdn.net/Sxy_wspsby/article/details/131997388

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【网络层+数据链路层】深入理解IP协议和MAC帧协议的基本原理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录