【TCP/IP模型之传输层】详解TCP三次握手四次挥手过程、TCP的可靠性传输以及粘包问题

本文深入解析TCP/IP模型中的传输层,详细阐述TCP三次握手与四次挥手过程,探讨TCP的可靠性传输机制,包括确认应答、超时重传、连接管理和粘包问题。同时对比UDP协议的无连接、不可靠和面向数据报特性,以及TCP与UDP的适用场景和优缺点。
摘要由CSDN通过智能技术生成

认识端口号

端口号是由操作系统动态分配的。用于TCP/IP协议,在标识通信起到一定的作用。

常见的端口号

ssh服务器:22
ftp服务器:21
telnet服务器:23
http服务器:80(但是也不是绝对的,这只是一个习惯)
https服务器:443
一个进程可以绑定多个端口号,但是一个端口号只能被一个进程绑定(特殊情况fork创建的子进程和父进程可以绑定同一端口号,这是由于fork的同时会拷贝文件描述符(socket)).

UDP协议

UDP协议段格式

这里写图片描述

UDP的特点

理解UDP的传输就理解成寄信,所以UDP具有以下特点:

  • 无连接:只需要知道对端的端口号就可以进行传输。
  • 不可靠:这个是相对于TCP协议来说的,没有确认应答机制和重传机制。
  • 面向数据报:不能灵活的控制读写数据的次数和数量 ,应用层交给UDP多长的报文,都会无条件原样发送

如何理解面向数据报和面向字节流

相信学习了TCP协议和UDP协议,我们都知道这两个协议之间有一个不同点,那就是TCP协议面向字节流,但是UDP协议面向数据报,那么面向数据报和面向字节流到底应作何理解呢?

面向字节流(TCP)

理解面向字节流你就想象一个水池,不管这一次往里面注入水的过程分几次,但是取水的时候根据容器不同,所以取水的操作次数肯定和注入水的次数不同,这两者是没有关联的。
我们将接收缓存想象成水池,注水理解成发送数据,取水理解成 读取数据,在TCP连接的一端发送数据,调用一次write,写入100个字节,对端可以分十次一次10个字节读出来,也可以分两次一次读50个字节,这就体现了读数据的灵活,另一方面,发送数据也可以分十次发送,然后对端也可以有选择的十次一次读10字节,也可以一次全部读完,这体现了写数据的灵活。

面向数据报(UDP)

UDP基于报文,所以发送数据和接收数据都是以报文(UDP协议首部16位UDP长度,所以报文长度为64K)为单位的,发送调用几次sendto接收就会对应调用几次recvfrom,接收的时候每次最多接收一个报文(避免假如两个主机都发了一个报文,如果读取超过一个报文那么就会使两个主机的报文有些交叉在一起,那么接收的结果就是无意义的),而且报文是不可以合并的,那么假如报文比缓冲区的长度要长,缓冲区满了,就会有一部分被丢弃(指定MSG_PEEK)。所以假如数据超过了64K,那就要我们手动分包,分多次发送,然后再手动拼装。

TCP协议

TCP协议段格式

这里写图片描述

理解TCP的可靠性传输

确认应答机制

TCP在数据传输时都有对应的编号,叫做序列号,当接收到发送者的数据是会确认应答,告诉发送者你发送的数据我收到了,下一个应该从哪里开始。
这里写图片描述

超时重传机制

主机A发送给主机B的数据可能因为网络拥塞的原因没有到达主机B,此时如果在一定时间内主机A没有受到主机B的确认应答,那么就会重发数据。但是假如数据后面又到了,那主机B就会有很多重复的数据,不过因为有序列号,主机B可以自己去重。

连接管理:TCP三次握手四次挥手过程

图解示意图:

这里写图片描述
分析状态:

详解三次握手

这里写图片描述
第一次握手:客户端发送一个SYN(SYN置为1)标志,指明客户端打算连接的服务器的端口,以及初始序号X(seq=x),保存在包头的序列号里。此时客户端进入SYN_SENT状态,等待服务器确认。
第二次握手:服务器收到请求连接的包,再发送确认包ACK应答同时将确认序号设置成初始序号加1,即ack=x+1。同时进入SYN_RCVD状态。
第三次握手:客户端收到SYN+ACK,再次发送确ACK(SYN=0,ACK=1),并将服务器发过来的序号再加1,放在确认字段中发给服务器。此时双方进入ESTABLISHED状态。

详解四次挥手

这里写图片描述
第一次挥手:客户端主动关闭文件描述符socket,给服务器发送一个FIN报文段,此时进入FIN_WAIT_1状态。
第二次挥手:服务器接收到FIN,发回一个ACK给客户端,此时服务器进入CLOSE_WAIT状态,清理数据,同时客户端进入FIN_WAIT_2状态。
第三次挥手:数据清理完,服务器发给客户端一个FIN报文段,表示准备好了断开连接,也关闭文件描述符,进入LAST_ACK状态。
第四次挥手:客户端本就处于准备断开连接的状态,同时服务器也准备好了,所以就给服务器发送一个ACK报文段,客户端进入TIME_WAIT状态,在等待2MSL后才进入CLOSED状态,服务器直接进入CLOSED状态。

三次握手四次挥手相关问题理解

1、为什么是不能是2次握手?

由于在建立连接的时候不仅要客户端和服务器双方都做好收发数据的相关准备,其中最重要的是序列号的协商,如果按照两次握手,客户端给服务器发送一个SYN,服务器收到这个报文后再发给客户端一个ACK,这时服务器就认为建立好连接了,就可以发送数据了,但是,很明显假如服务器的应答分组在传输过程中丢掉了,那么客户端就不知道服务器是否准备好,也不知道服务器的序列号是什么,客户端就会认为连接没有建立成功,此时服务器发送数据客户端都会忽略,但是服务器等待客户端的确认应答,这注定是等不到的,然后就会重传,所以服务器就会死锁。

2、为什么是建立连接是三次握手关闭连接是四次挥手??

首先三次握手服务器端在LISTEN状态下收到客户端发来SYN报文连接请求,会给客户端发送ACK+SYN放在一个报文中来发送,客户端再发送一个ACK连接就建立好了,所以就只需要三次握手就可以了,但是在断开连接的时候当收到对方的断开连接请求FIN时,表示对方已经没有数据要发送了,但是你并没有将数据都发送完,所以肯定不会立马关闭socket,会先发一个ACK应答报文,表示你收到了他的请求,此时你会对数据进行处理,处理完成后就再发一个FIN,表示你已经准备好要断开连接了,对方再发一个ACK,两者就彻底断开连接。此处的FIN和ACK是没有办法合在一步的。

3、理解TIME_WAIT状态

主动关闭连接的一方就会进入TIME_WAIT状态。
当一端处于TIME_WAIT 状态时,连接已经是半断开了,但是没有完全断开,对于服务器而言,如果服务器突然连接掉了,他是不可能在2MSL的时间内重新启动,bind总是会失败的。如果想要连接那就设置socket的SO_REUSEADDR选项(重用一个地址)。

intopt=1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

4、四次挥手主动断开连接的一方等待2MSL的意义《TCP/IP详解》??

首先是为了保证A(主动断开连接的一方)发送给B的最后一个ACK报文能够到达B,ACK一旦丢失,处于LAST_ACK状态的B就收不到自己发送出去的FIN的应答,那就会重传ACK、FIN(这就需要2MSL的时间),而这个2MSL的时间段是一定能够等到B重传的FIN和ACK,然后A就能进行确认然后断开连接(相当于多了一次保障);其次是为了防止已失效的请求报文段出现在这里,A发送完ACK在经过2MSL。就可以使所有这一次连接产生的报文全部清除(报文可能会被混淆,其他时候的连接可能被当作本次的连接)。

5、三次握手过程中发送方再次发送ACK的必要性?

是为了防止已失效的连接请求报文段有传送到了B端,那么可能会误导B端,产生错误。这种情况就是A端发送的第一个请求在网络中滞留直到快释放才到达,那么B就会认为是A的又一次请求,就会同意建立连接,所以说如果不是三次握手,那么只要B发出确认连接就已经建立完成,可是第一个请求不到就要一直等待会浪费很多时间。

流量控制

接收端接收数据的速度是一定的,如果不停的发导致缓冲区满了的话,那么就会发生丢包,再有就是丢包重传一系列反应,所以要根据接收端的接收速度来发送数据,来保证数据的完整性。

  • 接收端将自己可以接收的缓冲区大小放进TCP首部,然后通过ACK告诉发送端。
  • 假如接收端发现自己的缓冲区快满了,就会将窗口大小设置成更小的值通知发送端
  • 发送端在知道了这个值之后就会减缓发送的速度
  • 如果缓冲区满了,就会将窗口置成0,发送端就无法发送数据了,但是仍旧要定期将窗口大小发送给发送端,一旦不是0就又可以发送数据了。

拥塞控制

由于有的时候网络状态很堵,但是这样的情况下贸然发送大量数据会有很严重的后果,所以拥塞控制机制就引入了慢开始,先发送少量数据探探路,如果不堵得话,慢慢加大数据(指数增加),当拥塞窗口达到阈值就开始线性增长,达到拥塞窗口的最大值就要再回到0重新慢开始。
示意图:

窗口越大,吞吐量越大,性能越高

滑动窗口

像有了确认应答机制,可以保证发送的数据都收到了,即便没有收到也会有超时重传,但是如果每发一个数据就应答一次,显然这样效率是非常低的,滑动窗口的出现就是为了提高效率,主要原理就是,发送端可以连续发送若干条数据,不需要对方的确认应答(这一段就称为滑动窗口),收到一个应答窗口就会向后移动,然后继续发送数据。这样就能保证窗口的吞吐量(吞吐量越大效率越高)
这里写图片描述
此时如果丢包比如说2001~3000的包被丢掉了,应答的时候自然就会少了这一部分数据的应答,这样也可以确定丢包了,另外一种情况,2001~3000丢包,后面3001~4000和4001~5000甚至后面的5001~6000应答报文中都会出现下一个应该是2001,连续几次就会重新发送2001~3000的数据.。但是不同的是再次返回的ACK就不是3001,而应该是原本应走到的5001~6000的应答“下一个应该是6001”。

延迟应答

因为加入已接收到数据就应答那么窗口就会很小,牢记:窗口越大,吞吐量越高,传输速率越快。

捎带应答

有的时候客户机发一个“你好吗?”,然后对端发一个“我很好”,这样就实现了ACK和响应一起发给客户机了。

粘包问题

什么是粘包问题?

一方面传输层发送的是一个个报文(带有TCP头部),但是到了应用层就只能看得到连续的字节数据,所以应用程序就不知道哪一部分的数据是一个整体,所以有的时候一个数据和另一个数据会粘带在一起,有的时候读不完,造成有的数据缺失这就是粘包问题。
但是UDP就不会因为UDP在发送数据和接收数据的时候都是一次send对应一次recv所以要么会丢失,要么就接收到了,不会出现粘连。

怎么解决粘包问题

核心:明确数据的边界
1、具体制定一个完整的数据有多大,按照指定的这个大小读取。
2、在包和包之间使用明确的分隔符。

TCP异常情况

进程终止:

进程终止:文件描述符就在进程的PCB里面保存着,所以终止了进程,也就相当于关闭了连接
机器重启:(和进程终止情况相同)
机器掉电/网线断开:此时另一方没有感知到对端掉电,仍会尝试发送消息,但是此时就会发现连接已经不在了。不过就算不去发消息也可以知道对端是否还在,就是TCP内部有一个保活定时器,会定期地询问对方还在不在,如果对方不在,就把连接释放。

TCP和UDP总结

1、TCP传输更可靠:有序号的传输;确认应答机制;连接管理(三次握手四次挥手);超时重传;流量窗口(避免发送端太快,接收端接收不急就会丢包);拥塞控制(慢开始)

2、有连接:连接管理

3、面向字节流:读写灵活

但是UDP也不是就不好,UDP应用于高速传输和实时性要求较高的传输,而且UDP可以用于广播。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值