网络编程(二)TCP和UDP

认识UDP和TCP

TCP和UDP都是传输层中最经典的协议,传输层重点关注是将数据从发送端传输到接受端 ,二者都是全双工(一条链路能够进行双向通信)

UDP

协议端格式:

源/目的端口号:从发送端(源端口号)------>接收端(目的端口号)

注:16位UDP长度代表整个数据报的最大长度(UDP首部+数据),如果校验和出错会直接丢弃

UDP的首部为16位,也就是说UDP传输的数据最大长度为64K, 如果传输的数据>64k就需要在应用层手动分包,多次发送,然后在接收端拼装(数据太大了,只能分几次发了)

特点:

**无连接:**不需要建立连接,只需要知道接收端的端口号和IP就能够进行传输

**不可靠传输:**没有确认机制,没有重传机制(丢了就是丢了,没有售后),即使是因为网络故障导致也不会有任何的错误信息返回

**面向数据报:**不能够灵活的控制读写数据的次数和数量,每次读写操作的执行对象必须是一个完整的UDP数据报


TCP

协议端格式:

SYN: 请求建立连接,携带SYN标识的称为同步报文段

**ACK:**确认号是否有效(由服务器接收到客户端发送请求连接之后将同步报文段加上ACK发送给客户端)

FIN: 通知接收端,发送端要关闭连接(携带FIN标识的称为结束报文段

RST: 请求重新建立连接(携带RST标识的称为复位报文段

PSH:提示接收端应用从TCP缓冲区把数据读走

URG:紧急指针是否有效

特点:

**有连接:**TCP传输首先需要与服务器建立连接,再根据接收端的端口号和IP向接收端进行传输

**可靠传输:**TCP传输有确认应答机制,如果传输数据没有被接收端获取到,那么TCP就会重新进行传输(有售后)

**面向字节流:**读写操作灵活(例如文件操作也是字节流)


理解TCP协议的状态转化:

确认应答

TCP会给每个字节进行编号,也就是序列号,而每一个ACK也都带有对应的确认序列号,接收端通

过ACK的确认序列号来向发送端反映已经收到的数据

数据序列号意义:

1.能够通过序列号来匹配正确应答(因为网络编译会有"后发先至"的特性,通过序列号可以匹配到对应序列号的应答)

2.确认数据是否成功传输到对端


连接管理(三次握手建立连接,四次挥手断开连接)

三次握手(建立连接)

过程:客户端向服务器发送同步报文(SYN) ,服务器接收到之后加上应答报文(ACK)组成一个网络数据 一起返回给客户端,客户端接收到网络数据之后**给服务器发送应答报文(ACK)**结束。

三次握手(建立连接)的意义:

确定双方通信链路是正常的,才能进行数据传输

四次挥手(断开连接):

四次挥手的意义是告知对方,要终结此次连接,而提出断开连接的可以是客户端、服务端中的任意一方

过程:

**第一次:**客户端 ------>服务端:客户端发送FIN,告知服务端我要断开连接了,此时客户端已经没有数据要传输,服务端还可以接受数据(客户端establish------>FIN_wait1)

**第二次:**服务端------>客户端:服务端向客户端发送ACK,表示ojbk,我现在处理的数据编号是xxx,还有数据没有处理完(服务器从establish------>close_wait,客户端收到ACK变成FIN_wait2)

**第三次:**服务端------>客户端:服务端向客户端发送FIN,表示我处理完所有数据了,我也断开连接了(此时服务端close_wait------>last_wait,客户端收到FIN,从FIN_wait2------>time_wait)

**第四次:**客户端------>服务端:客户端向服务端发送ACK,表示知道了,双方都关闭,一方不再传输数据,一方不再接收数据


超时重传

在一定的时间内用来应对网络故障导致丢包的策略,发送端总是通过确认应答来验证数据是否传输到对端

可能情景:

①数据包传输的时候丢了,对端没接收到

②对端接收到之后,给发送端发送的确认号丢了(ACK丢了)

对于第二种情景,重传之后对端会接收到两份相同的数据,这时候TCP会对对端的数据进行去重操作(例如转账这种情景,发送重复转账那就是非常严重的错误!!)

超时重传的超时时间是否是具体化的?

不是,超时时间是随着重传轮数增加,第一次重传是50ms之后,没有接收到确认应答进行第二次重传,第二次重传可能是100ms,依次类推。


滑动窗口

动态调节传输效率:由于是全双工模式,所以滑动窗口适用于双端的数据传输

窗口的大小决定了数据的传输速率,假定客户端作为传输端,服务端作为接受端,接收端规定自身接受数据的窗口大小,然后传输端根据接收端的窗口大小来调节传输端的窗口大小

就好比,你接收端说我的快递柜只有四格,那传输端看你只有四个格子(窗口大小 ),每次只拿四个快递(数据 ),然后传输端把编号为1和2的快递发给接收端 ,接收端拿到了之后放到快递柜里,只有在接收端把1和2号快递从快递柜上拿走数据处理 ),传输端在接收端收到1和2号快递之后会更新最新的快递编号为3和4,并且把放在地上的5和6号快递补上来(因为窗口大小为4


流量控制

流量控制就是控制数据传输的速率,防止因为传输速率过快导致缓存区溢出

假定缓冲区大小是500,里面有接受未处理的数据占了300,此时因为传输速率过快导致有300的数据要传输给缓存区,缓存区的空间只有500-300=200,那就会有大小为100的数据被丢弃,触发重传机制,而这部分重传的数据只有等到缓存区释放出空间才会进行重传~

传输数据的时候,传输端的速率会根据窗口大小来调整,当缓存区已经满了的情况下窗口会被调整为0,不再传输数据直到缓存区释放空间


拥塞控制

这里要有一个概念,就是拥塞窗口。传输端传输数据是一个慢启动的过程,通常会先传输少量的数据试探当前的网络状况,每次传输成功之后就会扩大窗口大小,提高传输速率,遇到拥塞情况就匀速传输(不再倍速提高速率,呈线性增长),具有快重传、快恢复特性


延迟应答、捎带应答

延迟应答------接收端在收到一定的数据量才向传输端返回接收标识(ACK)

例如:传输端发10个数据,接受端每收到1个就要返回一次ACK告知传输端数据已经被接收,延迟应答就是改成每收到5个数据向传输端反馈,只需要反馈2次

延迟应答核心机制:

**时间阈值:**在一定的时间内没有数据交互就向传输端发送ACK包

**数据阈值:**每当接受端收到一定量的数据就会向传输端发送ACK包

**避免超时:**延迟应答的时间间隔不能超过或等于重传机制时长,超过这个时长会导致数据重传


捎带应答------接收端需要向发送端传输数据时,将ACK捎带在数据报文里,不需要单独传输ACK包

TCP面向字节流,粘包问题和解决方案

面向字节流:在使用TCP协议进行传输数据时,可以灵活读写,例如1个100字节长度的数据,可以利用TCP协议进行读写,1次读写100个字节长度/1次读写1个字节长度然后执行100次读写操作

"粘包问题":

这里的包针对的是应用层的数据包,数据包通过TCP协议传输到达的时候,应用层不知道具体数据长度,只识别到数据包有序列号,应用层看到的是一大串的字节数据(就是若干数据包紧挨着,但是你不知道这些数据包的界限在哪?那应用层怎么读取具体的数据?)

在这一点上,UDP和TCP就有所区别,UDP由于是传输数据报,数据报有报文长度,而TCP用的是序列号

解决方案: 确定数据包之间的边界

①对于定长的数据包,每次在进行读写操作的时候保证进行定长读取

②对于定长的数据包,在数据包的头部规定一个统计数据包总长的字段,这样每次读写就能知道数据包的结束点位

③对于边长的数据包,还可以在包与包之间用规定好的符号进行分割(不过这个需要程序员自行在应用层进行规定)

基于UDP实现可靠传输:

1.引入序列号,保证数据顺序;

2引入确认应答机制,保证对端接收到了数据;

3.引入超时重传,在一定时间内没有收到应答就重新传输

MTU对UDP和TCP的影响:

MTU对于数据片的最大传输单元是1500个字节,最小是46个传输字节(除去报头)

而UDP传输的数据报又不是定长的,如果数据包长度过大,需要进行数据分片,那么就会大大增加丢包的情况,导致收到的数据不完整,而且分片过后有一个包会没有ip报头

TCP面向字节流传输,如果遇到需要IP分片的情况,由于TCP的可靠传输机制,服务端会通过匹配序列号来确认数据是否传输到达,而服务端匹配的序列号如果不是对应的序列号就会让整段数据重传(例如:传输的数据段序列号是1-1000,然后由于分片变成了460和540,服务端先后接收到460和540然后进行匹配,因为要匹配的序列号应该是1000,所以服务端让客户端重新传输1-1000这个数据段,然后服务端再对受到的数据进行去重)