表示层(Presentation layer)
会话层(Session layer)
传输层(Transport layer)
网络层(Network layer)
数据链路层(Data link layer)
物理层(Physical layer)
其中上三层称之为高层,定义应用程序之间的通信和人机界面。什么意思呢,就是上三层负责把电脑能看懂的东西转化为你能看懂的东西,或把你能看懂的东西转化为电脑能看懂的东西。
下四层称之为底层,定义的是数据如何端到端的传输(end-to-end),物理规范以及数据与光电信号间的转换。
下面一层一层的来说明物理层
物理层是OSI/ISO的第一层,它虽然处于最底层,却是整个开放系统的基础。物理层为设备之间的数据通信提供传输媒体及互连设备,为数据传输提供可靠的环境。
物理层的主要功能
为数据端设备提供传送数据的通路,数据通路可以是一个物理媒体,也可以是多个物理媒体连接而成.一次完整的数据传输,包括激活物理连接,传送数据,终止物理连接.所谓激活,就是不管有多少物理媒体参与,都要在通信的两个数据终端设备间连接起来,形成一条通路。
传输数据.物理层要形成适合数据传输需要的实体,为数据传送服务.一是要保证数据能在其上正确通过,二是要提供足够的带宽(带宽是指每秒钟内能通过的比特(BIT)数),以减少信道上的拥塞。传输数据的方式能满足点到点,一点到多点,串行或并行,半双工或全双工,同步或异步传输的需要。完成物理层的一些管理工作。
物理层的一些重要标准
物理层的一些标准和协议早在OSI/TC97/C16 分技术委员会成立之前就已制定并在应用了,OSI也制定了一些标准并采用了一些已有的成果。下面将一些重要的标准列出,以便读者查阅。
ISO2110:称为"数据通信----25芯DTE/DCE接口连接器和插针分配"。它与EIA(美国电子工业协会)的"RS-232-C"基本兼容。
ISO2593:称为"数据通信----34芯DTE/DCE----接口连接器和插针分配"。
ISO4092:称为"数据通信----37芯DTE/DEC----接口连接器和插针分配"。与EIARS-449兼容。
CCITT V.24:称为"数据终端设备(DTE)和数据电路终接设备之间的接口电路定义表"。其功能与EIARS-232-C及RS-449兼容于100序列线上.
数据链路层
数据链路可以粗略地理解为数据通道。物理层要为终端设备间的数据通信提供传输媒体及其连接。媒体是长期的,连接是有生存期的。在连接生存期内,收发两端可以进行不等的一次或多次数据通信。每次通信都要经过建立通信联络和拆除通信联络两过程。这种建立起来的数据收发关系就叫作数据链路。而在物理媒体上传输的数据难免受到各种不可靠因素的影响而产生差错,为了弥补物理层上的不足,为上层提供无差错的数据传输,就要能对数据进行检错和纠错。数据链路的建立、拆除,对数据的检错、纠错是数据链路层的基本任务。
链路层的主要功能:
链路连接的建立,拆除,分离。
帧定界和帧同步。链路层的数据传输单元是帧。协议不同。帧的长短和界面也有差别,但无论如何必须对帧进行定界。
顺序控制。指对帧的收发顺序的控制。
差错检测和恢复。还有链路标识,流量控制等等.差错检测多用方阵码校验和循环码校验来检测信道上数据的误码,而帧丢失等用序号检测.各种错误的恢复则常靠反馈重发技术来完成。
数据链路层的主要协议
数据链路层协议是为发对等实体间保持一致而制定的,也为了顺利完成对网络层的服务。主要协议如下:
ISO1745--1975:"数据通信系统的基本型控制规程"。这是一种面向字符的标准,利用10个控制字符完成链路的建立,拆除及数据交换。对帧的收发情况及差错恢复也是靠这些字符来完成。
ISO1155, ISO1177, ISO2626, ISO2629等标准的配合使用可形成多种链路控制和数据传输方式。
ISO3309--1984:称为"HDLC 帧结构"。
ISO4335--1984:称为"HDLC 规程要素"。
ISO7809--1984:称为"HDLC 规程类型汇编"。这3个标准都是为面向比特的数据传输控制而制定的.有人习惯上把这3个标准组合称为高级链路控制规程。
ISO7776:称为"DTE数据链路层规程"。与CCITT X.25LAB"平衡型链路访问规程"相兼容。
链路层产品
独立的链路产品中最常见的当属网卡,网桥也是链路产品。MODEM的某些功能有人认为属于链路层,对些还有争议。数据链路层将本质上不可靠的传输媒体变成可靠的传输通路提供给网络层。在IEEE802.3情况下,数据链路层分成了两个子层,一个是逻辑链路控制,另一个是媒体访问控制。下图所示为IEEE802.3LAN体系结构。
AUI=连接单元接口 PMA=物理媒体连接
MAU=媒体连接单元 PLS=物理信令
MDI=媒体相关接
网络层
网络层的产生也是网络发展的结果.在联机系统和线路交换的环境中,网络层的功能没有太大意义.当数据终端增多时。它们之间有中继设备相连。此时会出现一台终端要求不只是与唯一的一台而是能和多台终端通信的情况,这就是产生了把任意两台数据终端设备的数据链接起来的问题,也就是路由或者叫寻径。另外,当一条物理信道建立之后,被一对用户使用,往往有许多空闲时间被浪费掉。人们自然会希望让多对用户共用一条链路,为解决这一问题就出现了逻辑信道技术和虚拟电路技术。
网络层主要功能
网络层为建立网络连接和为上层提供服务,应具备以下主要功能:
路由选择和中继
激活,终止网络连接
在一条数据链路上复用多条网络连接,多采取分时复用技术
差错检测与恢复
排序,流量控制
服务选择
网络管理
网络层的一些主要标准如下:
ISO.DIS8208:称为"DTE用的X.25分组级协议"
ISO.DIS8348:称为"CO 网络服务定义"(面向连接)
ISO.DIS8349:称为"CL 网络服务定义"(面向无连接)
ISO.DIS8473:称为"CL 网络协议"
ISO.DIS8348:称为"网络层寻址"
除上述标准外,还有许多标准。这些标准都只是解决网络层的部分功能,所以往往需要在网络层中同时使用几个标准才能完成整个网络层的功能。由于面对的网络不同,网络层将会采用不同的标准组合。
。
在具有开放特性的网络中的数据终端设备,都要配置网络层的功能。现在市场上销售的网络硬设备主要有网关和路由器。
传输层
传输层是两台计算机经过网络进行数据通信时,第一个端到端的层次,具有缓冲作用。当网络层服务质量不能满足要求时,它将服务加以提高,以满足高层的要求;当网络层服务质量较好时,它只用很少的工作。传输层还可进行复用,即在一个网络连接上创建多个逻辑连接。 传输层也称为运输层。传输层只存在于端开放系统中,是介于低3层通信子网系统和高3层之间的一层,但是很重要的一层。因为它是源端到目的端对数据传送进行控制从低到高的最后一层。
有一个既存事实,即世界上各种通信子网在性能上存在着很大差异。例如电话交换网,分组交换网,公用数据交换网,局域网等通信子网都可互连,但它们提供的吞吐量,传输速率,数据延迟通信费用各不相同。对于会话层来说,却要求有一性能恒定的界面。传输层就承担了这一功能。它采用分流/合流,复用/介复用技术来调节上述通信子网的差异,使会话层感受不到。
此外传输层还要具备差错恢复,流量控制等功能,以此对会话层屏蔽通信子网在这些方面的细节与差异.传输层面对的数据对象已不是网络地址和主机地址,而是和会话层的界面端口。上述功能的最终目的是为会话提供可靠的,无误的数据传输。传输层的服务一般要经历传输连接建立阶段,,数据传送阶段,传输连接释放阶段3个阶段才算完成一个完整的服务过程。而在数据传送阶段又分为一般数据传送和加速数据传送两种。传输层服务分成5种类型。基本可以满足对传送质量,传送速度,传送费用的各种不同需要。
传输层的协议标准有以下几种:
ISO8072:称为"面向连接的传输服务定义"
ISO8072:称为"面向连接的传输协议规范"
会话层
会话层提供的服务可使应用建立和维持会话,并能使会话获得同步。会话层使用校验点可使通信会话在通信失效时从校验点继续恢复通信。这种能力对于传送大的文件极为重要。会话层,表示层,应用层构成开放系统的高3层,面对应用进程提供分布处理,对话管理,信息表示,恢复最后的差错等. 会话层同样要担负应用进程服务要求,而运输层不能完成的那部分工作,给运输层功能差距以弥补.主要的功能是对话管理,数据流同步和重新同步。要完成这些功能,需要由大量的服务单元功能组合,已经制定的功能单元已有几十种,现将会话层主要功能介绍如下。
为会话实体间建立连接。为给两个对等会话服务用户建立一个会话连接,应该做如下几项工作:
将会话地址映射为运输地址
选择需要的运输服务质量参数(QOS)
对会话参数进行协商
识别各个会话连接
传送有限的透明用户数据
数据传输阶段
这个阶段是在两个会话用户之间实现有组织的,同步的数据传输。用户数据单元为SSDU,而协议数据单元为SPDU。会话用户之间的数据传送过程是将SSDU转变成SPDU进行的。
连接释放
连接释放是通过"有序释放"、"废弃"、"有限量透明用户数据传送"等功能单元来释放会话连接的。会话层标准为了使会话连接建立阶段能进行功能协商,也为了便于其它国际标准参考和引用,定义了12种功能单元.各个系统可根据自身情况和需要,以核心功能服务单元为基础,选配其他功能单元组成合理的会话服务子集。
会话层的主要标准有"DIS8236:会话服务定义"和"DIS8237:会话协议规范"。
表示层
表示层的作用之一是为异种机通信提供一种公共语言,以便能进行互 *** 作。这种类型的服务之所以需要,是因为不同的计算机体系结构使用的数据表示法不同。例如,IBM主机使用EBCDIC编码,而大部分PC机使用的是ASCII码。在这种情况下,便需要会话层来完成这种转换。通过前面的介绍,我们可以看出,会话层以下5层完成了端到端的数据传送,并且是可靠,无差错的传送。但是数据传送只是手段而不是目的,最终是要实现对数据的使用。由于各种系统对数据的定义并不完全相同,最易明白的例子是键盘,其上的某些键的含义在许多系统中都有差异。这自然给利用其它系统的数据造成了障碍。表示层和应用层就担负了消除这种障碍的任务。
对于用户数据来说,可以从两个侧面来分析,一个是数据含义被称为语义,另一个是数据的表示形式,称做语法。像文字、图形、声音、文种、压缩、加密等都属于语法范畴。表示层设计了3类15种功能单位,其中上下文管理功能单位就是沟通用户间的数据编码规则,,以便双方有一致的数据形式,能够互相认识。ISO表示层为服务、协议、文本通信符制定了DP8822、DP8823、DIS6937/2等一系列标准。
应用层
应用层向应用程序提供服务,这些服务按其向应用程序提供的特性分成组,并称为服务元素。有些可为多种应用程序共同使用,有些则为较少的一类应用程序使用。应用层是开放系统的最高层,是直接为应用进程提供服务的。其作用是在实现多个系统应用进程相互通信的同时,完成一系列业务处理所需的服务.其服务元素分为两类:公共应用服务元素CASE和特定应用服务元素SASE.CASE提供最基本的服务,它成为应用层中任何用户和任何服务元素的用户,主要为应用进程通信,分布系统实现提供基本的控制机制。特定服务SASE则要满足一些特定服务,如文卷传送、访问管理、作业传送、银行事务、订单输入等。
这些将涉及到虚拟终端、作业传送与 *** 作、文卷传送及访问管理、远程数据库访问、图形核心系统、开放系统互连管理等等。
应用层的标准有DP8649"公共应用服务元素"、DP8650"公共应用服务元素用协议"、文件传送、访问和管理服务及协议
为了达到这个目的,我们需要构造一个可快速检索的数据结构。C语言的性能高,所以我们用C语言来构造这个数据结构。为了确保大量的数据不会让用户感到迷惑,所以我们还需要想出一个合并数据的解决方案。最后,为了更好的适应市场,我们需要把app做的更完善一些。完成这个教学后,你将学到这款app的所有核心内容。
数据结构
首先我们先来分析下数据,搞清我们要如何处理数据。旅馆数据中包含了一系列的坐标点(包括纬度和经度),我们需要根据这些坐标点在地图上进行标注。地图可以任意的拖动并放大缩小,所以我们不需要把所有的点都全部绘制出来,我们只需要绘制可以显示在屏幕上的点。核心问题是:我们需要查询出显示在屏幕上的所有的点,所以我们要想出一个查找算法,查找存在于一个矩形范围内的所有点。
一个简单的解决方式就是遍历所有的点,然后判断(xMin<=x<=xMax并且yMin<=y<=yMax),很不幸,这是一个复杂度为O(N)的算法,显然不适合我们的情况。
这儿有个更好的解决方法,就是我们可以利用对称性来减少我们的查询范围。那么如何能通过查询的每一次的迭代来减少查询的范围呢?我们可以在每个区域内都加索引,这样可以有效减少查询的范围。这种区域索引的方式可以用四叉树来实现,查询复杂度为O(H)(H是查询的那个点所在的树的高度)
四叉树
四叉树是一个数据结构,由一系列的结点(node)构成。每个结点包含一个桶(bucket)跟一个包围框(boundingbox)。每个桶里面有一系列的点(point)。如果一个点包含在一个外包围框A中,就会被添加到A所在结点的桶(bucket)中。一旦这个结点的桶满了,这个结点就会分裂成四个子结点,每个子节点的包围框分别是当前结点包围框的1/4。分裂之后那些本来要放到当前结点桶中的点就都会放到子容器的桶中。
那么我们该如何来对四叉树进行编码呢?
我们先来定义基本的结构:
typedef struct TBQuadTreeNodeData {
double x
double y
void * data
} TBQuadTreeNodeData
TBQuadTreeNodeData TBQuadTreeNodeDataMake( double x, double y, void * data)
typedef struct TBBoundingBox {
double x0 double y0
double xf double yf
} TBBoundingBox
TBBoundingBox TBBoundingBoxMake( double x0, double y0, double xf, double yf)
typedef struct quadTreeNode {
struct quadTreeNode* northWest
struct quadTreeNode* northEast
struct quadTreeNode* southWest
struct quadTreeNode* southEast
TBBoundingBox boundingBox
int bucketCapacity
TBQuadTreeNodeData *points
int count
} TBQuadTreeNode
TBQuadTreeNode* TBQuadTreeNodeMake(TBBoundingBox boundary, int bucketCapacity)
TBQuadTreeNodeData结构包含了坐标点(纬度,经度)。void*data是一个普通的指针,用来存储我们需要的其他信息,如旅馆名跟电话号码。TBBoundingBox代表一个用于范围查询的长方形,也就是之前谈到(xMin<=x<=xMax&&yMin<=y<=yMax)查询的那个长方形。左上角是(xMin,yMin),右下角是(xMax,yMax)。
最后,我们看下TBQuadTreeNode结构,这个结构包含了四个指针,每个指针分别指向这个结点的四个子节点。它还有一个外包围框和一个数组(数组中就是那个包含一系列坐标点的桶)。
在我们建立完四叉树的同时,空间上的索引也就同时形成了。这是生成四叉树的演示动画。
下面的代码准确描述了以上动画的过程:
void TBQuadTreeNodeSubdivide(TBQuadTreeNode* node)
{
TBBoundingBox box = node->boundingBox
double xMid = (box.xf + box.x0) / 2.0
double yMid = (box.yf + box.y0) / 2.0
TBBoundingBox northWest = TBBoundingBoxMake(box.x0, box.y0, xMid, yMid)
node->northWest = TBQuadTreeNodeMake(northWest, node->bucketCapacity)
TBBoundingBox northEast = TBBoundingBoxMake(xMid, box.y0, box.xf, yMid)
node->northEast = TBQuadTreeNodeMake(northEast, node->bucketCapacity)
TBBoundingBox southWest = TBBoundingBoxMake(box.x0, yMid, xMid, box.yf)
node->southWest = TBQuadTreeNodeMake(southWest, node->bucketCapacity)
TBBoundingBox southEast = TBBoundingBoxMake(xMid, yMid, box.xf, box.yf)
node->southEast = TBQuadTreeNodeMake(southEast, node->bucketCapacity)
}
bool TBQuadTreeNodeInsertData(TBQuadTreeNode* node, TBQuadTreeNodeData data)
{
// Bail if our coordinate is not in the boundingBox
if (!TBBoundingBoxContainsData(node->boundingBox, data)) {
return false
}
// Add the coordinate to the points array
if (node->count <node->bucketCapacity) {
node->points[node->count++] = data
return true
}
// Check to see if the current node is a leaf, if it is, split
if (node->northWest == NULL) {
TBQuadTreeNodeSubdivide(node)
}
// Traverse the tree
if (TBQuadTreeNodeInsertData(node->northWest, data)) return true
if (TBQuadTreeNodeInsertData(node->northEast, data)) return true
if (TBQuadTreeNodeInsertData(node->southWest, data)) return true
if (TBQuadTreeNodeInsertData(node->southEast, data)) return true
return false
}
现在我们已经完成了四叉树的构造,我们还需要在四叉树上进行区域范围查询并返回TBQuadTreeNodeData结构。以下是区域范围查询的演示动画,在浅蓝区域内的是所有的标注点。当标注点被查询到在指定的区域范围内,则会被标注为绿色。
以下是查询代码:
typedef void (^TBDataReturnBlock)(TBQuadTreeNodeData data)
void TBQuadTreeGatherDataInRange(TBQuadTreeNode* node, TBBoundingBox range, TBDataReturnBlock block)
{
// If range is not contained in the node's boundingBox then bail
if (!TBBoundingBoxIntersectsBoundingBox(node->boundingBox, range)) {
return
}
for ( int i = 0i <node->counti++) {
// Gather points contained in range
if (TBBoundingBoxContainsData(range, node->points[i])) {
block(node->points[i])
}
}
// Bail if node is leaf
if (node->northWest == NULL) {
return
}
// Otherwise traverse down the tree
TBQuadTreeGatherDataInRange(node->northWest, range, block)
TBQuadTreeGatherDataInRange(node->northEast, range, block)
TBQuadTreeGatherDataInRange(node->southWest, range, block)
TBQuadTreeGatherDataInRange(node->southEast, range, block)
}
用四叉树这种结构可以进行快速的查询。在一个包含成百上千条数据的数据库中,可以以60fps的速度查询上百条数据。
用旅馆数据来填充四叉树
旅馆的数据来自于POIplaza这个网站,而且已经格式化成csv文件。我们要从硬盘中读取出数据并对数据进行转换,最后用数据来填充四叉树。
创建四叉树的代码在TBCoordinateQuadTree类中:
typedef struct TBHotelInfo {
char * hotelName
char * hotelPhoneNumber
} TBHotelInfo
TBQuadTreeNodeData TBDataFromLine(NSString *line)
{
// Example line:
NSArray *components = [line componentsSeparatedByString:@ "," ]
double latitude = [components[1] doubleValue]
double longitude = [components[0] doubleValue]
TBHotelInfo* hotelInfo = malloc( sizeof (TBHotelInfo))
NSString *hotelName = [components[2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
hotelInfo->hotelName = malloc( sizeof ( char ) * hotelName.length + 1)
strncpy(hotelInfo->hotelName, [hotelName UTF8String], hotelName.length + 1)
NSString *hotelPhoneNumber = [[components lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
hotelInfo->hotelPhoneNumber = malloc( sizeof ( char) * hotelPhoneNumber.length + 1)
strncpy(hotelInfo->hotelPhoneNumber, [hotelPhoneNumber UTF8String], hotelPhoneNumber.length + 1)
return TBQuadTreeNodeDataMake(latitude, longitude, hotelInfo)
}
- ( void )buildTree
{
NSString *data = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@ "USA-HotelMotel" ofType:@"csv" ] encoding:NSASCIIStringEncoding error:nil]
NSArray *lines = [data componentsSeparatedByString:@ "\n" ]
NSInteger count = lines.count - 1
TBQuadTreeNodeData *dataArray = malloc( sizeof(TBQuadTreeNodeData) * count)
for (NSInteger i = 0i <counti++) {
dataArray[i] = TBDataFromLine(lines[i])
}
TBBoundingBox world = TBBoundingBoxMake(19, -166, 72, -53)
_root = TBQuadTreeBuildWithData(dataArray, count, world, 4)
}
现在我们用iPhone上预加载的数据创建了一个四叉树。接下来我们将处理app的下一个部分:合并数据(clustering)。
合并数据(clustering)
现在我们有了一个装满旅馆数据的四叉树,可以用来解决合并数据的问题了。首先,让我们来探索下合并数据的原因。我们合并数据是因为我们不想因为数据过于庞大而使用户迷惑。实际上有很多种方式可以解决这个问题。GoogleMaps根据地图的缩放等级(zoomlevel)来显示搜索结果数据中的一部分数据。地图放的越大,就越能清晰的看到更细节的标注,直到你能看到所有有效的标注。我们将采用这种合并数据的方式,只显示出来旅馆的个数,而不在地图上显示出所有的旅馆信息。
最终呈现的标注是一个中心显示旅馆个数的小圆圈。实现的原理跟如何把图片缩小的原理差不多。我们先在地图上画一个格子。每个格子中包含了很多个小单元格,每个小单元格中的所有旅馆数据合并出一个标注。然后通过每个小单元格中所有旅馆的坐标值的平均值来决定合并后这个标注的坐标值。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)