必问
1.下载一个面试者做过的应用,找一个面试者做过的页面分析下页面结构、约束或者 frame 布局的连法和计算方法;
2.说说 UITableView 常用的几个 delegate 和 data source 代理方法,动态 Cell 高度计算什么的;
3.接下来,在手机里随便找一个 App 的页面,让面试者当场说说如果是他写应该用哪些 UI 组件和布局方式等。
4.你实现过一个框架或者库以供别人使用么?如果有,请谈一谈构建框架或者库时候的经验;如果没有,请设想和设计框架的public的API,并指出大概需要如何做、需要注意一些什么方面,来使别人容易地使用你的框架
答:抽象和封装,方便使用。首先是对问题有充分的了解,比如构建一 个文件解压压缩框架,从使用者的角度出发,只需关注发送给框架一个 解压请求,框架完成复杂文件的解压操作,并且在适当的时候通知给是 哦难过者,如解压完成、解压出错等。在框架内部去构建对象的关系, 通过抽象让其更为健壮、便于更改。其次是API的说明文档。
5.架构上 MVC 还是 MVVM 还是 MVP 神马的到是可以聊聊各自的见解
上架经验,被拒绝的原因,有哪些坑,什么开发者账号,多少钱,用什么布局页面。
以上问完了,基本对面试者的实力实力,表达能力都了解一点,下面的问题再挑选一些询问,面试就搞定了
私人问题:
是否有女朋友;女朋友是不是在本地工作;薪资要求;日常加班是否有时间;居住地离公司多远;是否需要配置苹果电脑;
观察面试者脾气,是否认真端正,是否强硬争辩,是否礼貌;
孩子年龄小需要照顾,没多少时间
面试者年龄大,售后服务不行,生活稳定怕风险!
基础
1.@property后面可以有哪些修饰符
一类是表示原子性(也就是线程安全)的,有atomic和nonatomic,默认是atomic,acomic也就是线程安全,但是我们一般都用的nonatomic,因为atomic的线程安全开销太大,影响性能,即使需要保证线程安全,我们也可以通过自己的代码控制,而不用atomic。
一类是表示引用计数的,有assign(iOS5以前用unsafe_unretained),strong,weak,copy。
assign: assign用于非指针变量,一般用于基础类型和C数据类型,这些类型不是对象,统一由系统栈进行内存管理。
weak:对对象的弱引用,不增加对象的引用计数,也不持有对象,当对象消失后指针自动指向nil,所以这里也就防止了野指针的存在。
strong:对对象的强引用,会增加对象的引用计数,如果指向了一个空对象,会造成野指针,平常我们用得最多的应该也是strong了。
copy:建立一个引用计数为1的新对象,赋值时对传入值进行一份拷贝,所以使用copy关键字的时候,你将一个对象复制给该属性,该属性并不会持有那个对象,而是会创建一个新对象,并将那个对象的值拷贝给它。而使用copy关键字的对象必须要实现NSCopying协议。
unsafe_unretained:跟 weak 类似,声明一个弱引用,但是当引用计数为 0 时,变量不会自动设置为 nil,现在基本都用weak了。
一类是表示读写权限的,默认是readwrite(可读可写),还有就是readonly,当你希望暴露出来的属性不能被外界修改时就需要申明为readonly。
2.这个写法会出什么问题: @property (copy) NSMutableArray *array;
一个属性如果标记了copy,当你调用其setter方法时,他会建立一个索引计数为1的对象,然后释放旧对象。
其实就是一个NSArray对其做增删改查的时候都会找不到该方法,程序崩溃。
3.什么情况使用 weak 关键字,相比 assign 有什么不同?
1.在ARC模式下,在有可能出现循环引用时,让其一端使用weak修饰。例如:delegate(代理)属性
2.自身已经对它强引用一次了,没有必再强引用一次使用weak解决。例如:自定义IBOutlet控件属性
两者区别:
1.weak只能用于修饰对象类型,基本数据类型不能使用
2.assign修饰对象和基本数据类型都可以,但是只是简单地进行赋值操作而已
注意:assign修饰的对象(一般编译的时候会产生警告:Assigning retained object to unsafe property; object will be released after assignment)在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,造成野指针。对象一般分配在堆上的某块内存,如果在后续的内存分配中,刚好分到了这块地址,程序就会崩溃掉。
那为什么可以用assign修饰基本数据类型?因为基础数据类型一般分配在栈上,栈的内存会由系统自己自动处理,不会造成野指针。
weak修饰的对象在释放之后,指针地址会被置为nil。所以现在一般弱引用就是用weak。
4.架构上 MVC 还是 MVVM 还是 MVP 神马的到是可以聊聊各自的见解,
5. 常见的Objective-C 的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int
Objective-C的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedeflongNSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是long。
6.ViewController生命周期
按照执行顺序排列:
1. initWithCoder:通过nib文件初始化时触发。
2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。
3. loadView:开始加载视图控制器自带的view。
4. viewDidLoad:视图控制器的view被加载完成。
5. viewWillAppear:视图控制器的view将要显示在window上。
6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。
7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。
8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。
9. viewDidAppear:视图控制器的view已经展示到window上。
10.viewWillDisappear:视图控制器的view将要从window上消失。
11.viewDidDisappear:视图控制器的view已经从window上消失。
中阶
1.用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
1、因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的
属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对
象,我本身持有的就是一个不可变的副本.
2、如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如
果这个可变对象在外部被修改了,那么会影响该属性.
copy此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。
当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。
这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。
所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的”
(mutable),就应该在设置新属性值时拷贝一份。
2.简单介绍一下设计模式:
1) MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
3.Category(类别)、Extension(扩展)和继承的区别
区别:
分类有名字,类扩展没有分类名字,是一种特殊的分类。
分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。
继承可以增加,修改或者删除方法,并且可以增加属性。
4.什么是KVO 和KVC?
1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)
举例说明:
stu.name = @"张三" // 点语法给属性赋值
[stu setValue:@"张三" forKey:@"name"]; // 通过字符串使用KVC方式给属性赋值
stu1.nameLabel.text = @"张三";
[stu1 setValue:@"张三" forKeyPath:@"nameLabel.text"]; // 跨层赋值
2). KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。
KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。
// 通过下方方法为属性添加KVO观察
- (void)addObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(nullable void *)context;
// 当被观察的属性发送变化时,会自动触发下方方法
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{}
KVC 和 KVO 的 keyPath 可以是属性、实例变量、成员变量。
4.block的注意点
1). 在block内部使用外部指针且会造成循环引用情况下,需要用__week修饰外部指针: __weaktypeof(self) weakSelf = self;
2). 在block内部如果调用了延时函数还使用弱指针会取不到该指针,因为已经被销毁了,需要在block内部再将弱指针重新强引用一下。 __strongtypeof(self) strongSelf = weakSelf;
3). 如果需要在block内部改变外部栈区变量的话,需要在用__block修饰外部变量
5.什么是 TCP / UDP ?
TCP:传输控制协议。
UDP:用户数据协议。
TCP 是面向连接的,建立连接需要经历三次握手,是可靠的传输层协议。
UDP 是面向无连接的,数据传输是不可靠的,它只管发,不管收不收得到。
简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般。
6.HTTP协议中 POST 方法和 GET 方法有那些区别?
- GET用于向服务器请求数据,POST用于提交数据
- GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体里面,因此GET请求不适合用于验证密码等操作
- GET请求的URL有长度限制,POST请求不会有长度限制
7.请简单的介绍下APNS发送系统消息的机制
APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连接的行为,由iOS系统和APNS进行长连接替代。 APNS的原理:
1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)
2). 应用程序接收到设备令牌并发送给自己的后台服务器
3). 服务器把要推送的内容和设备发送给APNS
4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示
8.述下SDWebImage里面给UIImageView加载图片的逻辑
SDWebImage 中为 UIImageView提供了一个分类UIImageView+WebCache.h, 这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。
加载图片的过程大致如下:
1.首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存
2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来
3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片
4.下载后的图片会加入缓存中,并写入磁盘中
5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来
SDWebImage原理:
调用类别的方法:
1.从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
2.从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。
3.从网络上获取,使用,缓存到内存,缓存到沙盒。
21:iOS逆向传值的几种方法
- 代理
- 通知
- 单例
- Block
- Kvo
22.你们的App是如何处理本地数据安全的(比如用户名的密码)?
https://blog.csdn.net/baize_security/article/details/52766981
23.说一下UITableViewCell的卡顿你是怎么优化的?
24.为什么一定要在主线程里面更新UI?
因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI
更新的函数栈,这中间的时间非常的短,就让大家误以为分线程可以更新
UI。如果子线程一直在运行,则子线程中的UI更新的函数栈主线程无法获
知,即无法更新只有极少数的UI能,因为开辟线程时会获取当前环境,如点
击某个按钮,这个按钮响应的方法是开辟一个子线程,在子线程中对该按钮
进行UI更新是能及时的,如换标题,换背景图,但这没有任何意义UI操作并
不是线程安全的,多线程更新UI会造成死锁,竞争条件等多种问题。
iOS推荐UI因为子线程代码执行完毕了,又自动进入到了主线程,执行了子
线程中的UI更新的函数栈,这中间的时间非常的短,就让大家误以为分线程
可以更新]UI。如果子线程一直在运行,则子线程中的UI更新的函数栈 主线程无法获知,即无法更新
只有极少数的UI能,因为开辟线程时会获取当前环境,如点击某个按钮,这
个按钮响应的方法是开辟一个子线程,在子线程中对该按钮进行UI 更新是
能及时的,如换标题,换背景图,但这没有任何意义 .
UI操作并不是线程安全的,多线程更新UI会造成死锁,竞争条件等多种问
题。iOS推荐UI操作在主线程中进行,避免出现crash等无法预知的问题。
比如TableView的刷新,有可能线程a往模型数组中添加了数据并刷新
tableView,tableView调用了
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
得知每组cell的个数,但是就在tableView调用
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法的时候,
线程b将模型数组里面的数据删除干净了,如果此时在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
方法里访问模型数组,就会出现数组越界,这在网络请求数据的时候很容易
出现,一定要确定数据返回的block或者delegate是在哪个线程,如果是子
线程一定要回主线程刷新UI。
25.说一下多线程,你平常是怎么用的?
http://www.cocoachina.com/ios/20170829/20404.html iOS多线程详解
高阶
26.objc中向一个nil对象发送消息将会发生什么?
在 Objective-C 中向 nil 发送消息是完全有效的——只是在运行时不会有任何作用:
如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。例如:
Person * motherInlaw = [[aPerson spouse] mother];
如果 spouse 对象为 nil,那么发送给 nil 的消息 mother 也将返回 nil。
如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者 long long 的整型标量,发送给 nil 的消息将返回0。
如果方法返回值为结构体,发送给 nil 的消息将返回0。结构体中各个字段的值将都是0。
如果方法的返回值不是上述提到的几种情况,那么发送给 nil 的消息的返回值将是未定义的。
具体原因如下:
objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。
那么,为了方便理解这个内容,还是贴一个objc的源代码:
// runtime.h(类在runtime中的定义)
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指针指向Meta Class,因为Objc的类的本身也是一个Object,为了处理这个关系,runtime就创造了Meta Class,当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在method Lists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对
象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找
方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所
谓的返回内容都是具体调用时执行的。那么,回到本题,如果向一个nil
对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。
27.runloop和线程有什么关系?
runloop与线程是一一对应的,一个runloop对应一个核心的线程,为什么说是核心的,是因为runloop是可以嵌套的,但是核心的只能有一个,他们的关系保存在一个全局的字典里。
runloop是来管理线程的,当线程的runloop被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务。
runloop在第一次获取时被创建,在线程结束时被销毁。
对于主线程来说,runloop在程序一启动就默认创建好了。
对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创
建,所以在子线程用定时器要注意:确保子线程的runloop被创建,不然定时器不会回调。
28.Objective-C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?
线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:
29.KVC的底层实现?
当一个对象调用setValue方法时,方法内部会做以下操作:
1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
30. 如何对iOS设备进行性能测试?
Profile-> Instruments ->Time Profiler
开发项目时你是怎么检查内存泄露?
1). 静态分析 analyze。
2). instruments工具里面有个leak可以动态分析。
31. GCD 与 NSOperation 的区别:
GCD 和 NSOperation 都是用于实现多线程:
GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。
NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现
32. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
// 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ });
// 当并发队列组中的任务执行完毕后才会执行这里的代码
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并图片
});
33.什么是 RunLoop
从字面上讲就是运行循环,它内部就是do-while循环,在这个循环内部不断地处理各种任务。 一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。 主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数intmain(intargc, char* argv[]) {@autoreleasepool{returnUIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
34.什么是 Runtime
Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。
1). 使用时需要导入的头文件 <objc/message.h> <objc/runtime.h>
2). Runtime 运行时机制,它是一套C语言库。
3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。 比如: 类转成了 Runtime 库里面的结构体等数据类型, 方法转成了 Runtime 库里面的C语言函数, 平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)// OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。// [stu show]; 在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show));
4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。
36.__block修饰的变量为什么能在block里面能改变其值?
默认情况下,在block中访问的外部变量是复制过去的,即:写操作不对
原变量生效。但是你可以加上 __block
我们都知道:block不允许修改外部变量的值,这里所说的外部变量的
值,指的是栈中指针的内存地址。
__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外
部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。
37.block的实质是什么?有几种block?分别是怎样产生的?
iOS Block理解
//www.greatytc.com/p/9e9a6d7eba92
iOS底层原理总结 - 探寻block的本质
http://www.cocoachina.com/ios/20180628/23965.html
block本质上也是一个oc对象,他内部也有一个isa指针。block是封装了函数调用以及函数调用环境的OC对象。
局部变量都会被block捕获,自动变量是值捕获,静态变量为地址捕获。全局变量则不会被block捕获
即使block中使用的是实例对象的属性,block中捕获的仍然是实例对象,并通过实例对象通过不同的方式去获取使用到的属性。
block最终都是继承自NSBlock类型,而NSBlock继承于NSObjcet。那么block其中的isa指针其实是来自NSObject中的。这也更加印证了block的本质其实就是OC对象。
block有3中类型
__NSGlobalBlock__ ( _NSConcreteGlobalBlock )
__NSStackBlock__ ( _NSConcreteStackBlock )
__NSMallocBlock__ ( _NSConcreteMallocBlock )
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 1. 内部没有调用外部变量的block
void (^block1)(void) = ^{
NSLog(@"Hello");
};
// 2. 内部调用外部变量的block
int a = 10;
void (^block2)(void) = ^{
NSLog(@"Hello - %d",a);
};
// 3. 直接调用的block的class
NSLog(@"%@ %@ %@", [block1 class], [block2 class], [^{
NSLog(@"%d",a);
} class]);
}
return 0;
}
38.看过哪些三方库?说一下实现原理以及好在哪里?
39.说一下HTTP和HTTPs的请求过程?
HTTP协议(HyperText Transfer Protocol,超文本传输协议):是一种
发布和接收 HTML页面的方法。
HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)简单
讲是HTTP的安全版,在HTTP下加入SSL层。
SSL(Secure Sockets Layer 安全套接层)主要用于Web的安全传输协
议,在传输层对网络连接进行加密,保障在Internet上数据传输的安全。
HTTP的端口号为80,
HTTPS的端口号为443
https://blog.csdn.net/xun527/article/details/78387345
OSI 各层功能
应用层
与其它计算机进行通讯的一个应用,它是对应应用程序的通信服务的。例如,一个没有通信功能的字处理程序就不能执行通信的代码,从事字处理工作的程序员也不关心OSI的第7层。但是,如果添加了一个传输文件的选项,那么字处理器的程序员就需要实现OSI的第7层。示例:TELNET,HTTP,FTP,NFS,SMTP等。
表示层
这一层的主要功能是定义数据格式及加密。例如,FTP允许你选择以二进制或ASCII格式传输。如果选择二进制,那么发送方和接收方不改变文件的内容。如果选择ASCII格式,发送方将把文本从发送方的字符集转换成标准的ASCII后发送数据。在接收方将标准的ASCII转换成接收方计算机的字符集。示例:加密,ASCII等。
会话层
它定义了如何开始、控制和结束一个会话,包括对多个双向消息的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的,在某些情况下,如果表示层收到了所有的数据,则用数据代表表示层。示例:RPC,SQL等。
传输层
这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。
网络层
这层对端到端的包传输进行定义,它定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。为了适应最大传输单元长度小于包长度的传输介质,网络层还定义了如何将一个包分解成更小的包的分段方法。示例:IP,IPX等。
数据链路层
它定义了在单个链路上如何传输数据。这些协议与被讨论的各种介质有关。示例:ATM,FDDI等。
物理层
OSI的物理层规范是有关传输介质的特这些规范通常也参考了其他组织制定的标准。连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容。物理层常用多个规范完成对所有细节的定义。示例:Rj45,802.3等。