TCP/IP协议模型
五层及常用协议
| 应用层 | HTTP、FTP、telnet、ssh |
| 传输层 | TCP、UDP |
| 网络层 | ICMP、IP、IGMP |
| 数据链路层 | ARP、RARP、CSMA/CA |
| 物理层 | 802.11系列协议 |
端到端和点到点
应用层和传输层使用端到端协议,也就是说,应用关心的是一端到另一端的通信,比如A访问B的上的一个网站,那么端到端协议解决A和B怎么解析俩者之间的数据,而对这些数据怎么一步一步在A和B之间来回不关心,而网络层正好是解决这个问题,所以说网络层使用点到点协议,这里更为准确的说,A和B不是一台主机,而是主机上的一个进程,由于一台主机上一般会有多个进程,那么A发送的数据到B所在的主机上,为了能够正确的送给B,需要给B一个端口,让B接收到数据
端口号
一般会预留1~1023的端口是保留端口,是给超级用户的进程专门保留的。常见的默认端口 http 80,https 443,mysql 3306,FTP 20 21,Telnet 23,ssh 22,rsync 873,smtp 25,ldap 389,ntp 123
ipv4地址
| A | 0 7位网络号 24位主机号 | 0.0.0.0 ~ 127.255.255.255 |
| B | 1 0 14位网络号 16位主机号 | 128.0.0.0 ~ 191.255.255.255 |
| C | 1 1 0 21位网络号 8位主机号 | 192.0.0.0 ~ 223.255.255.255 |
| D | 1 1 1 0 28位多播组号 | 224.0.0.0 ~ 239.255.255.255 |
| E | 1 1 1 1 0 27位 | 240.0.0.0 ~ 255.255.255.255 |
子网掩码和网段
ip地址网络号部分对应1,主机号部分对应0,转换后的结果就是子网掩码,所以B类地址对应的子网掩码就是255.255.0.0,其中某一个网段就是128.0.0.1/16,C类地址对应的子网掩码就是255.255.255.0,某一个网段192.168.0.1/24, 看俩个ip是否在同一个网段,将ip与对应的子网掩码按位AND,结果相同就表明这俩个ip在同一子网络,可以直接通信
ICMP
报文格式
不同类型和代码的报文有着不同的格式,但是前四个字节的格式是一致的。


从上图可以看到,icmp报文分为查询报文和差错报文,对于差错报文,必须在报文数据部分先填充生成该差错报文的IP数据报的首部,包含选项部分,但是一般IP数据报都不包括选项部分,所以是20个字节,然后包括跟在首部的后面8个字节
PING
ping程序使用的icmp的回显请求和回显应答报文

一般标识符是发送进程的id号。由于防火墙等保护措施的存在,主机之间可能无法进行端口之间的访问,但是icmp报文一般不会被屏蔽,其实也可以被屏蔽,那么就可以通过选项部分自定义数据格式,借助可正常通信第三方主机搭建icmp隧道。
IP网际协议
报文格式

1 | |
选路
路由表
可以使用netstat -rn或者route -n查看路由表
1 | |
RIP 选路信息协议
一句话总结,每个节点将自己的路由表定期发送给相邻的节点,节点在接收到相邻节点的路由表后,更新自己的路由表,问题是,当一个节点突然下线,就会导致需要过很长的时间,所有的路由表才能被通知到
OSPF 开放最短路径优先
路由器主动测试与邻站相连链路的状态,将这些信息发送给其他邻站。邻站将这些信息在自洽系统中传播出去,相对RIP的优势:
- 直接使用IP报文,而不是UDP,在IP报文的格式中有自己的“协议”,
- 对于到达一个节点有着相同费用的路径时,OSPF可以平均分配流量
- 支持子网
- 没有“坏消息”传递很慢的问题
- … …
BGP 边界网关协议
TCP
可靠性
tcp是提供可靠的,面向连接的服务,如何保证可靠性?
- 应用数据被分割为最适合发送的数据块
- 发送出一个段后,讲启动一个定时器,如果没有及时收到一个确认,将重发这个报文段
- 当接收到另一端的数据,将发送一个确认
- 有着首部和数据的校验和,ip只有首部校验和
- tcp会对分片的报文段重新排序
- 有着流量控制
报文格式

1 | |
三次握手和四次挥手

为什么需要三次握手?
因为如果没有第三个报文段,那么接收连接的主机无法确认发起主机是否在线。
为什么要四次挥手?
接收端第一次发送报文是尽快响应,待接收端接收/发送完数据后,发送第二个报文告知发送端自己准备断开连接了;而发送端必须再在放FIN的ack,告知接收端自己确定断开连接了,
为什么发送端发送完FIN的ack后需要等到2MSL时间才关闭连接?
如果最后一个报文没有被接收端接收,那么接收端就会再发送一个FIN,所以不能立即关闭;如果时间少于2 MSL,那么新的五元组就会受到旧的报文段的干扰
Nagle算法
一个TCP连接上,最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前,不能发送其他的小分组。TCP收集这些小分组,并在确认到达之时,用同一个分组发送出去。
比如,在使用ssh连接远程主机的时候,在命令行里输入命令的时候,总是等待一行命令输入完毕,然后再发送。但是,使用图形界面连接远程主机的时候,鼠标的移动需要实时显示在本机图形界面上,这时就需要关闭nagle算法,比如,nginx配置中的tcp_nodelay on就是用于关闭nagle算法的。
粘包问题:在发送端开启Nagle算法后,那么应用层的数据可能不是完整的,某一个tcp包中的应用层数据前半段是一个完整数据段,后半段是一个数据段的前面部分,这样,在接受端接受到这个数据后,发送给应用层的数据无法被应用层正确处理,只能等待完整数据到齐;另外,如果接收方的应用层处理数据慢与接受速度,那么多个包就会被缓存,这样应用层就会读到多个首尾相连的包。发送关闭Nagle算法,或者接受方在应用程序在处理从缓存读来的分组时,读完一条数据时,就应该循环读下一条数据,直到所有的数据都被处理
滑动窗口
如果每发送一个报文段,都要等待接受端的确认,实在是低效,那么考虑发送多个数据等接受端一次性确认可以提高效率,但是就要考虑究竟发送几个数据才等待确认,发送的数据的顺序如何保证,这是滑动窗口所解决的问题。
发送端有一个发送窗口,接受端有一个接受窗口,发送端可以一直发送报文段,直到可用窗口大小为0,对于已发送但是未被确认的报文,将暂时缓存,预备超时重传,接受端只对按序到达的数据中最高序号发送确认报文,对于未按序接收到的报文,也是先缓存,等待按序的其他报文全部到达后再发送确认。
接受窗口的大小取决于应用、系统、硬件的限制,发送窗口的大小取决于接受窗口,接受端可以在确认报文中指明自己的接受窗口大小,从而控制发送端的发送速率,达到流量控制的效果。

拥塞窗口
滑动窗口只关心俩端发送和接受能力,但是实际发送时,如果只考虑接受端的性能,不断发送报文段,可能会导致网络拥塞,比如发现一个报文段超时了,那么说明此时的中间网络很拥挤,但是tcp的超时重传机制会让发送端重新发送这个报文段,这就会导致中间网络更加拥挤,所以实际发送报文段的时候,还有一个指标控制报文段的发送,避免中间网络拥挤,这个指标就是拥塞窗口。
控制拥塞的四个算法:
- 慢启动:一个主机加刚加入一个网络时,拥塞窗口从一个初始值缓缓增大,线性增长,超过RTT后加倍,指数增长,直到超过阈值,一般是65535字节,进入拥塞避免
- 拥塞避免:每过一个rtt,窗口自增1
- 拥塞发生:当发现网络拥塞时,即发生丢包,拥塞窗口直接变回初始值,而阈值直接变为发生丢包时的拥塞窗口的一半
- 快速恢复:当接收端再收到比期望序号大的报文时,会重复发送最近一次确认信号,称为冗余ack,发送端接收到三个相同的冗余ack,便知道哪个报文丢失,于是立即重发该丢失报文,接下来执行拥塞避免算法。

坚持定时器
由于TCP不会对ack进行确认,如果接收端宣布了滑动窗口为0,则发送端会停止发送报文,直到接收端发送了一个非零的窗口,但是,如果对这个信息的ack丢失了,连接双方会进入死锁的情况,为了避免这种情况,要使用tcp坚持定时器去避免。
当发送TCP收到一个窗口大小为零的确认时,就启动坚持计时器 。 当坚持计时器期限到时,发送TCP就发送一个特殊的报文段, 叫做 探测报文段 。这个报文段只有一个字节的数据。它有一个序号,但它的序号永远不需要确认;甚至在计算对其他部分的数据的确认时该序号也被忽略。探测报文段提醒对端:确认已丢失,必须重传。
坚持计时器的值设置为重传时间的数值。但是,若没有收到从接收端来的响应,则需发送另一个探测报文段,并将坚持计时器的值加倍和复位。发送端继续发送探测报文段,将坚持计时器设定的值加倍和复位,直到这个值增大到门限值( 通常是60秒 )为止。在这以后,发送端每隔60秒就发送一个探测报文段,直到窗口重新打开。
UDP
报文格式

校验和
在进行校验时,UDP数据报和TCP段都会有一个12字节的伪首部,上图中的17是UDP的代码,TCP是6,ICMP是1,IGMP是2。伪首部是为了让数据报能够确保源ip和目的ip正确,并且确保数据被正确的协议所解析。
DNS
报文格式
