这里写目录标题
一、TCP
TCP/IP 网络分层(四层)
- 应用层
- 传输层
- 网络互连层
- 网络访问层
- 物理层
应用层
应用层主要是规定了应用程序之间如何相互传递报文,比如说 HTTP,它就规定
-
报文的类型,是请求报文还是响应
-
报文语法,报文分为几段,各段是什么意思、用什么分隔
应用层的协议还有:DNS域名解析协议,收发邮件SMTP
传输层
传输层就是为两台主机之间的应用进程提供端到端的逻辑通信;
但是并不是将数据包从一台主机传送到另一台,而是对「传输行为进行控制」
网络互联层
网络互连层提供了主机到主机的通信,就是将传输层产生的的数据包封装成分组数据包发送到目标主机,提供路由选择的能力
网络层的主要协议是IP协议,主要的作用就是给包加上源地址和目标地址,然后将数据包传送到目标地址
收到 IP 数据包解析以后,它怎么知道这个分组应该投递到上层的哪一个协议(UDP 或 TCP)
ip报文头部有上层协议的标识
网络访问层
网络访问层提供了主机连接到物理网络需要的硬件和相关的协议
分层的好处
- 各层独立:限制了依赖关系的范围,各层之间使用标准化的接口,不需要知道上下层是如何工作的,增加或者修改一个应用层协议不影响传输层协议
- 易于测试和维护:提高了可测试性,可以独立测试特定层,某一层有了更好的实现可以整体替换掉,可插拔性
- 标准化:每一职责清楚,方便进行标准化
1、TCP协议(需要补充)
TCP是一个可靠的,面向连接的,面向字节流、全双工的协议
-
可靠的: TCP 是在 IP 协议的基础上构建的传输层协议,IP 是一种无连接不可靠的协议,就是说IP协议只会将数据报从发送者传输给接收者,并不保证包到达的顺序和是否重复,甚至说,不会保证包是否到达接收者;所以说 TCP 必须通过自身的一些机制来保障可靠性(大概是从5个方面)
-
面向连接: 就是在发送数据之前需要握手建立连接,然后再结束通信时通过挥手来断开连接
-
字节流: TCP在传输层发送消息的时候,一个消息可能会被分割成多个TCP报文进行转发给网络层,我们不能单纯的认为一个TCP报文就是一个消息,它们之间没有一个固定的边界,所以TCP是面向字节流协议
TCP提供了一种字节流服务,而收发双方都不保持记录的边界,应用程序应该如何提供他们自己的记录标识呢?
TCP 这一层收发双方其实不好处理,会交给应用层处理,比如通过报文固定长度,不足补0;特殊前缀等
-
全双工: 在 TCP 中发送端和接收端可以是客户端,也可以是服务器,通信的双方在任意时刻既可以是接收数据的那一方也可以是发送数据的那一方,每个方向的数据流都独立管理序列号、滑动窗口大小、MSS 等信息
可靠性从5个方面来保证:
- 保证包一定到达: 每个TCP包首部中都有两个字节用来表示校验和,防止在传输过程中有损坏。如果收到一个校验和有差错的报文,TCP 不会发送任何确认直接丢弃它,等待发送端重传
- 解决包乱序和重复: 在TCP的包首部中有32位的确认序号,假设我们TCP发三个数据包,因为网络的原因导致第二个、第三个包先到接收端,第一个包最后到,接收端不会因为到达顺序和发出顺序不一样就把包弄错,TCP 会根据他们的序号进行重新的排列然后把结果传递给上层应用程序。如果 TCP 接收到重复的数据,可能的原因是超时重传了两次但这个包并没有丢失,接收端会收到两次同样的数据,它能够根据包序号丢弃重复的数据
- 超时重传: TCP 发送数据后会启动一个定时器,等待对端确认收到这个数据包。如果在指定的时间内没有收到 ACK 确认,就会重传数据包,然后等待更长时间,如果还没有收到就再重传,在多次重传仍然失败以后,TCP 会放弃这个包
- 流量控制:
- 拥塞控制:
UDP
TCP 是一个有状态的协议,需要先与对方建立连接然后才能发送数据,而且保证数据不丢失不重复。而 UDP 则比较简单,它无状态,不用事先建立连接就可以任意发送数据,但不保证数据一定会发到对方。两个协议的另一个重要区别在于数据的形式。TCP 的数据是连续的“字节流”,有先后顺序,而 UDP 则是分散的小数据包,是顺序发,乱序收。
2、TCP首部
端口号(源端口、目标端口)
TCP 的首部中会包含源端口号和目标端口号
端口号就是用来区分一个主机上不同应用程序的
端口号分为:
- 熟知端口号:HTTP、HTTPS
- 已登记端口号:MySQL、Redis
- 临时端口号
TCP 用两个字节的整数来表示端口,一台主机最大允许 65536 个端口号;
使用 netstat 和 lsof 来做一些端口号相关的操作
1、序列号
TCP 是面向字节流的协议,通过 TCP 传输的字节流的每个字节都分配了序列号,序列号指的是报文段第一个字节的序列号,序列号加上报文长度就可以确定传输的是哪一段数据,就可以保证包的顺序
序列号主要用来解决数据包乱序和重复的问题,数据包以正确的顺序组装传递给上层应用
初始序列号
初始序列号是在 TCP 三次握手之前生成的,三次握手握手的主要目的就是交换客户端和服务器各自的初始序列号
初始序列号是通过源地址、目标地址、源端口、目标端口和一个随机有因子通过MD5进行计算出来的,因为我们的 MD5 其实是一种摘要算法,如果仅有这几个因子的话,其实初始序列是很有可能相同的,所以我们就是把 MD5 算出来的结果加上时间因子,这样初始序列号就不会重复了
2、确认号
TCP 使用确认号ACK来告知对方下一个期望接收的序列号,小于此确认号数值的所有字节都已经收到
- 不是所有的包都需要确认的
- 不是收到了数据包就立马需要确认的,可以延迟一会再确认
- ACK 包本身不需要被确认,否则就会无穷无尽死循环了
- 确认号永远是表示小于此确认号的字节都已经收到
3、TCP 标记
TCP 有很多类型的数据包,它们各自的含义也不相同;TCP 首部有一个8比特位的标记位,不同类型的数据包只需要将对应的比特位置为1就行,并且这些标记可以组合使用,SYN+ACK,FIN+ACK
- SYN(Synchronize):用于发起连接数据包同步双方的初始序列号
- ACK(Acknowledge):确认数据包
- RST(Reset):这个标记用来强制断开连接,通常是之前建立的连接已经不在了、包不合法、或者实在无能为力处理
- FIN(Finish):通知对方我发完了所有数据,准备断开连接,后面我不会再发数据包给你了。
- PSH(Push):告知对方这些数据包收到以后应该马上交给上层应用,不能缓存起来
窗口大小
TCP 首部中有一个窗口大小,窗口大小表示的是接受端还有多少缓存区可以用来接收数据,当窗口变成 0 时,表示接收端暂时不能接收数据了;
窗口大小是在三次握手的时候确定的
这个窗口的大小是在不断变化的,因此也叫做滑动窗口就,流量控制就是基于滑动窗口来做的
滑动窗口的本质就是接收缓冲区空闲的空间,接收端会通过ACK包来告诉发送端窗口的大小,发送端根据窗口的大小来发送数据达到流量控制的目的
辅助信息(需要补充)
MSS TCP 允许接收的最大报文段
TCP 会主动把数据分割成小段再交给网络层,最大的分段大小称之为 MSS,为了避免被发送方分片
这样一个 MSS 的数据恰好能装进一个 MTU 而不用分片
- 数据链路层传输的帧大小是有限制的,不能把一个太大的包直接塞给链路层,这个限制被称为「最大传输单元(Maximum Transmission Unit, MTU)」
SACK 选择确认选项
Window Scale 窗口缩放选项
Timestamps 时间戳
- 发送方发送数据的时候,将自己的时间戳也发过去
- 接收方收到数据后,将收到的发送方的时间戳返回去,并且把自己的时间戳也放进去
这样做的好处是:
- 测量两端的往返时延(RTTM)
- 防止序列号回绕
3、TCP 三次握手(需要补充)
三次握手的目的是为了交换客户端和服务端的初始序列号还有交换一些辅助的信息
辅助信息:
- 最大段大小(MSS)
- 窗口大小(Win)
- 窗口缩放因子(WS)
- 是否支持选择确认
第一次握手:
客户端首先会确定一个初始序列号,然后会向服务端发送一个 SYN 报文,这个报文的 SYN 标记被置位,这个 SYN 报文的序列号就是我们的初始序列号,第一次握手的作用就是让服务端知道客户端的初始序列号
SYN 报文不携带数据,但是需要被确认,所以是会消耗一个序列号,下次发送数据序列号要加一
第二次握手:
服务端也会确认一个自己的初始序列号,然后向客户端发送一个 SYN 报文和一个 ACK 报文,这个 SYN 报文的作用就是告知客户端服务端的初始序列号;ACK 报文的作用是告诉客户端说,我收到你发的 SYN 报文了,你的下一个报