学习一个协议,很多时候就是在研究报文格式
16位UDP长度,表示整个数据报(UDP首部+UDP数据)的最大长度;
如果校验和出错,就会直接丢弃;
源端口号: 发送端端口号
目的端口号: 接收端端口号
UDP长度: 整个UDP的首部长度 与 数据的长度之和
校验和: 检测UDP数据报文在传输过程中是否有错,错误就丢弃。
能不能把UDP这里的端口改成4个字节之类的?
改不了…
报文长度是2字节,一个UDP最多就是65535 => 64k
1.无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接.
2.不可靠:没有任何安全机制,发送端发送数据报以后,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息.
3.面向数据报:应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并.
4.缓冲区:UDP只有接收缓冲区,没有发送缓冲区.
5.全双工:UDP的socket既能读,也能写.
6.大小受限:UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部).
源端口号: 发送端端口号
目的端口号: 接收端端口号
序号: 发送数据的位置.每发送一次数据就累加一次该数据字节数的大小.
确认序号: 下一次应该收到的数据的序列号.
首部长度: 表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60
保留: 为了以后拓展时使用,其长度位4位.一般设置为0.即使收的包在该字段不是0,也不会丢弃
这六个标志位,是TCP报文的核心字段:
URG: 为1时,表示包中需要紧急处理的数据,
ACK: 为1时,确认应答的字段变为有效
PSH: 为1时,需要将收到的数据立刻传入上层应用协议,为0时,则不需要立刻传而是先进行缓存
RST: 为1时,表示与TCP连接中出现异常必须强制断开连接,复位报文段
SYN: 为1时,表示希望建立连接.带SYN标识的称为同步报文段
FIN: 为1时,表示不会再有数据发送,希望断开连接.带FIN标识的为结束报文段
窗口大小: 通知从相同TCP首部的确认应答号所指位置开始能够接收的数据大小(8位字节).
校验和: 目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到检验和有差错,则TCP段会被直接丢弃。
紧急指针: 在URG控制位为1时有效(可以有,也可以没有,可有一个,也可有多个)
1.有连接
2.可靠
3.面向字节流
4.缓冲区:TCP有接收缓冲区,有发送缓冲区.
5.全双工
6.大小不受限
保证可靠传输的核心机制,发送方发出数据之后,能够知道对方有没有收到.
关键就是接收方在收到消息后,给发送方返回一个应答报文(ACK,ackknowledge),表示自己收到了.
举个例子:
A同学给B同学发消息:
这个相当于对确认应答进行了补充,确认应答是网络一切正常的时候,通过ACK通知发送方我收到了,如果出现丢包的情况,超时重传机制就起到了作用.
这主要是发送端没发送成功,还有接收端没应答成功,都会触发重传....
正常情况下,连续两次丢包概率还是很低的,假设丢包概率为10%,连续两次就是10% * 10% => 1%,如果重传一直失败,他也不会无休止重传,说明这时网络可能遇到了严重的问题,就只能放弃了(自动断开TCP的连接)
这个也是TCP保证可靠性的一个机制…
1)如何建立连接:
三次握手:
三次握手有啥用?和可靠性有啥关系?
三次握手,相当于是"投石问路",检查一下当前这个网络情况是否满足可靠性传输的基本条件,如果你的网络这时非常差,强行TCP传输,也会涉及到大量丢包,更具体地说,可以认为,三次握手其实就是在检测通信的双方,发送能力和接收能力是否都正常,就像打电话,开始你先对对面说:"喂喂喂,能听见吗?",对面回:"能听见,你能听见吗?",你说:"能听见",这个时候就可以确定这四个步骤是好使的,这也就意味着具备了可靠传输的前提条件...经历了三次握手,通信双方就能验证了各自的发送能力和接收能力都是ok的,接下来就可以进行后续的传输了.. |
滑动窗口存在的意义就是在保证可靠性的前提下,尽可能提高传输效率!!!
在这里,我们发现,每次执行一次操作,都需要等一次ACK,大量的时间就花费在了ACK上了
像这样,我们一次发了四组数据,在发送这四组数据的过程中,不进行等待,等四组都发完了,在统一等…
如果一次批量发送数据N,统一等待一波,此时这里N称为"窗口大小"
"滑动"的意思,并不用把N组数据的ACK都等到,才能继续往下发送,而是收到一个ACK,就继续往下发送一组,当前这图里发了四组,只要1001到了,就可以发送(4001 ~ 5000)这组数据了,依次发送
当然,如果在这里发生了丢包该如何重传?
像这种情况下的ACK被丢了怎么办?
没事,不必要处理!!!,在发送4001之前,发现只收到了2001,1001没收到.
他2001表示:2001之前的数据都已确认收到,只需要保证最后一个ACK收到了,前面的都是收到了的
这一种情况就会触发重传了:
由于1001 ~ 2000 这个数据丢了,然后B就会反复的索要1001这个数据,即使A给B已经往后发了,这时B任然在索要1001,当若干次后,A就发现了,就触发了重传,
A重传1001 ~ 2000后,2001 ~ 7000这些数据都是已经传过的,这些就没必要重传了,接下来B 就向 A 索要 7001 开始的数据..
流量控制是滑动窗口的延伸,目的是为了保证可靠性. 在滑动窗口中,窗口越大,传输速率就越高,这不光要考虑发送方,还得考虑接收方,如果发送方发的贼快,接收方根本处理不过来,接收方就会把新收到的包给丢了,发送方不就要重传了吗,所以发送方光图快是不行的.. |
流量控制的关键,就是要衡量接收方的速率,此处就直接使用接收方接收缓冲区的剩余空间大小,来衡量当前的处理能力…
接收方通过ACK报文来告知发送方剩余空间多大
通过16位窗口大小,来衡量当前接收方剩余空间大小,发送方收到这个数据之后,就会灵活调整发送速度(调整窗口大小)(虽然我说的16位,实际上窗口的大小不止64k,还可以更大)
这个也是滑动窗口的延伸,也是限制滑动窗口的速率
拥塞控制衡量的是,发送方到接收方,这个链路之间,拥堵情况(处理能力)
这个相当于流量控制的延伸,流量控制是踩下了刹车,发的不要太快,延时应答,就像在这个基础上,能够尽量的让窗口更大些
这个就像那个注水的同时出水,每次注入一波水,就问当前水池剩余空间是多少,采取的措施就是不立即回答,而是稍晚一点回答,迟一点回答,意味着在这个时间里,就会出更多的水,如果立即回答,剩余30吨可以注入,但是延时一点回答,还剩40吨可以注入(放了10吨了). 这个操作就是在有限的情况下,又尽可能提高了一点传输速度 |
这个不仅仅TCP存在粘包问题,其他面向字节流的机制,也存在,比如读文件.
TCP粘包问题 的粘 粘的是应用层数据报,在TCP接收缓冲区中,若干个应用层数据包混在一起了,分不出来谁是谁…
1)进程终止
在进程毫无防备的情况下,突然结束进程,这个时候该进程的TCP连接是咋样的? ==>TCP连接,是通过Socket来建立的,Socket本质上是进程打开的一个文件,文件其实就是存在于进程的PCB里面的 文件描述符表,每次打开一个文件(包括Socket),都在文件描述符表里增加一项.每次关闭一个文件,都在文件描述符表里,进行删除一行,如果直接杀死进程,PCB也就没了,里面的文件描述符表也就没了,此处的文件相当于"自动关闭"了,这个过程其实和手动调用socket.close(一样,都会触发四次挥手~) |
2)机器关机
按照正常流程关机,会让操作系统杀死所以进程,然后再关机,跟进程终止一样 |
3)机器掉电/网线断开
就像台式机,直接拔掉电源,操作系统不会有任何反应时间,更不会有任何处理措施, |
这个题其实就是考TCP,本质上就是在应用层基于UDP复刻TCP的机制-
实现确认应答机制. 每个数据收到之后,都要反馈一个ACK(应用程序自己定义一个 ack包)
实现序号/确认序号,以及实现去重
实现超时重传.
实现连接管理
要想提高效率,实现滑动窗口
为了限制滑动窗口,实现流量控制/拥塞控制
实现延时应答,捎带应答,心跳机制…
1:啥时候使用TCP? =>对可靠性有一定要求,(日常开发中的大多数情况,都基于TCP)
2:如果传输的单个数据报比较长(超过 64k) -> 首选 TCP
3:啥时候使用UDP? =>对可靠性要求不高,对于效率的要求更高(机房内部的主机之间通信,分布式系统中,广播就是首选UDP)