目录
1.UDP协议
1.1 UDP协议的包头信息:
1.2 UDP特点
2.TCP协议
2.1 TCP包头(变长的)
2.2 可靠性分析:
2.3 可靠性机制——确认应答(确认序号)+ 超时重传
2.4 连接管理——三次握手
2.5 连接管理——四次挥手
2.6 部分面试题:
2.7 流量控制 VS 拥塞控制
2.8其他机制:
3.UDP & TCP
定长——8个字节,容易做解包
16位源端口 + 16位目的端口 + 16位UDP长度(决定了能传输的数据最大长度是64K) + 16位校验和(校验和就是为了防止数据错误,类似hash算法,发方计算得到校验和,收方用相同hash计算,比对数据,如果收端的hash值与发端的hash不一致,会直接丢弃)
无连接的(不用连接就发送);
不可靠的(只管发,至于发成功没,发正确没是不能确定的)
面向数据报文(从应用层来的数据,我收到就直接发,不会拆分也不会合并,也没有发送缓冲区)
职责:
进程-进程通信
TCP是可靠的(但不能保证是安全的)
TCP会尽自己最大努力,将数据发给对方
如果真的发不过去,TCP至少会告诉进程,让进程知道我没发过去,数据失败了(UDP不可靠就在这里,任何反馈信息都没有,发出去就不管了)
校验和也保证了我数据大概率无错
TCP可以保证收到的数据一定是有序的,按照发放顺序
TCP会根据对方的接收能力和网络线路的承载能力,进行流量的控制
确认-应答机制——对方的TCP对收到的TCP数据确认应答,通过32位序号SN和32位确认序号ASN实现
确认应答机制:
【双方维护各自的SN,ASN则是对对方SN的回应】
超时重传机制:
如果没有收到应答:
可能对方确实没有收到?
可能对方的应答还没来?
可能对方的应答丢包了?
总之,发方不应该无限期等下去,可以定一个时限
无论哪种情况,发方是不管的,如果超过了时间还没收到,发方就重发一份,这就要求 收方 要有去重能力(根据序列号去重),收方对于已经收到的丢弃就行;
发方也不应该无限的超时重传,所以,超时重传的次数也有限
达到上限次数后,就实在没办法了,所以TCP会关闭连接再通知进程(以异常返回),最后的最后,TCP会发送 reset segment 出去给收方(最后的努力)
什么是连接?
TCP有接收缓冲区,有发送缓冲区
TCP需要维护发送时的序号SN
TCP需要维护接收到的确认序号
每次连接都需要各自维护这些信息(对OS来说,TCP全部共享一块区域)
这些属性的集合被TCP抽象出 连接 的概念
为什么要建立连接?
确认对方存在;
交换必要数据(SN,ASN)
建立连接——三次握手
(除上述信息,还需维护连接状态)
从标志位角度看三次握手:
【按规定,第三次ack那里,才允许携带数据】
从序列号角度看三次握手:
从TCP状态变更角度看三次握手:
【TCP连接是全双工的,只要连接通了,谁发消息谁先发都行】
具体到代码实现中:
通过四次挥手操作,断开双方的连接:
请求断开连接的标志位是 FIN
四次挥手其实也可以合并,但是并不要求
如合并为三次:
FIN——FIN+ACK——ACK
如双方同时关闭:
状态转移图:
如:
(1)为什么要有TIME_WAIT这个状态,而不是直接close?
TIME_WAIT状态用于冷搁置
如果直接变close状态,有可能这一个进程的信息还在,如5元组信息,可能被再次使用,导致新连接的数据不知道该给哪个
防止最后一个数据丢失来数据重传
(2)想一想,为什么是TIME_WAIT的时间是2MSL?
(3)异常关闭连接
RST标志位——收到 reset segent后,TCP直接关闭连接,然后进程收到一个异常
(4)TCP异常情况
直接使用任务管理器关闭进程——该进程的TCP连接会:OS是知道是哪些连接的,OS会控制四次握手正常关闭
点击重启/关机——运行着的进程的连接也会正常关闭(OS控制)
断电关闭电脑——什么都不会发生,我这边来不及做任何处理,对面也不知道发生了啥,不会处理——>直到对方有写操作,然后多次超时重连,才会发现问题,但仍然不知道是线路的问题还是对方的问题,如果对方只有读操作,也是永远发现不了问题的——>所以一般也会给读操作增加一个超时时间,再定期给对方发消息(heartbeat心跳包)
线路出问题——同上,只读发现不了问题
流量控制——TCP支持根据接收端的处理能力,来决定发送端的发送速度
拥塞控制——根据网络承载能力进行控制
(1)流量控制
知道对方的接收能力(即对方的接收缓冲区中还能装多少)——接收窗口报头信息中的窗口大小就是接收能力大小
发送方的发送量<=对方的实时窗口大小——发送方利用滑动窗口机制进行发量控制
滑动窗口:
(2)拥塞控制
知道网络的承载能力——拥塞窗口
发送量:发送窗口 = f(拥塞窗口,接收窗口),f函数可以是取最小
最后同样按照滑动窗口机制进行控制
【重点区别:知道网络承载能力】:
无精确值,只能通过算法来推算————这里介绍的是90年代的老的算法
慢开始+快增长(指数阶段+加法阶段)
慢开始:初始值为1
快增长:指数增长——引入一个叫做慢启动的阈值ssthresh,当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长
在遇到好像网络阻塞,超时重发的时候,慢启动阈值会变成原来的一半
单位时间内,重传次数超过一定值就认为网络阻塞,拥塞窗口置回1
报头中的其他信息:
URG+16位紧急指针
PSH=0,运行TCP把收到的数据暂存一段时间,集齐一定数量后再给应用层
选项:其他扩展信息
假设接收端缓冲区为1M。一次收到了500K的数据;
——>如果立刻应答,返回的窗口就是500K;但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;
——>在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;
——>如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M;
但也不是所有的包都可以延迟应答:
数量限制:每隔N个包就应答一次;时间限制:超过最大延迟时间就应答一次;
不再是一回一发,而是我在回的同时顺带把我要发的数据也附加上,就是既应答又请求
当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK,就像是在提醒发送端 "我想要的是 1001" 一样
——>如果发送端主机连续三次收到了同样一个 "1001" 这样的应答,就会将对应的数据 1001 - 2000 重新发送;
——>这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中;
——>这种机制被称为 "高速重发控制"(也叫 "快重传")
主要区别:
网络编程时如何选择合适的传输层协议?
UDP如何变成可靠的?
——>把它变成tcp呗,tcp有的他都可以借鉴: