网络编程(二)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这个数据段,然后服务端再对受到的数据进行去重)