传输层:是负责应用程序之间的数据传输(通过端口的描述,描述了哪两个进程间的通信);传输层的两个主要协议:UDP 和 TCP
UDP协议全称:用户数据报协议(User Dategram Protocol, UDP)
协议典型特性:无连接、不可靠、面向数据报
用户数据报UDP有两个字段:报头字段和数据字段
报头字段包含4个内容:源端口号、目的端口号、UDP总长度、校验和。总共8个字节
1、源端口号:UDP源端口号:占16位,在需要对方回信时选用。不需要时可全为0;
2、目的端口号:UDP目的端口号,占16位,终点交付报文时使用
3、长度:UDP用户数据报的长度,占16位,其最小值为8(即仅有首部)
4、校验和:占16位,使用二进制反码求和算法,检测UDP用户数据报在传输过程中是否有错,出错则丢弃
校验流程:
发送端:(1) 把数据包的校验和字段置为0;(2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和;(3)把得到的结果存入到校验和字段中
接收端:(1)把首部看成以16位为单位的数字组成,依次进行反码求和,包括校验和字段;(2)检查计算出的检验和的结果是否等于0(反码应该为16个0);(3)如果等于0,说明被整除,校验和正确。否则校验和就是错误的,并将该数据报丢弃
无连接:在发送数据之前不需要建立连接,只要知道对方的地址信息就可以直接发送数据。
不可靠:不保证数据安全有序到达目的端。对于udp接收端来说,一旦报文过多就会因为溢出而使报文丢失;且udp只提供简单的检验和,当接收端进程通过检验和发现传输出错时,就会将出错的用户数据报直接丢弃----需要程序员在应用层提供必要的包序管理
面向数据报:有最大长度限制的传输方式----取决于数据报长度字段。因为长度字段只有16位,所以数据报总长度不能大于64k,也就是说sendto接口给予的数据报长度不能大于64k-8(报头占8个字节)的大小。若传输的数据比较大,则需要程序员在应用层进行分包操作,并提供包序管理。
udp通信在报头中确定了数据报长度,因此udp的数据的传输时整条收发的。在发送端,sendto接口给予的数据会放到发送缓冲区后直接封装头部,然后发送给接收端;在接收端,recvfrom总是只能接收一条完整的数据,而不会出现接收半条或者接收多条的情况。因此recvform给予的缓冲区一定要足够大,若给予的缓冲区大小 小于一条数据的长度,则recvform就会报错
缺点及解决办法:
1、不保证安全有序到达:需要在应用层使用tcp所使用的一些机制实现
2、不保证有序到达:需要在应用层进行包序管理
3、udp报文有最大长度限制:报文最大长度小于64k,因此发送大块数据的时候,需要在应用层进行数据分包进行发送
4、udp实现的是整条交付:因此接收方必须定义的缓冲区足够大,能够一次性取出一条数据
TCP协议全称:传输控制协议(Transmission Control Protocol, TCP)
协议典型特性:面向连接,可靠传输,面向字节流
TCP协议格式包含两个字段:TCP首部字段和TCP数据字段
1、源端口和目的端口:描述各端之间哪个进程在通信
2、序号:在TCP连接中传送的字节流中每一个字节都是按顺序编号
3、确认序号:实现tcp的包序管理,保证tcp数据是有序交付的
4、数据偏移/首部长度:描述tcp报头长度,tcp报头是不定长的,最小20字节,最大60字节 (长度是以4字节为单位计算长度的)
5、保留:为将来定义新的用途保留,现在一般置为0
6、6个控制位:URG
-紧急指针标志位,为1表示有效,为0表示忽略;ACK
-确认序号标志,为1表示有效,为0表示忽略;PSH
-Push标志位,指示接收方接收到带有Push标志的数据时,应尽快将报文段交给应用程序;RST
-重置连接标志位,为1时表示tcp连接出现错误,需要释放连接,然后重新建立传输连接;SYN
-建立连接请求标志位,为1时表示是一个连接请求或连接接收报文;FIN
-释放连接标志位,为1时表示发送方已经没有数据发送了,应释放连接
7、窗口:实现滑动窗口机制,控制对方发送的数据量
8、校验和:二进制反码求和算法,校验数据一致性
9、紧急指针:是一个带外数据,是与普通数据不同的通道独立传送给用户
10、选项数据和填充:主要用于协商以及描述一些信息
连接建立成功之后才能进行数据通信,tcp有自己的连接管理:三次握手建立连接以及四次挥手断开连接----网络 救救孩子吧,到现在还搞不懂TCP的三次握手四次挥手
可靠传输就是确保数据有序安全到达对端。可靠传输是由多种机制所实现的特性:面向连接、确认应答机制、超时重传机制、通过序号和确认序号实现数据有序交付、通过校验和字段校验数据一致性,不一致则要求对方进行重传、滑动窗口、拥塞控制
确认应答机制:发送数据后要求对方进行确认回复,才能知道对方是否收到了这条数据,通过序号与确认号实现
超时重传机制:发送数据等待确认响应超时之后,就会认为数据已经丢失,应该要进行重新传输。这个响应超时的时间默认一般在200ms左右,这是一个动态的时间,会随着发送数据后得到的响应的时间进行调整。
seq:本条数据的起始序号
ack:对对方发送数据的确认号,告知对方确认序号之前的数据我都收到了
三次握手时,双方会协商起始序号,起始序号为一个随机值。第一次握手时客户端数据起始序号假设为x;第二次握手,服务端收到后要进行确认回复,ack就等于客户端发送的起始序号+1,所以ack=x+1,然后要发送数据,起始序列号假设为y;第三次握手,客户端收到数据后要进行确认回复,ack就等于客户端发送的起始序号+1,所以ack=y+1,然后要发送数据,发送的数据的起始序号为上一次发送个给客户端的起始序号+1,所以seq=x+1
总结:seq=上次发送的起始序列+1;ack为对方发送的起始序列+1。
数据通信时,假设协商起始序号为x,发送的数据长度len为1024。服务端收到后要进行确认回复,ack就等于客户端发送的起始序号seq+数据长度len,所以ack=x+1024,然后要发送数据,起始序列号假设为y,长度为1024;客户端收到后要进行确认回复,ack就等于服务端发送的起始序号seq+数据长度len,所以ack=y+1024,然后要发送数据,起始序列号为上次发送数据的起始序号+数据长度,所以seq=x+1024;服务端收到后要进行确认回复,ack就等于客户端发送的起始序号seq+数据长度len,所以ack=x+2048,然后要发送数据,起始序列号为上次发送数据的起始序号+数据长度,所以seq=y+1024;
总结:seq=上次发送的起始序列seq+数据长度len;ack为对方发送的起始序列seq+对方发送的数据长度len
数据连续发送时,如果第一条数据丢失了,接收方直接收到了第二和第三条数据,接收方就不会对第二第三条数据进行回复。因为确认序号ack确认的是这个序号之前的数据全部已经收到。目的是防止因为确认回复的丢失导致对方的重传。
滑动窗口解决丢包问题:第一种是发送方发送的数据过快,接收方来不及取出,接收缓冲区满溢后,则下次接收的数据都会被丢弃;第二种是发送方发送大量的数据,但是因为网络状态不好导致大量丢包造成重传。
滑动窗口:解决由于发送过多或者过快造成接收端缓冲区满而导致的丢包问题----滑动窗口机制
拥塞控制:解决因为网络不好而导致发送的数据越多丢包的就越多的问题
拥塞控制原理是通过进行网络探测,以一种慢启动,快增长的传输方式,根据网络状态调整发送速度的机制。当网络状态优良时,传输的速度就很快;如果网络状态不好时,传输的速度就相对慢一些。
当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1字节的试探报文;当收到第一个字节的数据的确认后,就发送2个字节的报文;若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级;最后会达到一个提前预设的“慢开始门限”,比如24,即一次发送了24个分组。当出现网络拥塞,比如丢包时就会重新开始进行网络试探。
tcp提高传输性能的方式:
1、快速重传机制:发送端连续发送多条数据时,若接收端接收的数据并非是后沿起始序列的数据,则认为有可能后沿数据丢失,首先不会进行接收到的数据的确认回复,其次向发送端间隔连续发送三次后沿数据的重传请求,要求对方对后沿数据进行重传。发送方连续收到三条同一重传请求,则对这条数据进行重传。快速重传可以一定程度上避免发送端必要的超时重传。之所以是连续发送三次重传请求,是因为避免网络的延迟,数据报的延迟到达,三次可以有一个缓冲时间,若是两次的时候收到了后沿数据,则不再发送第三条重传请求,这时候发送端也就不用重传了。
2、延迟应答机制:接收方接收到数据之后,并不立即进行确认回复(因为如果立即确认回复,接收端的窗口就变小了,导致传输的吞吐量变小了)而是延迟应答,则有可能应答的时候程序在上层已经将数据取出,保证窗口大小不会变小,从而提高传输数据的吞吐量
3、捎带应答机制:接收方接收到数据之后,进行确认回复,确认回复就是一个报头中的确认序号进行的,为了减少空报头的响应占据带宽,则使用捎带应答,在即将要发送的数据头部中进行上一条接收到的数据进行确认回复
字节流:字节流传输服务,是面向连接的,有序的一种最小以字节为传输单元的传输方式
发送端在send发送数据的时候,并不会立即封装报头,而是将数据先放到发送缓冲区中,选择合适的时候再去从缓冲区中取出合适大小的数据进行传输
接收端在recv接收数据的时候,并非一条一条向上交付,而是根据recv想要的数据长度从接收缓冲区中取出指定长度的数据进行交付
优点:发送灵活,大量小的数据会集合成一条大的数据进行一次性发送,减少了IO次数从而提高了性能;接收方接收是也更加灵活,想取多少取多少
缺陷:tcp交付的这条数据可能并非一条完整的数据,也有可能是多条数据,tcp对上层给予的数据边界并不敏感,不关注是几条数据,只关注自己可以传输多少字节的数据和接收多少个字节的数据----粘包问题。而udp对每条传输的数据都有边界区分,每次刚好就只交付一条完整的数据
tcp的粘包问题:tcp有可能将多条数据当做一条数据进行处理,发送接收两端都有可能发送粘包问题,发送端有可能将多条数据当做一条发送,接收端也有可能将多条数据当做一条处理
粘包问题的解决方案:
程序员在应用层进行数据的边界管理
1、每条数据之间以特殊字符进行间隔(数据带有特殊字符需要转义处理,增加了应用层的处理操作过程)
2、数据定长传输,每条数据的长度都是固定的(数据短小时要进行补位,传输了大量的无用数据)
3、应用层协议头部中定义数据长度----http/udp
http:http头部以\r\n\r\n特殊字符间隔表示结束,并且在头部中通过Content-Length确定正文长度
udp:在传输层就进行了粘包的解决,头部定长8字节,头部中也定义了数据报长度,接收端只要取出报头,根据数据报长度取出对应长度的数据即可