计算机经网络体系结构:
各层作用及协议
分层 | 作用 | 协议 |
---|---|---|
物理层 | 通过媒介传输比特,确定机械及电气规范(比特 Bit) | RJ45、CLOCK、IEEE802.3(中继器,集线器) |
数据链路层 | 将比特组装成帧和点到点的传递(帧 Frame) | PPP、FR、HDLC、VLAN、MAC(网桥,交换机) |
网络层 | 负责数据包从源到宿的传递和网际互连(包 Packet) | IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP(路由器) |
运输层 | 提供端到端的可靠报文传递和错误恢复( 段Segment) | TCP、UDP、SPX |
会话层 | 建立、管理和终止会话(会话协议数据单元 SPDU) | NFS、SQL、NETBIOS、RPC |
表示层 | 对数据进行翻译、加密和压缩(表示协议数据单元 PPDU) | JPEG、MPEG、ASII |
应用层 | 允许访问OSI环境的手段(应用协议数据单元 APDU) | FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS |
IP 网际协议
IP 地址分类:
IP 地址 ::= {<网络号>,<主机号>}
IP 地址类别 | 网络号 | 网络范围 | 主机号 | IP 地址范围 |
---|---|---|---|---|
A 类 | 8bit,第一位固定为 0 | 0 —— 127 | 24bit | 1.0.0.0 —— 127.255.255.255 |
B 类 | 16bit,前两位固定为 10 | 128.0 —— 191.255 | 16bit | 128.0.0.0 —— 191.255.255.255 |
C 类 | 24bit,前三位固定为 110 | 192.0.0 —— 223.255.255 | 8bit | 192.0.0.0 —— 223.255.255.255 |
D 类 | 前四位固定为 1110,后面为多播地址 | |||
E 类 | 前五位固定为 11110,后面保留为今后所用 |
IP 数据报格式:
ICMP 网际控制报文协议
ICMP 报文格式:
应用:
- PING(Packet InterNet Groper,分组网间探测)测试两个主机之间的连通性
- TTL(Time To Live,生存时间)该字段指定 IP 包被路由器丢弃之前允许通过的最大网段数量
运输层
协议:
- TCP(Transmission Control Protocol,传输控制协议)
- UDP(User Datagram Protocol,用户数据报协议)
端口:
应用程序 | FTP | TELNET | SMTP | DNS | TFTP | HTTP | HTTPS | SNMP |
---|---|---|---|---|---|---|---|---|
端口号 | 21 | 23 | 25 | 53 | 69 | 80 | 443 | 161 |
TCP
- TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,其传输的单位是报文段。
特征:
- 面向连接
- 只能点对点(一对一)通信
- 可靠交互
- 全双工通信
- 面向字节流
TCP 如何保证可靠传输:
- 确认和超时重传
- 数据合理分片和排序
- 流量控制
- 拥塞控制
- 数据校验
TCP 报文结构
TCP 首部
TCP:状态控制码(Code,Control Flag),占 6 比特,含义如下:
- URG:紧急比特(urgent),当
URG=1
时,表明紧急指针字段有效,代表该封包为紧急封包。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据), 且上图中的 Urgent Pointer 字段也会被启用。 - ACK:确认比特(Acknowledge)。只有当
ACK=1
时确认号字段才有效,代表这个封包为确认封包。当ACK=0
时,确认号无效。 - PSH:(Push function)若为 1 时,代表要求对方立即传送缓冲区内的其他对应封包,而无需等缓冲满了才送。
- RST:复位比特(Reset),当
RST=1
时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。 - SYN:同步比特(Synchronous),SYN 置为 1,就表示这是一个连接请求或连接接受报文,通常带有 SYN 标志的封包表示『主动』要连接到对方的意思。
- FIN:终止比特(Final),用来释放一个连接。当
FIN=1
时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
UDP
- UDP(User Datagram Protocol,用户数据报协议)是 OSI(Open System Interconnection 开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,其传输的单位是用户数据报。
特征:
- 无连接
- 尽最大努力交付
- 面向报文
- 没有拥塞控制
- 支持一对一、一对多、多对一、多对多的交互通信
- 首部开销小
UDP 报文结构
UDP 首部
TCP/UDP 图片来源于:https://github.com/JerryC8080/understand-tcp-udp
TCP 与 UDP 的区别
- TCP 面向连接,UDP 是无连接的;
- TCP 提供可靠的服务,也就是说,通过 TCP 连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP 尽最大努力交付,即不保证可靠交付
- TCP 的逻辑通信信道是全双工的可靠信道;UDP 则是不可靠信道
- 每一条 TCP 连接只能是点到点的;UDP 支持一对一,一对多,多对一和多对多的交互通信
- TCP 面向字节流(可能出现黏包问题),实际上是 TCP 把数据看成一连串无结构的字节流;UDP 是面向报文的(不会出现黏包问题)
- UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如 IP 电话,实时视频会议等)
- TCP 首部开销20字节;UDP 的首部开销小,只有 8 个字节
TCP 黏包问题
原因
TCP 是一个基于字节流的传输服务(UDP 基于报文的),“流” 意味着 TCP 所传输的数据是没有边界的。所以可能会出现两个数据包黏在一起的情况。
解决
- 发送定长包。如果每个消息的大小都是一样的,那么在接收对等方只要累计接收数据,直到数据等于一个定长的数值就将它作为一个消息。
- 包头加上包体长度。包头是定长的 4 个字节,说明了包体的长度。接收对等方先接收包头长度,依据包头长度来接收包体。
- 在数据包之间设置边界,如添加特殊符号
\r\n
标记。FTP 协议正是这么做的。但问题在于如果数据正文中也含有\r\n
,则会误判为消息的边界。 - 使用更加复杂的应用层协议。
TCP 流量控制
概念
流量控制(flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收。
方法
利用可变窗口进行流量控制
TCP 拥塞控制
概念
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
方法
- 慢开始( slow-start )
- 拥塞避免( congestion avoidance )
- 快重传( fast retransmit )
- 快恢复( fast recovery )
TCP的拥塞控制图
TCP 传输连接管理
因为 TCP 三次握手建立连接、四次挥手释放连接很重要,所以附上《计算机网络(第 7 版)-谢希仁》书中对此章的详细描述:https://github.com/luchenqun/interview/blob/master/images/TCP-transport-connection-management.png
TCP 三次握手建立连接
【TCP 建立连接全过程解释】
- 客户端发送 SYN 给服务器,说明客户端请求建立连接;
- 服务端收到客户端发的 SYN,并回复 SYN+ACK 给客户端(同意建立连接);
- 客户端收到服务端的 SYN+ACK 后,回复 ACK 给服务端(表示客户端收到了服务端发的同意报文);
- 服务端收到客户端的 ACK,连接已建立,可以数据传输。
TCP 四次挥手释放连接
【TCP 释放连接全过程解释】
- 客户端发送 FIN 给服务器,说明客户端不必发送数据给服务器了(请求释放从客户端到服务器的连接);
- 服务器接收到客户端发的 FIN,并回复 ACK 给客户端(同意释放从客户端到服务器的连接);
- 客户端收到服务端回复的 ACK,此时从客户端到服务器的连接已释放(但服务端到客户端的连接还未释放,并且客户端还可以接收数据);
- 服务端继续发送之前没发完的数据给客户端;
- 服务端发送 FIN+ACK 给客户端,说明服务端发送完了数据(请求释放从服务端到客户端的连接,就算没收到客户端的回复,过段时间也会自动释放);
- 客户端收到服务端的 FIN+ACK,并回复 ACK 给客户端(同意释放从服务端到客户端的连接);
- 服务端收到客户端的 ACK 后,释放从服务端到客户端的连接。
TCP 有限状态机
TCP 有限状态机图片
Socket
Socket 中的 read()、write() 函数
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
read()
- read 函数是负责从 fd 中读取内容。
- 当读成功时,read 返回实际所读的字节数。
- 如果返回的值是 0 表示已经读到文件的结束了,小于 0 表示出现了错误。
- 如果错误为 EINTR 说明读是由中断引起的;如果是 ECONNREST 表示网络连接出了问题。
write()
- write 函数将 buf 中的 nbytes 字节内容写入文件描述符 fd。
- 成功时返回写的字节数。失败时返回 -1,并设置 errno 变量。
- 在网络程序中,当我们向套接字文件描述符写时有俩种可能。
- (1)write 的返回值大于 0,表示写了部分或者是全部的数据。
- (2)返回的值小于 0,此时出现了错误。
- 如果错误为 EINTR 表示在写的时候出现了中断错误;如果为 EPIPE 表示网络连接出现了问题(对方已经关闭了连接)。
Socket 中 TCP 的三次握手建立连接
我们知道 TCP 建立连接要进行 “三次握手”,即交换三个分组。大致流程如下:
- 客户端向服务器发送一个 SYN J
- 服务器向客户端响应一个 SYN K,并对 SYN J 进行确认 ACK J+1
- 客户端再想服务器发一个确认 ACK K+1
只有就完了三次握手,但是这个三次握手发生在 Socket 的那几个函数中呢?请看下图:
从图中可以看出:
- 当客户端调用 connect 时,触发了连接请求,向服务器发送了 SYN J 包,这时 connect 进入阻塞状态;
- 服务器监听到连接请求,即收到 SYN J 包,调用 accept 函数接收请求向客户端发送 SYN K ,ACK J+1,这时 accept 进入阻塞状态;
- 客户端收到服务器的 SYN K ,ACK J+1 之后,这时 connect 返回,并对 SYN K 进行确认;
- 服务器收到 ACK K+1 时,accept 返回,至此三次握手完毕,连接建立。
Socket 中 TCP 的四次握手释放连接
上面介绍了 socket 中 TCP 的三次握手建立过程,及其涉及的 socket 函数。现在我们介绍 socket 中的四次握手释放连接的过程,请看下图:
图示过程如下:
- 某个应用进程首先调用 close 主动关闭连接,这时 TCP 发送一个 FIN M;
- 另一端接收到 FIN M 之后,执行被动关闭,对这个 FIN 进行确认。它的接收也作为文件结束符传递给应用进程,因为 FIN 的接收意味着应用进程在相应的连接上再也接收不到额外数据;
- 一段时间之后,接收到文件结束符的应用进程调用 close 关闭它的 socket。这导致它的 TCP 也发送一个 FIN N;
- 接收到这个 FIN 的源发送端 TCP 对它进行确认。
这样每个方向上都有一个 FIN 和 ACK。
TCP三次握手和四次挥手的过程图
由上图可以看出,一共有11种不同的状态。这11种状态描述如下:
CLOSED:关闭状态,没有连接活动或正在进行;
LISTEN:监听状态,服务器正在等待连接进入;
SYN_RCVD:收到一个连接请求,尚未确认;
SYN_SENT:已经发出连接请求,等待确认;
ESTABLISHED:连接建立,正常数据传输状态;
FIN_WAIT 1:(主动关闭)已经发送关闭请求,等待确认;
FIN_WAIT 2:(主动关闭)收到对方关闭确认,等待对方关闭请求;
TIME_WAIT:完成双向关闭,等待所有分组死掉;
CLOSING:双方同时尝试关闭,等待对方确认;
CLOSE_WAIT:(被动关闭)收到对方关闭请求,已经确认;
LAST_ACK:(被动关闭)等待最后一个关闭确认,并等待所有分组死掉。
TCP三次握手
- 因为双方都需要确认对方收到了自己发送的序列号,确认过程最少要进行三次通信。
- 防止失效的连接请求报文段被服务端接收,从而产生错误。失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』。若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态。此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。
TCP四次挥手
- TCP四次挥手,由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。
- 确保数据能够完成传输。 关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你不需马上会关闭SOCKET,你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
TIME_WAIT状态
主动发起关闭连接的操作的一方将达到TIME_WAIT状态,而且这个状态要保持Maximum Segment Lifetime的两倍时间。为什么要这样做而不是直接进入CLOSED状态?原因有二:
一、保证TCP协议的全双工连接能够可靠关闭:如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
二、保证这次连接的重复数据段从网络中消失:如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
select、poll、epoll区别
比较 | select | poll | epoll |
---|---|---|---|
操作方式 | 遍历 | 遍历 | 回调 |
底层实现 | 数组 | 链表 | 哈希表 |
IO效率 | 每次调用都进行线性遍历,时间复杂度为O(n) | 每次调用都进行线性遍历,时间复杂度为O(n) | 事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到rdllist里面。时间复杂度O(1) |
最大连接数 | 1024(x86)或 2048(x64) | 无上限 | 无上限 |
fd拷贝 | 每次调用select,都需要把fd集合从用户态拷贝到内核态 | 每次调用poll,都需要把fd集合从用户态拷贝到内核态 | 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝 |
epoll触发模式
用英文来表示,水平触发为Level Trigger,边缘触发为Edge Trigger。
EPOLLET了代表ET事件,而epoll默认采取的是LT,也就是说在能够正确使用epoll之前,我们必须弄明白ET和LT,尤其是准备直接使用nonblocking和ET的朋友。
LT和ET原本应该是用于脉冲信号的,可能用它来解释更加形象。Level和Edge指的就是触发点,Level为只要处于水平,那么就一直触发,而Edge则为上升沿和下降沿的时候触发。听起来到时挺玄乎的,那么怎么区分这个Level和Edge呢?很简单,0->1这种类型的事件就是Edge,而Level则正好相反,1->1这种类型就是,由此可见,当缓冲区有数据可取的时候,ET会触发一次事件,之后就不会再触发,而LT只要我们没有取完缓冲区的数据,就会一直触发。
TCP与UDP的区别
1)基于连接与无连接
2)对系统资源的要求(TCP较多,UDP少)
3)UDP程序结构较简单
4)流模式与数据报模式
5)TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
6)TCP有拥塞控制和流量控制,UDP没有
TCP提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快
流量控制和拥塞控制的实现机制
网络拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致引起这部分乃至整个网络性能下降的现象,严重时甚至会导致网络通信业务陷入停顿,即出现死锁现象。拥塞控制是处理网络拥塞现象的一种机制。数据的传送与接收过程当中很可能出现收方来不及接收的情况,这时就需要对发方进行控制,以免数据丢失。
滑动窗口的实现机制
滑动窗口机制,窗口的大小并不是固定的而是根据我们之间的链路的带宽的大小,这个时候链路是否拥护塞。接受方是否能处理这么多数据了。 滑动窗口协议,是TCP使用的一种流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。
SOCKET通讯
服务器端:
1 获取电话线 socket()
2 分配电话号码 bind()
3 等着电话打来 listen()
4 接听电话 accept()
5 相互交谈 read()/write()
6 挂断电话 close()
客户端:
1 获取电话线 socket()
2 呼叫服务器 connect()
3 相互交谈 read()/write()
4 挂断电话 close()
长连接、短连接的区别和使用
长连接:client 方与 server 方先建立连接,连接建立后不断开,然后再进行报文发送和接收。这种方式下由于通讯连接一直存在。此种方式常用于 P2P 通信。
短连接:Client 方与 server 每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此方式常用于一点对多点通讯。C/S 通信。
使用时机:
长连接:短连接多用于操作频繁,点对点的通讯,而且连接数不能太多的情况。每个 TCP 连 接的建立都需要三次握手,每个 TCP 连接的断开要四次握手。如果每次操作都要建立连接然后再操作的话处理速度会降低,所以每次操作下次操作时直接发送数据 就可以了,不用再建立 TCP 连接。例如:数据库的连接用长连接,如果用短连接频繁的通信会造成 socket 错误,频繁的 socket 创建也是对资源的浪 费。
短连接:web 网站的 http 服务一般都用短连接。因为长连接对于服务器来说要耗费一定 的资源。像 web 网站这么频繁的成千上万甚至上亿客户端的连接用短连接更省一些资源。试想如果都用长连接,而且同时用成千上万的用户,每个用户都占有一个 连接的话,可想而知服务器的压力有多大。所以并发量大,但是每个用户又不需频繁操作的情况下需要短连接。