网络协议--tcp协议(传输层协议)

tcp是面向连接的,可靠的,流式服务。

一.tcp面向连接--三次握手和四次挥手

1.tcp的三次握手

每进行一次握手就会发送一次tcp报文的头部。

2.tcp报文的首部格式

16位端口号(port number):告知主机该报文段是来自哪里(源端口)及发送给哪个上层协议或应用程序(目的端口)。进行tcp通信时,客户端往往是被分配系统自动选择的临时端口号。服务器使用知名服务端口号。所有知名服务使用的端口号都定义在/etc/services文件中。

32位序号(sequence number):一次tcp通信(从tcp连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。假设主机A和B进行tcp通信,A发送给B的第一个tcp报文段中,序号值被系统初始化位某个随机值ISN,某个tcp报文段传送的数据是字节流1025~2048,该报文段的序号值就是ISN+1025。从B到A的序号值也具有相同含义。

32位确认号(acknowledgement number):用作对另一方发送来的tcp报文段的响应。其值是收到的tcp报文段的序号值加一(seq+1)。

4位头部长度(header length):标识该tcp头部有多少个32bit字(4字节),4位最大能表示15,所以tcp头部长度最长60字节。

6位标志位:

URG:表示紧急指针(urgent pointer)是否有效。

ACK:表示确认好是否有效,携带ACK标志的tcp报文段位确认报文段。

PSH:提示接收端应用程序应该立即从tcp接收缓冲区中读走数据,为接受后续数据腾出空间。

RST:表示要求对方重新建立连接。称携带RST的tcp报文段为复位报文段。

SYN:表示请求建立一个连接。称携带SYN的tcp报文段为同步报文段。

FIN:通知对方本端要关闭连接了。称携带FIN的tcp报文段为结束报文段。

16位窗口大小(window size):是tcp流量控制的一个手段。窗口是指接受通告窗口(Recevier Window,RWND)。告诉对方本端的tcp接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。

16位校验和(tcp checksum):由发送端填充,接收端对tcp报文段执行CRC算法以检验tcp报文段在传输过程中是否损坏。这个校验不仅包括tcp头部,也包括数据部分,这是tcp可靠传输的一个重要保障。

16位紧急指针(urgent pointer):一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。这个字段是紧急指针相对于当前序号的偏移,不妨称之为紧

急偏移。tcp紧急指针是发送端向接收端发送紧急数据的方法。

3.tcpdump

使用tcpdump可以观察tcp头部信息和三次握手过程。

Flags后的方括号中代表tcp报文段的标志位的首字母,上图tcpdump输出Flags[S],表示该tcp报文段包含SYN标志。

seq是序号值,win是接收窗口大小。options是tcp选项,其具体内容列在方括号中。mss是发送端(客户端)通告的最大报文段长度。

4.四次挥手-断开连接(close()执行完后进行)

所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。挥手之前主动释放连接的客户端结束ESTABLISHED阶段。随后开始“四次挥手”:

a:首先客户端想要释放连接,向服务器端发送一段TCP报文,其中

- 标记位为FIN,表示“请求释放连接“;

- 序号为Seq=U;

- 随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。

b:服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:**

  - 标记位为ACK,表示“接收到客户端发送的释放连接的请求”;

  - 序号为Seq=V;

  - 确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值;

  - 随后服务器端开始准备释放服务器端到客户端方向上的连接。
    客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了

 c:服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:**
    (第二次挥手 服务器端回复 确认收到 客户端想要释放连接的请求 返回ACK,但是 服务端还有些数据的处理,所以不能马上断开连接,所以需要第三次握手 即服务端发送 FIN 释放连接的标志位)

    - 标记位为FIN,ACK,表示“已经准备好释放连接了”。注意:这里的ACK并不是确认收到服务器端报文的确认报文。
    - 序号为Seq=W;
    - 确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。
      随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。

 d:客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:**

    - 标记位为ACK,表示“接收到服务器准备好释放连接的信号”。

    - 序号为Seq=U+1;表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。

    - 确认号为Ack=W+1;表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。随后客户端开始在TIME-WAIT阶段等待2MSL。
      服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。
      客户端等待完2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”。

      后“两次挥手”既让客户端知道了服务器端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了,由此完成“四次挥手”。

5.tcp状态转移图

主动关闭TIME_WAIT状态大约持续两分钟  ,

TIME_WAIT状态存在的意义:
1.可靠的终止tcp的连接(主动关闭的一端完成四次挥手到FIN_WAIT_2状态时,收到对方发送的FIN,发给对方ACK,若ACK在发送过程中丢失,对方没有收到ACK会认为自己发的FIN丢失,会重新发送FIN,此时主动断开方收到FIN时,会再次发送ACK,对方收到后消失。

2.保证让迟来的 TCP 报文段有足够的时间被识别并丢弃。(确保新进程启动后不会收到发给老进程的数据)

当一端服务器端一端客户端完成三次握手后,断开网线,服务器ser结束,重启服务器后再连接网线,客户端处于已完成三次握手状态,服务器端处于listen()状态。

二.tcp的可靠性

TCP保证可靠性一般有以下几种方法:

1.检验和:在数据传输过程中,把传输的数据当作一个16位整数。把所有的数据加起来,最前面的进位补到最后一位,然后取反得到校验和。发送方和接收方验证校验和是否相同。不相同则数据传输有误,相同也可能有问题。
2.确认应答:ACK和序列号(一应一答)机制保证数据的完整性(三次握手与四次挥手过程中通过比对Seq和ACK来实现)
3.超时重传:发送数据包在一定的时间周期内没有收到相应的ACK,等待一定的时间,超时之后就认为这个数据包丢失,就会重新发送(也就是发送数据后,长时间没收到回应,会把数据再发一次。)
4.连接管理:三次握手,四次挥手
5.最大消息长度:理想的情况下是该长度的数据刚好不被网络层分块。
6.滑动窗口拥塞控制:控制传输上流量(发送数据时开始是慢启动,先发送一点点数据去探测网络拥塞不拥塞,如果不拥塞了,则大量的发送数据。如果突然拥塞了,则又很慢的发送数据。这样是为了尽可能快的发送数据,避免网络拥塞造成一系列问题)

7.流量控制:TCP利用滑动窗口实现流量控制,流量控制是为了控制发送方的发送速率,保证接收方来的及时接收。

三.tcp流式服务

TCP 协议会将数据切割为一个个片段,然后丢给网络层,接着打包成一个个数据包进行传输**。流数据变成了一个个片段数据,这会无法保证数据到达的次序。因为 IP 协议在传输过程中,不会按顺序进行发送和接受数据包。针对这问题,TCP 协议为了确保数据到达的顺序与文本流顺序相同。TCP 协议将每个 TCP 片段中分为头部(header)和数据(payload)两部分。每个头部中带有一个序号。这相当于给每个片段增加一个序号标记,方便后续排序。

1.tcp粘包

(指多次send的数据被recv一次性收到)

指发送方发送的若干包数据到达接收方时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能来自接收方。

 2.tcp产生粘包的原因:

(1)发送方原因:tcp默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:

1.只有上一个分组得到确认,才会发送下一个分组

2.收集多个小分组,在一个确认到来时一起发送

(2)接收方原因:tcp接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理,实际上,tcp将接收到的数据包**保存在接收缓存**里,然后应用程序主动从缓存读取收到的分组。如果tcp接受数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就可能读取到多个首尾相接粘到一起的包。

3.如何解决?

(1)发送方

对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。

(2)接收方

接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。

(3)应用层

应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。

解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值