🥁作者: 华丞臧.
📕专栏:【网络】
各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞+收藏+关注
)。如果有错误的地方,欢迎在评论区指出。
推荐一款刷题网站 👉 LeetCode刷题网站
文章目录
一、再谈端口号
端口号用来标识一个主机上进行通信的不同的应用程序。
在TCP/IP协议中,用“源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号”这样一个五元组来标识一个通信。
网络协议TCP/IP协议是在内核中实现的,本质是使用C语言实现的。
1.1 端口号范围划分
- 0~1023:知名端口号,HTTP、FTP、SSH等这些广为使用的应用层,他们的端口号都是固定的。
- 1024~65535:操作系统动态分配的端口号,客户端程序的端口号,就是由操作系统从这个范围分配的。
1.2 知名端口号
ssh
服务器:22ftp
服务器:21telnet
服务器:23http
服务器:80https
服务器:443
使用如下命令可以看到知名端口号:
cat /etc/services
1.3 认识两个指令
netstat
netstat是一个用来查看网络状态的重要工具。
语法:netstat [选项]
功能:查看网络状态
常用选项:
- n 拒绝显示别名,能显示数字的全部转化成数字。
- l 仅列出有在 Listen (监听) 的服務状态。
- p 显示建立相关链接的程序名。
- t (tcp)仅显示tcp相关选项。
- u (udp)仅显示udp相关选项。
- a (all)显示所有选项,默认不显示LISTEN相关。
pidof
在查看服务器的进程id时非常方便。
语法:pidof [进程名] 。
功能:通过进程名, 查看进程id。
二、UDP协议
2.1 UDP协议端格式
- 16位端口号:表示数据从哪个进程(源)来,要到哪个进程(目的)去。
- 16位UDP长度,表示整个数据报(UDP首部+UDP数据)的最大长度,16位为64KB。
- 检验数据某些字段是否出错,如果检验和出错,数据报会被直接丢弃。
//udp报头格式类似
struct udp_hdr
{
unsigned int src_prt:16;
unsigned int dst_prt:16;
unsigned int udp_len:16;
unsigned int udp_check:16;
}
2.2 UDP的特点
- 无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接。
- 不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。
- 面向数据报:不能够灵活的控制读写数据的次数和数量。
面向数据报
应用层交给UDP多长的报文,UDP原样发送,既不会拆分也不会合并。
- 用UDP传输100个字节的数据:如果发送端调用一次sendto发送100个字节,那么接收端也必须调用对应的一次recvfrom接收100个字节,而不能循环调用10次recvfrom每次接收10个字节。
UDP缓冲区
- UDP没有真正意义上的发送缓冲区。调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。
- UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了, 再到达的UDP数据就会被丢弃。
UDP使用注意事项
我们注意到,UDP协议首部中有一个16位的最大长度,也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)。然而64K在当今的互联网环境下是一个非常小的数字。如果我们需要传输的数据超过64K, 就需要在应用层手动分包多次发送,并在接收端手动拼装。
基于UDP的应用层协议
- NFS:网络文件系统
- TFTP: 简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议(用于无盘设备启动)
- DNS:域名解析协议
三、TCP协议
TCP全称传输控制协议,是一个对数据的传输进行详细控制的协议。
3.1 TCP协议段格式
- 源端口和目的端口:表示数据从哪个进程来,要到哪个进程去。
- 4位TCP报头长度:表示该TCP报头有多少个4字节数,所以TCP最大长度为15 * 4 = 60字节。
- 6位标志位:
- URG:紧急指针是否 有效。
- ACK:确认序号是否有效。
- PSH:提示接收端应用程序立刻从TCP缓存区把数据读走。
- RST:请求重新连接,对方要求重新建立连接; 我们把携带RST标识的称为复位报文段。
- SYN:请求建立连接; 我们把携带SYN标识的称为同步报文段。
- FIN:请求断开连接,通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段。
- 16位检验和:发送端填充,CRC检验,接收段效验不通过,则认为数据有问题,检验包括TCP首部和TCP数据。
- 16位紧急指针:标识该部分数据位紧急数据。
3.2 确认应答(ACK)机制
TCP提供可靠传输,那么TCP是如何实现可靠传输的呢?首先要明白什么是可靠传输–保证数据不丢包、检验和不出错,且有序接收,确认应答机制就是TCP保证可靠传输的一个机制。
TCP将每个字节的数据都进行了编号即为序列号,每个ACK都带有对应的确认序列号,告诉发送者我已经收到哪些数据了下一次应从哪里开始发送。
3.3 超时重传机制
在网络通信中,可能存在各种各样的情况导致数据无法送达到目的主机,为了保证可靠性,TCP提供了超时重传机制。
- 主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;
- 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。
3.4 链接管理机制
在正常情况下,TCP需要经过三次握手建立连接,四次挥手断开连接。
-
TCP是面向连接的,需要对TCP连接进行监听这无疑会付出性能的损耗。
-
三次握手的目的是保证通信双方能正常的收发信息。
-
三次握手能够让服务端将TCP连接的代价嫁接到请求方,这样可以避免一台主机发送大量SYN请求从而导致服务器挂掉。
-
四次挥手的目的是确保通信双方安全的断开连接。
-
首先发起断开连接的一方,在接收另一方的FIN请求后,会进入TIME_WAIT状态,TIME_WAIT状态会持续两个RTT时间(往返时间),在此期间端口号不会被释放。
可以将四次挥手中第一个ACK和第二FIN请求合并形成三次挥手呢?
观察四次挥手过程可见,
FIN2
包含了ACK1
中的确认值,因此三次挥手只能将FIN2
和ACK1
合并。但这样合并是有问题的,被动关闭方发送ACK1
只是确认主动关闭方发来的结束报文段,但并不代表自身的数据已经传输完毕。即当断开连接时,一个方向的断开,只是说明该方向数据已传输完毕,而另一方向或许还有数据,所以要等到另一个方向数据也全部传输完成后,才能实现四次挥手。但是这个时间不确定,因此会导致主动关闭方的结束报文段长时间未得到响应而进行超时重传等等,造成了资源浪费或者其他的问题。
注意:TCP面向连接的全双工传输控制协议,因此对于TCP协议的两端来说断开连接是必须双方都要断开,而每一端的FIN请求都是关闭自己的发送端口,因此需要两端互发一次FIN请求并收到ACK应答。这里面试官可能会问ACK1和FIN2合并会有什么问题。一端断开另一端的数据可能并没有发送完,所以最好不合并。
3.5 滑动窗口
确认应答策略规定,对每一个发送的数据段都要给一个ACK应答,收到ACK后再发送下一个;但是这样会导致网络通信性能较差,尤其是网络通信还存在各种问题可能导致数据段无法送达,并且数据往返时间不确定。
- 一收一发的方式性能较低,因此可以一次发送多条数据,这样就能大大的提高性能(将多个段的等待时间重叠在一起)。
-
窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,上图的窗口大小就是4000个字节(四个段)。
-
发送前四个段的时候,不需要等待任何ACK,直接发送。
-
收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据,依次类推。
-
操作系统内核为了维护这个滑动窗口,需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉。
-
窗口越大,则网络的吞吐率就越高。
-
情况一:数据包已经抵达, ACK被丢了。
这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认。 -
情况二:数据包就直接丢了。
- 当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK,就像是在提醒发送端 “我想要的是 1001” 一样;
- 如果发送端主机连续三次收到了同样一个 “1001” 这样的应答,就会将对应的数据 1001 - 2000 重新发送;
- 这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了 (因为2001 - 7000) 接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中。
这种机制被称为 “高速重发控制”(也叫 “快重传”)。
3.6 流量控制
接收端处理数据的速度是有限的,如果发送端发的太快导致接收端缓冲区溢出,这时发送端继续发送就会造成丢包继而引发丢包重传等一系列连锁反应。
流量控制:TCP支持根据接收端的处理能力,来决定发送端的发送速度。
- 接收端将自己可以接收的缓冲区大小放入TCP首部中的窗口大小字段,通过ACK端通知发送端;
- 窗口大小段越大,说明网络的吞吐量越高;
- 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
- 发送端接收到这个窗口大小之后,就会根据该窗口大小调整自己的发送速度;
- 如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
3.7 拥塞控制
网络通信需要占用资源吗?
- 网络通信肯定是要占用资源的。
在计算机网络中,宽带、每个路由器节点中的缓存和处理机等,都是网络资源。当在某个时间段中,某一个网络资源的需求量超过了这个资源所能提供的量,网络性能就会变差,这种情况就是拥塞。网络拥塞是由许许多多的因素引起的,比如当某个节点的缓存容量太小时、或者处理机处理的速率太慢等,如果只是简单的扩大缓存和提高处理及处理速率,虽然可以暂时的解决部分问题,但是整个网络生态的瓶颈却无法突破。只有整个网络所有的部分都平衡加强,问题才能解决。拥塞控制就是防止太多的数据进入到网络中,这样可以使网络中的路由器或者链路不会过载,首先要求当前的网络可以承受住现有的网络负荷,它是一个全局性的过程。(牛客网)
- 拥塞控制的算法有以下四种:
- 慢启动(slow-start):当客户端发送数据的时候,如果一次性把大量的数据字节发送到网络中,就有可能引起网络拥塞,因为并不清楚网络的负荷状态。所以较好的方法是先探测一下,由小到大逐渐增大发送窗口,也就是慢慢地增大窗口数值。通常刚开始发送报文段时先把拥塞窗口cwnd设置为一个最大报文段MSS的值,每收到一对新的报文段确认后,把拥塞窗口的数值再加一个MSS。
- 拥塞避免(congestion avoidance):让拥塞窗口cwnd缓缓地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍,让拥塞窗口按照线性规律慢慢增长,比慢开始算法的拥塞窗口增长速率慢很多。
- 快重传(fast retransmit):要求接收方每收到一个失序的报文段之后就立即发出重复确认而不是等待自己发送数据时捎带确认,为的就是让发送方能尽早地知道有报文段没有到达接收方。
- 快恢复(fast recovery):两个要点,一是当发送方连续收到三个重复确认时,就执行”乘法减小“算法,把慢开始门限ssthresh减半,这是为了预防网络发生拥塞。二是发送方认为网络很可能没有发生阻塞,因此不会执行慢开始算法,而是把cwnd(拥塞窗口)值设置成慢开始门限ssthresh减半之后的数值,然后执行拥塞避免算法,使拥塞窗口呈线性增长。
3.8 延迟应答和捎带应答
延迟应答
如果接收数据的主机立刻返回ACK应答,返回的窗口可能会比较小:
- 假设接收端缓存区为1M,一次收到了500K的数据;如果立刻应答,返回的窗口就是500K。
- 但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了。
- 在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来。
- 如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回窗口的大小就是1M。
窗口越大,网络吞吐量就越大,传输效率就越高,我们要尽可能的保证在网路不拥塞的情况下尽量提高传输效率,但也不是所有的包都可以延迟应答:
- 数量限制:每隔N个包裹就应答一次。
- 时间限制:超过最大延迟时间就应答一次。
捎带应答
在很多应用场景下,客户端服务器在应用层也是“一发一收”的,这意味着客户端给服务器说了 “How are you”,服务器也会给客户端回一个 “Fine, thank you”;那么这个时候ACK就可以搭顺风车,和服务器回应的 “Fine, thank you” 一起回给客户端。
3.8 粘包问题
TCP存在粘包问题,这个包指的是应用层的数据包。
在TCP的协议头中,没有如同UDP一样的报文长度字段,但是有一个序号字段。站在传输层的角度,TCP是一个一个报文传输过来的,按照序号排好放在缓冲区中;站在应用层的角度,看到就是一串连续的字节数据,那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。
- 如何避免粘包问题呢?
明确两个包之间的边界。
- 对于定长的包,保证每次都按固定大小读取即可;例如上面的Request结构,是固定大小的,那么就从缓冲区从头开始按sizeof(Request)依次读取即可;
- 对于变长的包,可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;
- 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔 符不和正文冲突即可)。
- 对于UDP协议来说,是否存在粘包问题呢?
- 对于UDP,如果还没有上层交付数据,UDP的报文长度仍然在. 同时,UDP是一个一个把数据交付给应用层,就有很明确的数据边界。
- 站在应用层的站在应用层的角度,使用UDP的时候,要么收到完整的UDP报文,要么不收,不会出现"半 个"的情况。
四、总结
4.1 TCP小结
TCP如何保证可靠性:
- 校验和
- 序列号(按序到达)
- 确认应答
- 超时重传
- 连接管理
- 流量控制
- 拥塞控制
TCP性能改善:
- 滑动窗口
- 快速重传
- 延迟应答
- 捎带应答
基于TCP的应用层协议:
- HTTP
- HTTPS
- SSH
- Telnet
- FTP
- SMTP
4.2 TCP和UDP对比
对比 | UDP | TCP |
---|---|---|
连接 | 无连接 | 面向连接 |
可靠性 | 不可靠 | 可靠 |
传输方式 | 面向数据报 | 面向字节流 |
报文首部 | 报文首部开销小,8字节 | 报文首部开销大,20字节 |
场景 | 一对一、多对多、一对多 | 一对一 |
传输控制 | 无 | 拥塞控制、流量控制等 |