再上一篇文章中 介绍了关于网络编程中应用层的一些基本知识,
本文会着重讲解传输层中Tcp和Udp两种协议
在网络通信中,我们以“源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号”这样的一个五元组来标识一个通信。
端口号的范围是 0~65535,但在这其中还被划分为知名端口号和普通端口号
谈到端口号,就要说说与它捆绑使用的进程了。
端口号是有限的,那么是否可以重复利用呢?
回答一下
一个进程可以绑定多个端口号
一个端口号不能被多个进程所绑定
我们把进程想象成房间,把端口号想象成进入房间的门,是不是就可以具象化的理解了。
到了具体的企业开发中,是这样使用的。
就拿游戏来说
打开游戏,此时游戏就是一个进程,这个进程提供了两个端口号,一个供玩家进入,一个共开发人员进入。
游戏玩家进入游戏,可以享受正常的对局,但是对于游戏内的参数设置以及充值系统不能更改。
而开发人员进入游戏,可以设置对应的游戏参数,调整地图,优化系统,更爱游戏内氪金点数。
TCP (Transmission Control Protocol) 和 UDP (User Datagram Protocol) 是两种不同的网络传输协议。
UDP协议格式
源端口号和目的端口号,标明了这个数据报从哪里来,要到哪里去。
UDP长度: UDP数据报能传输64KB大小的数据
UDP长度在整个UDP数据报中占2个字节,也就是16位,能表示的范围就是0~65535.单位是字节 1024*64=65536。虽然UDP数据报的报头还有8个字节,64KB和64KB-8在实际的开发中,是忽略不计的,只要要传输的数据接近于64KB时,就需要注意了。
UDP校验和: 使用CRC的方式来完成。大致就是通过固定的公式来对要传输数据进行计算得到一个结果,发送方和接收方对两个结果进行比较,如果相等就说明传输的数据没有问题。感兴趣的可以去网上搜一搜相关的介绍,这里不就展开介绍了。
在数字电路中,电平通常用两个状态来表示,分别是高电平和低电平。 高电平表示逻辑1,低电平表示逻辑0。也就是计算机内部的那一串串的二进制数据,当受到电磁波、电信号、光信号的干扰时,可能就会发送比特翻转,造成数据传输的错误。
UDP传输的过程类似于寄信.
UDP的主要用途
应用于对性能要求高,但是对可靠性要求不高的场景
TCP是一种面向连接的协议,它在传输数据之前会建立一条专用的通信连接。这意味着在数据传输过程中,两台计算机之间会有一条稳定的数据传输通道。因此,TCP可以保证数据传输的可靠性,但会带来一定的延迟
TCP协议格式
TCP最核心的机制就是可靠传输
而实现可靠传输就时依靠确认应答机制来实现的,其中超时重传是对确认应答的重要补充。
对于用于应答的数据,称为应答报文
对于序号的解释:
TCP会将每个字节的数据都进行编号,即位序列号
例如:
发送端,发送一个TCP数据报,载荷中的字节TCP会对其进行编号,当接收端接收到数据报后,会获取到数据报中的序号,进行一系列的业务逻辑后,对发送端数据报的序号+1,作为确认序号,并将ACK的值设为1,返回给发送端。
返回的确认序号有两层含义
在传输过程中出现丢包这种情况,
主机A将数据发送给主机B后,等待主机B的确认应答
当一段时间后还没有收到主机B的确认应答消息,此时主机A就会重新发送。
主机A是如何判断是否收到确认应答的呢?
主机A是通过是否收到了“ACK“来判断是否收到了应答。
如果一段时间内没有收到ACK,那么就认为是发生了丢包,就会重新发送。
那么问题又来了,ACK有没有可能会丢失呢?
答案是 会
如上就发生了丢失ACK的现象。
此时,主机B就收到了两份相同的数据,这样的情况肯定是不能存在的,在你游戏充值界面,你充值了50元,而由于服务器卡顿,给你的账号增加了100快价值的游戏币,肯定游戏厂商不会允许这样的情况发生的。
TCP接收方这边会对接收的数据按照序列号来进行去重。
在TCP重复传输\重复接收是无所谓的,但会保证在应用层不会读取到重复的数据。
那么超时重传的时间间隔是多少呢?
这个时间不是一个固定值,是会随着重传次数的增加而变长,
当时间达到一定阈值,就会重置连接。触发一个”复位报文“来进行尝试重连
但是当网络出现严重的故障时,RST也无法触发重置
只能断开连接(通信双方清除对方的数据 例如端口号 IP地址等)
总结一下
通信是如何实现可靠传输的?
在发送方发送数据时,会对字节进行编号,这个编号连续自增,TCP报头中的序号只存储靠前个字节的序号,接收方在接收到全部数据后,会按照接收到的序号+1生成确认序列,这里的确认序号有两个作用,一是说明这个序号之前的数据都已经收到,二是接下来应该发送从确认序号开始的数据,并将报头中的ACK标识符的bit位更改1,生成应答报文返回给发送方。
通信中丢包怎么办?
TCP拥有超时重传这样的机制,当一段时间后,发送方没有接收到来自于接收端的应答报文时,会重新传输数据报。
这里的时间间隔怎么设置?
每次的间隔时间会变长,当到达一定阈值后,就会尝试重置连接
重置连接细节
此时会将报头中的RST标志位的bit位改为1,来进行重置连接。
此时 发送方和接收方就会清除互相的信息(端口号、IP地址等)
通信中出现重复的数据怎么办?
TCP拥有一个接收缓冲区(类似于带有优先级的阻塞队列),当数据到达时,就会进入缓冲区,当应用程序进行read时,就会将数据从缓冲区删除,那么TCP接收会在缓冲区按照序列号来对数据进行去重。
为什么会出现重复的数据?
因为发送方无法分辨是数据丢了,还是ACK丢了,如果是ACK丢了,就会收到重复的数据。
建立连接:三次握手
断开连接:四次挥手
握手:发送一个不含业务数据的数据报,不起到任何业务的作用,只是建立连接。
在上述过程中,服务端和客户端各自给对方发送一个SYN,再各自给对方返回一个ACK,实际上是四次交互。
其中,中间的ACK和SYN可以合并成一个数据报(这里是由内核完成的,当收到客户端的ACK同步报文后,立即生成ACK和SYN,这两是同一时刻由内核控制完成的
ACK的bit为1,SYN的bit为1
可以缩减为两次握手吗?
不可以,服务器对于通信双方的接收能力和发送能力的验证没能完成。
那么四次交互不是更直观吗?
这是因为三次的效率比四次要高。
在数据的传输过程中,要经过层层的封装和分用,多一次而带来的消耗就会很大。
三次握手的意义
三次握手协商
TCP通信时使用的序号,就是通过三次握手协商出来的。
靠前次连接和第二次连接,协商出来的起始序号,往往差别很大。
这是为了避免当一个数据报在网络中传输时,可能由于线路规划不明确,导致在网络中一直游转,当通信双方断开连接时生成新的连接时(上一个业务结束,执行下一个业务),此时这个数据报才送到接收端,这时接收端就会根据序号的差异(检查序号时候如果差异过大,就会将这个数据报直接丢弃掉),从而防止上一次业务的逻辑运行到这次的业务中。
客户端和服务端都可以先发起FIN(结束报文)
这里我们假定客户端先发起。
和三次握手是不是有点相似,那为什么三次握手就可以合并两次操作,而四次挥手不可以呢?
四次挥手的FIN和ACK报文可以合并吗?
在特殊情况下是可以的,但一般来说是不可以的。
在服务器看到大量的CLOSE_WAIT,可能是什么原因?
LISTEN - 侦听来自远方TCP端口的连接请求; SYN-SENT - 在发送连接请求后等待匹配的连接请求; SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认; ESTABLISHED - 代表一个打开的连接,数据可以传送给用户; FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认; FIN-WAIT-2 - 从远程TCP等待连接中断请求; CLOSE-WAIT - 等待从本地用户发来的连接中断请求; CLOSING - 等待远程TCP对连接中断的确认; LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认; TIME-WAIT - 等待足够的时间以确保远程TCP接收到连接中断请求的确认; CLOSED - 没有任何连接状态;
为什么会有TIME_WAI?
当服务器给客户端发送FIN后,客户端不能立即释放TCP连接(因为此时客户端还没有发送ACK给服务器,服务器一段时间没收到ACK就会重传FIN,当服务器重传FIN后,客户端还要将ACK返回给服务器,需要服务器的端口号等信息,所以不能立即释放),在一定时间段内,没有收到服务器重传的FIN,就说明ACK已经被服务器所接收。
在日常的业务背景下,有时会处理大量请求,这时,如果再一条一条发送,一条一条接收的话,效率非常低下。此时就引出华东窗口这样的机制了。
没错,就是算法题中的那个滑动窗口。
窗口大小指的是无需得到ACK应答就能发送数据的最大值,图中的窗口大小是2500个字节(五个段)
当一个段接收到ACK后,窗口就会向后移动,然后发送第六个段的数据
操作系统内核开辟了发送缓冲区来记录当前有哪些数据还没有应答,应答了的数据就会从缓冲区中删除。
窗口越大,传输的数据就越多,网络的吞吐率就越高。
如果发现丢包怎么办?
丢的是ACK包: 不影响,因为后续的应答数据报的确认序列会告诉进程,这个序列号之前的数据,都已经接收了。
丢的是TCP数据报: 有影响,
如上这样的处理方式称为快速重传
滑动窗口有什么意义呢?
TCP为了保证可靠性,牺牲了很多的效率,滑动窗口就是为了弥补效率的牺牲,而采取的一种办法。
但是即使采取了措施,效率还是没有UDP快。
流量控制其实是滑动窗口的一个控制窗口大小的补充。
接收端处理数据的速度是有限的,如果发的太快。接收端还没来得处理,接收端的缓冲区就满了,可能就会发生丢包,引起丢包重传等一系列问题。
因此TCP⽀持根据接收端的处理能⼒, 来决定发送端的发送速度. 这个机制就叫做流量控制(FlowControl);
和流量控制一样,是为了辅助滑动窗口使用的。
数据在网络的传输中,会经过很多网络结点。传输的速度就会受到这些结点的限制。
为了探寻传输数据的的最高效率,引入了阻塞控制
工作流程如下
流量控制的窗口和阻塞控制的窗口选择哪个呢?
谁小听谁的
注意
阻塞控制的窗口变化也是有相应的规律的。
在接收方接收到数据后,并不立即返回ACK,而是隔一段时间再返回ACK,这样可以提高传输速率
窗口越大,网络的吞吐量就越大,也就是说网络传输的速度也就越快
当接收方接收到数据后,处理数据需要时间,而延迟应答的这一段时间正好就可以处理数据,处理完数据后,缓冲区的空闲窗口就会变大,从而由流量控制来进行响应给出反馈,从而使得传输速度变快。
说到延迟应答,就又跟四次挥手联系在一起了,延迟应答这种机制就可以将四次挥手给合并成三次挥手哦,不过这只是特殊情况。一般的情况就还是四次挥手。
** 延迟应答的时间的规划**
捎带应答 就是将两个数据报的内容在满足业务逻辑的情况下,将几个数据报合并在一起。
例如在三次挥手中,就将ACK报文和SYN报文合并在一起了。
这样做的意义:
可以调高效率,减轻服务器的压力,因为一次数据的传输,需要经过层层的封装和分用,,将两次操作合并成一次,减少了很多工作量。
首先我们要明确,粘包问题粘的是应用层的数据报
为什么会出现这样的情况?
因为TCP协议报头并没有像UDP协议一样报头中有着报文长度这样的属性字段,所以不能确定一个数据报是多长而进行分割
站在传输层的角度来说,TCP是一个一个报文来的,按照序号排放在缓冲区中.
站在应用层的角度来说,看到的只是一串连续的字节数据,
应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分结束是一个完整的数据包。
说了这么多,那么该如何让避免呢?
TAG:udp协议