TCP
三次握手
开头两次握手都不携带数据,但都要消耗1个序号,
为什么要三次握手?
- 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。两次握手的话,只有请求方的序列号起始值能被确认
四次挥手
客户端发送FIN,表示自己传完了
- 服务端发送ACK,确认收到
- 服务端此时可进行数据传输
服务端也传完了,发送FIN
- 客户端发送ACK,确认收到
- 此时进入TIME-WAIT,时长为2MSL,MSL即报文段的最大生存时间,保证若自己的ACK发送失败,还能接收到服务端重发给自己的一次FIN。详细说就是第一个MSL是自己的ACK传过去,第二个是对方的FIN发过来。
面试常考题
1、TCP链接建立的过程需要三次握手,为什么?
第一次握手是发送方发送连接请求与序列号起始值, 第二次握手是接收方接收到信息后,发送确认收到与自己的序列号起始值, 第三次握手是接收方接受到信息后,发送确认收到,并且该次传输可能携带数据。 首先是为了确保连接的可靠性,通信双方都需要接收到对方发送的序列号起始值并收到确认信息,如果仅有两次握手就只有请求方的序列号起始值能被确认
2、TCP链接断开的过程需要四次挥手,为什么?
第一次挥手是发送方发送FIN,表示传输数据完毕并且想断开连接, 第二次挥手是接收方发送确认收到信息,也可能携带数据, 第三次挥手是传完最后的数据后,发送方发送FIN,表示自己也传完数据了,随后断开连接, 第四次挥手是接收方发送确认收到信息 也是为了确保断开是实实在在断开了,双方都需要接收到对方确认结束的信息。
3、 关闭链接时,服务器端可不可以主动断开链接?为什么?
可以,角色互换
4、为什么需要TIME_WAIT状态,该状态可以删除吗?
不能,这是为了防止请求断开方的第四次挥手发送的ACK发送失败,TCP连接与断连核心都是双方都需要接收到对方发送的确认连接或断连的信息,而若是没有TIME_WAIT,请求断开方的第四次挥手便没有错误处理机制了。
5、TCP协议和UDP协议有啥区别?
TCP用于确保信息完整性的情况,比如文字信息传输,文件传输等。UDP则用于需要保证通信即时性,即使牺牲完整性,但可以接受的情况,如视频通话,FPS网游。 具体来说: UDP是无连接协议,传输信息前后都不需要像TCP那样握手挥手, 报文头部更小,低开销。 无错误检查机制,只保证传不保证收到 无拥塞控制,任何时候传输速度相等,网络环境差的时候会丢包
6、网络IO复用模型有哪些?它们之间的异同是什么?
seletct,poll,epoll 都是IO多路复用机制,用于监控多个文件描述符是否有IO事件发生。 select固定最大文件描述符为1024,每次调用都要遍历整个文件描述符集合,且需要重新设置该集合 poll无文件描述符数量限制,调用也要遍历整个文件描述符集合,也需要重新设置该集合 epoll无文件描述符数量限制,自动将活跃的文件描述符加入就绪队列,时间复杂度接近O(1),支持边缘触发与水平触发,适合大量并发连接的场景(当然极小量就不太适合了) 支持
7、网络IO模型有哪些?
阻塞型 非阻塞型 IO多路复用 信号驱动式IO 异步 这几种的流程都可以分为两个阶段,第一阶段内核从硬件设备接收数据,第二阶段是从内核将数据从内核态拷贝到用户态,而前四种的第二阶段都是阻塞的,而异步机制是程序不阻塞于内核将数据拷贝到用户态的过程,只需要接受内核传输完成时发送的成功信息,所以可以做到从开始就做撒手掌柜,完全不阻塞,自己可以处理其他事务。阻塞型是一直阻塞,非阻塞型是内核接受数据时一直轮询,看接收完毕与否。IO多路复用也是阻塞,只不过可以同时监听多个IO事件,信号驱动也是阻塞,只不过通知是以信号方式给出。
8、什么是同步、异步?什么是阻塞、非阻塞?
同步是调用者必须等待调用的任务完成,才能继续执行后续任务。多任务时,同步的概念是任务的执行顺序
需要严格按照调用顺序
完成,比如调用者想调用a,b两个任务,但必须等待a完成后才能调用b并等待完成。
异步则不要求调用者必须等待操作完成,可以先去干其他的,任务完成后由设定的机制来提醒任务完成。
TCP的状态转换
TIME_WAIT=2MSL: 什么是MSL?为什么客户端最后还要等待2MSL?
什么是MSL
- MSL是指TCP传输中,TCP报文段在网络中存在的最大生存时间。(MSL的主要目的是定义一个时间限制,以确保TCP报文段在网络中不会无限期地存在。是TCP允许不同的实现可以设置不同的MSL值)
为什么客户端最后还要等待2MSL
- 确保对方收到最终ACK:TIME_WAIT状态确保连接的另一方(服务器)有足够的时间接收到最后一个ACK。因为如果服务器没有收到这个ACK,并且第三次挥手超时, 服务端可能认为它发送的第三次挥手失败(迷失在网络中), 服务器它会重新发送FIN报文段(第三次挥手)。客户端在TIME_WAIT状态可以处理这种情况,确保连接的可靠终止。
- 端口和资源的正确释放:这个等待期还允许操作系统正确地清理和释放用于连接的资源,如端口号。在2MSL结束后,相同的端口号可以安全地被新的连接使用,不会受到旧连接残留数据的影响。
UDP
UDP特点
- 无连接:UDP是一种无连接协议。这意味着在数据包发送之前,发送方和接收方之间不需要建立连接。每个数据包之间独立发送,彼此之间没有依赖关系。
- 低开销:UDP协议头部较小,只有8字节,相比之下,TCP协议头部最少20字节。UDP的简单性使得它在传输数据时增加的开销更少。
- 不可靠传输:UDP不提供数据到达的保证。因为它不进行错误检查或者纠正,意味着网络上的数据包可能会丢失、重复或乱序到达,且发送方不会得到通知。
- 无拥塞控制:UDP不实现拥塞控制机制。它以相同的速度发送数据,不论网络条件如何。这可能导致在网络质量较差时数据包被丢弃。
- 快速传输:由于缺乏连接建立、确认响应、流量控制等机制,UDP可以更快速地传输数据(能不能到目的地是另外一件事)。
IP地址
分类
A类地址:1.X.X.X~126.X.X.X
网络号占用1字节 (网络号的字节构成位0XXX XXXX )
每一个网络下可以包含主机1677214台 (2^24 - 2) (24次方是因为主机号占用3字节, 主机号占用1字节)(-2是因为网络本身、广播IP)
B类地址:128.0.X.X~191.255.X.X
- 网络号占用2字节 (网络号的字节构成位10XX XXXX XXXX XXXX )
- 每一个网络下可以包含主机65534台 (2^16 - 2)
C类地址:192.0.0.X~223.255.255.X
网络号占用3字节 (网络号的字节构成位110X XXXX XXXX XXXX )
每一个网络下可以包含主机254台 (2^8 - 2)
D类地址:(224-239)是多播地址,主要用于多路广播用户, 非常用IP(D类地址没有划分为网络号和主机号)。
E类地址:(240-255)保留地址,目前尚未定义具体的用途。
广播IP: 专门用于向该IP所在网络中所有IP主机进行发送广播数据行为的一个IP地址。广播地址的主机号全为1。 1.1.1.1
网络本身IP: 用于标识该网络号的网络本身, 主机号全为0。 0.0.0.0
XXX.XXX.XXX.XXX的XXX是十进制,8位二进制表示,
最大十进制为2^8-1即255,所以比如XXX.XXX,能表示2^16个地址
子网掩码&CIDR
- 子网掩码定义:32位二进制 由一串连续的1跟着一串连续的0组成,1的位数对应IP地址中的网络号和子网号.而0对应主机号
IP跟子网掩码相与,得到响应的网络地址
- CIDR定义:无分类域间路由选择, 它在子网掩码的基础上消除了传统A、B、C类网络划分.
其实就是XXX.XXX.XXX.XXX/10的10;10代表前10位全是1:11111111.11000000.00000000.00000000
五种IO模型
并发式
- 餐厅有一个前台接待员(父进程)和多个服务员(子进程)
- 前台接待员的主要工作是迎接新客人,并安排服务员接待
- 当客人到达时:
- 前台接待员与客人建立初步接触(创建连接套接字)
- 叫来一个服务员负责这位客人
- 服务员开始专门服务这位客人(子进程处理请求)
- 前台接待员就不再管这位客人了(关闭套接字),转而等待下一位客人
为什么要关闭套接字?
- 如果不关闭,就像前台接待员还要记挂着已经交给服务员的客人一样,会分散注意力
- 关闭后,接待员可以专心等待和接待新客人
- 每个服务员(子进程)都可以专注服务好自己负责的客人(处理请求)
- 即使某个服务员服务时间较长(处理请求耗时),也不会影响前台继续接待新客人
在线程模型中:
- 这就像餐厅的所有员工都在同一个大房间工作
- 他们可以直接看到和使用同样的设施(共享文件描述符)
- 所以不需要每次都关闭接待通道,直到最后一个服务员下班
这种模式的优点:
- 效率高 - 可以同时服务多个客户
- 互不干扰 - 每个客户都有专门的服务员
- 灵活性好 - 处理时间长短不会相互影响
prefork
- 传统模式(普通并发服务器):
- 客人来了才临时叫服务员(创建进程)
- 需要时间安排人手
- 客人可能要等待
- Prefork模式:
- 开门前就安排好固定数量的服务员(预先创建进程)
- 所有服务员都在前台待命(accept等待)
- 客人一来就能立即服务
优点:
- 响应快 - 就像服务员已经站在门口等待
- 省去临时安排人手的时间
- 运行更稳定
缺点:
- 人手问题:
- 必须提前决定雇多少服务员(预设进程数)
- 太少:客人多时应付不来
- 太多:闲着浪费资源
- 客满情况:
- 如果所有服务员都在忙(进程都被占用)
- 新客人只能在门口等待(连接在队列中等待)
- 直到有服务员空闲才能接待
适合场景
- 需要快速响应的服务
- 负载相对稳定可预测的场景
-
对响应时间要求高的应用
就像餐厅要在”雇太多服务员增加成本”和”雇太少服务员客人等太久”之间找平衡一样,prefork服务器也需要在资源使用和服务能力间做权衡。
并发服务器模型
1. 反应式服务器(单个智能服务员模式):
一个超级服务员(单进程)通过智能手表(epoll/select)同时监控多个桌子:
- 不用在每桌前傻等
- 谁需要服务(有IO事件)就立即去服务谁
- 快速处理完就转身处理下一个请求
2. 反应式+线程池(智能服务员+专职厨师团队):
- 服务员还是用智能手表监控所有桌子
- 但遇到复杂需求(耗时操作)时:
- 不自己处理,而是交给后厨团队(线程池)
- 自己继续服务其他客人
- 等厨师做好了,再送给客人
3. 多反应式(多个智能服务员):
- 多个服务员,每人都戴智能手表
- 每个服务员负责不同区域
- 相当于把大餐厅分成几个小区域
- 提高了整体服务效率
客户端和服务端都由填入的协议创建一个socket(文件描述符形式),此时顺序不分先后。而服务端用bind将自定义的ip地址与端口号与socket创建的文件描述符绑定,而listen作用是设定监听数量上限,与这场连接本身没直接联系。随后调用accept来监听这个文件描述符并阻塞,实际意义就是监听文件描述符绑定的的ip地址与端口号有没有连接到来,也需要传入一个addr结构体,函数会设置内容为新到来客户端的ip与端口号。此时客户端便可调用connect,传入的是客户端所创建的文件描述符与包含自己ip与端口的addr。但connect传入的addr包含的ip与端口应该是对应服务端创建的文件描述符的网络信息,而不是accept所接受到的addr。比如服务端ip为321,客户端ip为123,accept到的addr包含的ip也是123而不是321,connect需要传入的addr包含的ip为321.
逻辑是:先监听服务器的监听的套接字,当有新链接到来时做出反应,将accept创建的新文件描述符a_fd加入到监听队列,实际上作用是监听是否有信息的传输,客户端若是send信息过来,服务端监听的a_fd就会就绪,从而可以处理信息,而服务器的套接字监听的作用则是将用于信息传输的fd加入队列中