数据链路层在物理层之上,属于计算机网络的低层,其最基本的服务是将源自物理层来的数据可靠地传输到相邻节点的目标机网络层。
使用的信道主要为:
点对点信道:使用点对点通信方式
广播信道:信道上连接许多主机组成局域网,需要使用专用的协议来进行协调。
数据链路(也有称逻辑链路)(data link):在一条物理线路上添加必要的通信协议来控制数据的传输(包括硬件和软件),常用网络适配器(网卡)实现。
帧(frame):数据链路层的协议数据单元。
图4. 1使用点对点信道的数据链路层
①A的数据链路层把网络层的IP数据报添加首部、尾部封装成帧。
②A将帧发送到B数据链路层。
③B检查,无差错则上报网络层,否则丢弃。
数据链路层不必考虑物理层如何实现比特传输的细节。甚至还可以更简单地设想好像是沿着两个数据链路层之间的水平方向把帧直接发送到对方。
根据以上的步骤,主要有封装成帧,透明传输,差错检测三问题。
封装成帧(framing)就是在一段数据的前后分别添加首部和尾部,然后就构成了一个帧。确定帧的界限,首尾的一个重要作用就是进行帧定界。
图4. 2用帧首部和尾部封装成帧
帧 = 首部 + IP数据报(来源于网络层) + 尾部
MTU(Maximum Transfer Unit):数据部分的最长长度
2.透明传输
"透明"很生动,就是说不管数据部分是什么,都不受限制。
为什么会受到限制?比如说传输的数据有一部分跟帧首部一模一样,那么就分不清哪里是首部了,传输的数据就会受到影响,所以说需要想办法解决这个问题。
3.差错检测
衡量标准:误码率BER(Bit Error Rate) = 传输错误比特 / 总比特
解决方案:循环冗余检验CRC(Cyclic Redundancy Check):发送方在数据后面添加n(一般为16,32)位测序列FCS(Frame Check Sequence),通过除法运算得出,如果传输中没有出现差错,那么余数为0,否则表示出错,就会丢弃。这种方式可以能够实现无比特差错(接收到的数据没有差错)的传输,但不是可靠传输(发送了什么就接到什么)。
图4. 3循环冗余检验CRC
对于点对点的链路,目前使用得最广泛的数据链路层协议是点对点协议 PPP (Point-to-Point Protocol)。用户使用拨号电话线接入互联网时, 用户计算机和ISP进行通信时所使用的数据链路层协议就是PPP协议。
PPP协议应当满足:简单、具备封装成帧、透明传输、差错检测功能、支持多种网络层协议、支持多种类型链路。
图4. 4用户到ISP的链路使用PPP协议
①封装帧。将IP数据报封装到串行链路的方法
②链路控制协议LCP(Link Control Protocol)。用于建立、配置、测试数据链路。
③网络控制协议NCP(Network Control Protocol)。支持多种网络层协议。
①内容
图4. 5PPP帧
F(Flag),01111110=0x7E:标志帧的开始
A,C:暂无定义。11111111=0xFF 00000011=0x03
协议: IP数据报: 00000000 00100001 = 0x0021
LCP: 11000000 00100001 = 0xC021
NCP: 10000000 00100001 = 0x8021
FCS:CRC的帧检测序列
②实现透明传输
定义好了帧格式,需要解决透明传输问题,不然信息与定义的字段一致就乱起来了。那么PPP协议怎么解决的呢?有俩方法。
将原来信息字段中出现的特殊字节转变为新的更多的字节组合。
表4. 1字节填充
|
原数据 |
新数据 |
|
F(01111110=0x7E) |
0x7D,0x5E |
|
0x7D |
0x7D,0x5D |
|
小于00100000=0x20的ASCII字符 |
前面填充0x7D,并改变该字符编码 |
接收方进行反变换后即可回复信息
在发送端,只要发现有5个连续1,则立即填入一个0。接收端对帧中的比特流进行扫描。每当发现5个连续1时,就把这5个连续1后的一个0删除。
图4. 6零比特的填充与删除
PPP协议已不是纯粹的数据链路层的协议,它还包含了物理层和网络层的内容。
图4. 7PPP协议实验图
在图中的网络中Router2发送给下一个Router的为PPP协议帧,截获后发现该信息帧格式与前述一致。
图4. 8路由器截获的PPP协议帧
广播信道进行一对多的通信,典型应用为局域网,下面说说局域网的数据链路层。
局域网:网络为一个单位拥有,地理范围和站点数目有限。局域网的优点是,具备广播功能,从一个站点可以访问全网;便于系统的扩展和逐渐地演变,各设备的位置可灵活调整和改变;提高了系统的可靠性、可用性和残存性。
主要有这么几种拓扑结构:


图4. 9局域网的拓扑结构
从上面的结构可以看出,局域网中计算机共享信道,因此 需要有一个合理的分配方式。包括两种:
(1)静态划分信道:把信道分配给用户(频分、时分、波分、码分复用),可能造成浪费,且代价较高,不适宜局域网。
(2)动态媒体接入控制/多点接入(multiple accese):在用户需要的时候才占用信道,更节省资源。包括①随机接入:用户随机发消息,要是同时发送就会碰撞,发送失败。②受控接入(使用较少),用户服从控制发送信息,例如多点线路探询(polling)/轮询。
注意,以太网在局域网市场有绝对优势,因此以太网≈局域网。
以太网现在一般用DIX EthernetV2标准,IEEE 802.3是第一个IEEE的以太网标准,二者只有微小差别。
IEEE802将局域网的数据链路层拆为两个子层:
逻辑链路控制 LLC (Logical Link Control)子层,不管采用何种协议的局域网,对 LLC 子层来说都是透明的,现已作用不大,有些厂家适配器不安装LLC。
媒体接入控制 MAC (Medium Access Control)子层,与接入到传输媒体有关的内容都放在 MAC子层。
图4. 9局域网的数据链路层
PC上需要安装通信适配器(adapter),又称网络接口卡 NIC (Network Interface Card),或"网卡",网卡包括处理器、存储器,一般使用RJ-45接口。
适配器功能包括:进行串行/并行转换;对数据进行缓存;在计算机的操作系统安装设备驱动程序;实现以太网协议。
图4. 9计算机通过适配器和局域网通信
前面说过,由于局域网上的计算机共享信道,因此就需要一个分配方式进行协调,以太网采用CSMA/CD协议,即载波监听多点接入/碰撞监测(Carrier Sense Multiple Access with Collision Detection)进行协调。
多点接入:说明是总线型网络,计算机共享信道。
载波监听:发送前监听,发数据前看看总线上有无其他站发送数据。
碰撞检测:边发送边监听,发送中如果检测到碰撞,就停止发送,等待一段随机时间再发送。(因为信道中的信息传送需要时间,每个站在发送数据之后的一小段时间内,存在着遭遇碰撞的可能性所以发送的时候也要监听碰撞)
因为边发送边监听,不能同时发送和接收,只能进行半双工通信。同时发送具有一定的不确定性,使整个以太网的平均通信量远小于以太网的最高数据率。
这次再详细看使用广播信道的以太网
图4. 9使用集线器的双绞线以太网
集线器(hub)工作在物理层,仅简单地转发数据,不会碰撞检测,相当于一个多接口的转发器。
整个拓扑逻辑上是一个总线型网,站点中的适配器执行CSMA/CD协议,共享逻辑上的总线。
局域网中的硬件地址又称物理地址或MAC地址(硬件地址/物理地址):48位固化在适配器的ROM中的唯一地址,只有换了适配器才会变。
IEEE 的注册管理机构 RA 负责向厂家分配地址字段6个字节中的前三个字节(即高位 24 位),称为组织唯一标识符。地址字段6个字节中的后三个字节(即低位 24 位)由厂家自行指派,称为扩展唯一标识符,必须保证生产出的适配器没有重复地址。
图4. 9MAC地址的组成
适配器从网络上每收到一个 MAC 帧就首先用硬件检查 MAC 帧中的 MAC 地址。如果是发往本站的帧(有单播[1对1]、广播[1对全部]、多播[1对多]三种)则收下,然后再进行其他的处理。否则就将此帧丢弃,不再进行其他的处理。
图4. 9MAC帧
注意,以太网以帧为单位(PPP以字节为单位)传送数据,传送时帧之间有间隙,接收方找到帧开始的定界符,后面连续的比特流都属于一个MAC帧,所以不需要帧结束定界符,也不需要字节填充保证透明传输。
1)物理层扩展
以太网之间主机间距离不能太远,否则信号会衰减,简单的方法是使用光纤和光纤调制解调器,这样很容易使主机和几公里以外的集线器连接。
图4. 9主机使用光纤和一对光纤调制解调器连接到集线器
使用多个集线器可以形成更大范围的以太网。但造成两个问题:碰撞域增大,更容易信息碰撞;必须使用同一以太网技术(例如数据率要相同)。

图4. 9扩展以太网
2)数据链路层扩展
①网桥
网桥根据MAC帧的目的地址进行转发和过滤,不改变帧的原地址,转发给目的地址所在的接口。
有4个作用:过滤通信量,增大吞吐量:将碰撞域隔离开,从而每个碰撞域可以各自通信,总线上通信量减少,总吞吐量增加;提高可靠性;可互连不同物理层,不同,AC子层和不同速率的以太网;扩大了物理范围。
缺点:增加时延;适宜通信量不大,用户不多的情况,可能因广播过多产生网络拥塞。
②交换机(switch)
交换机实质上是一个多接口的网桥,一般具有十几个及以上接口,工作在数据链路层。其特点包括:
接口一般工作在全双工方式;
具有并行性,当主机需要通信的时候,交换机一可以同时连通许多对的接口,使每一对通信的主机像独占通信媒体一样,无碰撞地传输数据;
以太网交换机的接口有存储器,能在输出端口繁忙时把到来的帧进行缓存。
即插即用,其内部的帧交换表(又称为地址表)是通过自学习算法自动地逐渐建立起来的。自学习算法还结合了生成树协议STP,防止以太网帧兜圈,在packet tracer中建立一个由四个交换机连接成的环路,会发现交换机会自动断开一个连接口,详细就不介绍了。
使用了专用的交换结构芯片,用硬件转发,其转发速率要比使用软件转发的网桥快很多。
图4. 9用以太网交换机扩展局域网
100Mb/s以上速率的以太网为高速以太网。包括:
快速以太网100BASE-T:在双绞线传送100Mb/s基带信号,为星形拓扑。
G比特以太网:1Gb/s以下全双工/半双工工作
10G比特以太网(10GE):传输媒体为光纤,只半双工工作
40/100G比特以太网:目前最高传输速率,用于和核心路由器连接。
对于上网用户密集的楼宇,可选择宽带接入高速以太网。
图4. 9以太网接入举例——光纤到大楼FTTB
这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in
给定两个大小相等的数组,如何找到不考虑位置的匹配元素的数量?例如:[0,0,5]和[0,5,5]将返回2的匹配项,因为有一个0和一个5共同;[1,0,0,3]和[0,0,1,4]将返回3的匹配项,因为0有两场,1有一场;[1,2,2,3]和[1,2,3,4]将返回3的匹配项。我尝试了很多想法,但它们都变得相当粗糙和令人费解。我猜想有一些不错的Ruby习惯用法,或者可能是一个正则表达式,可以很好地回答这个解决方案。 最佳答案 您可以使用count完成它:a.count{|e|index=b.index(e)andb.delete_at
是否可以在不实际下载文件的情况下检查文件是否存在?我有这么大的(~40mb)文件,例如:http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm这与ruby不严格相关,但如果发件人可以设置内容长度就好了。RestClient.get"http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm",headers:{"Content-Length"=>100} 最佳答案
我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT
Ruby中如何“一般地”计算以下格式(有根、无根)的JSON对象的数量?一般来说,我的意思是元素可能不同(例如“标题”被称为其他东西)。没有根:{[{"title":"Post1","body":"Hello!"},{"title":"Post2","body":"Goodbye!"}]}根包裹:{"posts":[{"title":"Post1","body":"Hello!"},{"title":"Post2","body":"Goodbye!"}]} 最佳答案 首先,withoutroot代码不是有效的json格式。它将没有包