字节iOS面试经验分享:HTTP与网络编程
🌟 嗨,我是LucianaiB!
🌍 总有人间一两风,填我十万八千梦。
🚀 路漫漫其修远兮,吾将上下而求索。
目录
最近,我有幸参加了字节跳动的iOS面试,这不仅是一次技术的挑战,更是一场知识的盛宴。面试过程中,我深刻感受到了字节对技术细节的严谨态度和对创新思维的高度重视。今天,我就把这次面试中关于HTTP与网络编程的那些事儿分享给大家,希望能帮到正在准备面试的小伙伴们。
HTTP协议简介
HTTP,即超文本传输协议,是互联网上应用最为广泛的网络协议之一。它基于TCP协议,通过请求-响应模式进行信息交换。客户端(如浏览器)向服务器发送请求,服务器处理后返回响应。这种模式使得客户端和服务器之间的数据交互变得简单而高效。
一个典型的URL地址,如https://www.google.com/search?q=url+含义#top
,包含了多个部分,每个部分都有其特定的含义:
- 协议:
https
,表示使用安全协议访问,相比HTTP,HTTPS增加了SSL/TLS加密层,数据传输更加安全。 - 域名:
www.google.com
,表示Google搜索引擎的地址。 - 路径:
/search
,表示访问搜索页面。 - 查询参数:
?q=url+含义
,表示搜索关键词为"url 含义"。 - 片段标识符:
#top
,表示跳转到搜索结果页面的最顶部。
iOS中HTTP请求的实现原理
在iOS开发中,发起一个HTTP请求的原理是基于底层的网络协议栈。具体来说,它利用TCP或UDP协议建立网络连接,然后根据HTTP协议的规范发送请求信息并接收服务器的响应。这个过程涉及到以下几个关键步骤:
- 创建URLRequest对象:使用
NSURLRequest
类创建一个请求对象,设置请求的URL、HTTP方法(如GET、POST等)、请求头信息、请求体等。 - 创建URLSession对象:使用
NSURLSession
类创建一个会话对象,它负责管理HTTP请求的执行。可以选择使用默认的共享会话,也可以创建自定义的会话。 - 创建URLSessionTask对象:使用
dataTask(with:completionHandler:)
方法创建一个数据任务,它负责执行HTTP请求并处理响应数据。 - 执行任务:调用
resume()
方法启动HTTP请求。 - 处理响应:数据任务完成之后,会回调
completionHandler
,传递响应数据、响应头信息等。
HTTPS与HTTP的区别
HTTPS和HTTP的主要区别在于安全性。HTTPS在HTTP的基础上增加了SSL/TLS加密层,使用端口443,而HTTP使用的是明文传输,端口为80。这意味着在HTTPS中,数据在传输过程中被加密,即使被截获,也无法轻易被解读,从而大大提高了数据传输的安全性。
TCP与UDP的区别
TCP和UDP是两种常用的传输层协议,它们的主要区别如下:
- 连接方式:TCP是面向连接的,需要通过三次握手建立连接,四次挥手断开连接;UDP是无连接的,不需要建立连接即可直接发送数据。
- 报头大小:TCP数据报的报头大小最少为20字节,UDP数据报的报头固定为8字节。
- 交付保证:TCP提供可靠的数据传输,如果数据在传输过程中丢失,会进行重传;UDP则不保证数据的可靠传输,数据包可能会丢失。
- 流量控制和拥塞控制:TCP有流量控制和拥塞控制机制,可以根据网络状况调整数据传输速率;UDP则没有这些机制。
- 面向对象:TCP面向字节流,UDP面向报文。
三次握手
三次握手是 TCP 协议建立连接的过程
- 客户端发送 SYN 包: 客户端向服务器发送一个 SYN 包,请求建立连接,并包含客户端的初始序列号(ISN)。
- 服务器发送 SYN+ACK 包: 服务器收到 SYN 包后,发送一个 SYN+ACK 包,表示同意建立连接,并包含服务器的初始序列号(ISN)和对客户端 SYN 包的确认号(ACK)。
- 客户端发送 ACK 包: 客户端收到 SYN+ACK 包后,发送一个 ACK包,确认服务器的 SYN+ACK 包,并包含对服务器 SYN+ACK 包的确认号(ACK)。
四次挥手
四次挥手是 TCP 协议断开连接的过程
- 客户端发送 FIN 包: 客户端向服务器发送一个 FI包,表示客户端不再发送数据,请求关闭连接。
- 服务器发送 ACK 包: 服务器收到 FIN 包后,发送一个 ACK包,确认客户端的 FIN 包。此时服务器仍然可以向客户端发送数据。
- 服务器发送 FIN 包: 服务器发送一个 FIN 包,表示服务器也不再发送数据,请求关闭连接。
- 客户端发送 ACK 包: 客户端收到 FIN 包后,发送一个 ACK包,确认服务器的 FIN 包,并表示连接已关闭。
Cookie与Session
在HTTP协议中,Cookie和Session是两种常用的会话跟踪技术。Cookie存储在用户本地,由浏览器管理,而Session存储在服务器端。如果禁用了Cookie,可以使用URL重写技术来进行会话跟踪,即在URL后面附加sid=xxxxx
等参数。
流量控制与拥塞控制
流量控制和拥塞控制是网络通信中的两个重要概念。流量控制主要关注单个连接的传输速率,通过接收方告知发送方当前的接收能力,发送方根据接收方的反馈调整发送速率。拥塞控制则关注整个网络的流量控制,通过网络节点的反馈信息,如丢包率、延迟等,来判断网络是否拥塞,并根据判断结果调整发送速率。
虚拟内存
虚拟内存是计算机系统中的一种内存管理技术。当程序运行时,如果内存不足,系统会将外存的一部分空间作为虚拟内存使用,从而扩展可用内存。然而,虚拟内存中的数据在断电后会丢失,与硬盘等外部存储器不同。
多线程并发访问共享资源
在多线程编程中,如果多个线程同时对一个共享资源进行操作,可能会导致数据不一致等问题。例如,两个线程对一个int a = 1
的变量同时进行a++
操作一万次,最后a
的值可能会小于20000。这是因为a++
操作并非原子操作,多个线程可能读取了相同的旧值并进行加1操作。解决方法包括使用互斥锁、原子操作等。
iOS中线程数量的限制
为了保证系统稳定性和性能,iOS对线程数量有着一定的限制。实际情况取决于设备的硬件资源和应用程序的内存使用情况。过多的线程可能会导致系统资源不足,从而引发应用程序崩溃或性能下降。因此,建议使用GCD或其他更高效的并发机制来管理线程。
堆和栈的区别
堆和栈是两种不同的内存分配方式。堆空间的内存是动态分配的,一般存放对象,并且需要手动释放内存。栈空间的内存是由系统自动分配,一般存放局部变量,如对象的地址等值,不需要程序员对这块内存进行管理。栈不够用时会发生栈溢出现象,此时可以使用堆来存储数据,但需要注意及时释放堆内存,否则会导致内存泄漏等错误。
@autoreleasepool的使用
在iOS开发中,@autoreleasepool
用于管理自动释放对象的生命周期。使用@autoreleasepool
可以减少内存峰值,特别是在需要创建大量临时对象的情况下,如在一个循环中不断创建和使用对象。此外,在非UI线程和自定义线程中,也需要手动创建@autoreleasepool
,以确保在这些线程中创建的自动释放对象能够被及时释放,避免内存泄漏。
App从编译到可执行文件的过程
App从编译到变成可执行文件的过程包括以下几个阶段:
- 预处理:处理源代码文件中的以"#"开头的预编译指令。
- 编译:将高级语言翻译成汇编语言。
- 汇编:将汇编语言变成计算机可识别的二进制代码。
- 链接:把目标文件(一个或多个)和需要的库(静态库/动态库)链接成可执行文件。
静态库与动态库的区别
静态库和动态库是两种不同的库类型,它们的主要区别如下:
- 静态库:在程序编译时就将所有要使用的库都装进了程序中,然后程序开始运行。优点是程序运行时不需要额外加载库,缺点是程序体积较大。
- 动态库:程序运行时,用到什么库,再去链接什么库。优点是程序体积较小,缺点是程序运行时需要额外加载库,可能会导致程序启动速度变慢。
类是如何添加到可执行文件中的
类信息是在编译和链接阶段被添加到可执行文件中的。编译器会将类信息转换为机器码并生成符号表,链接器会将类信息整合到可执行文件中,并为其分配内存地址。
复制粘贴的原理
我们常用的复制粘贴功能,其原理是使用了共享内存。操作系统会将我们选择的文本、图像、文件等数据复制到一块共享内存区域中,当需要粘贴时,再从这块共享内存区域中读取数据。
大容器VC的使用方式
在iOS开发中,大容器VC的使用方式主要有两种:
- 直接调用:父容器VC直接持有子容器VC的引用,并在需要时直接调用子容器的声明周期方法。
- 代理模式:父容器VC可以定义一个代理协议,子容器VC实现该协议。通过代理模式,父容器VC可以间接调用子容器VC的方法,从而实现解耦和更好的代码组织。
嗨,我是LucianaiB。如果你觉得我的分享有价值,不妨通过以下方式表达你的支持:👍 点赞来表达你的喜爱,📁 关注以获取我的最新消息,💬 评论与我交流你的见解。我会继续努力,为你带来更多精彩和实用的内容。
点击这里👉LucianaiB ,获取最新动态,⚡️ 让信息传递更加迅速。