当前位置: 代码网 > 服务器>服务器>Linux > Linux网络--传输层--TCP协议基础详解

Linux网络--传输层--TCP协议基础详解

2025年05月26日 Linux 我要评论
一、tcp协议格式tcp(传输控制协议)报文结构是网络通信中重要的基础概念,用于实现可靠的数据传输源端口与目的端口作用:标识通信的两端进程(范围:0~65535)示例:http默认使用80端口,htt

一、tcp协议格式

tcp(传输控制协议)报文结构是网络通信中重要的基础概念,用于实现可靠的数据传输

源端口与目的端口

  • 作用:标识通信的两端进程(范围:0~65535)
  • 示例:http默认使用80端口,https使用443端口

序号

  • 作用:标记本报文段中数据的第一个字节在整个数据流中的位置,用于保证数据有序传输
  • 特点:syn标志位为1时,序号为初始序号(isn),后续序号递增

确认序号

  • 作用:期望收到的下一个字节的序号,表示已成功接收该序号之前的数据
  • 规则:确认号 = 已接收数据的最后一个字节序号 + 1

首部长度

  • 作用:指示tcp头部的长度(以4字节为单位),最大值为60字节(默认20字节)
  • 原因:由于选项字段的存在,头部长度可能变化

标志位

用来区分tcp报文的类型

  • urg:紧急指针有效,通知接收方优先处理紧急数据
  • ack:确认号是否有效
  • psh:通知接收方立即将数据提交给上层应用,即从tcp缓冲区读走
  • rst:重置连接,用于异常中断
  • syn:同步序号,用于请求建立连接
  • fin:终止连接,用于断开连接

窗口大小

  • 作用:告知发送方当前接收方的可用缓冲区大小,用于流量控制
  • 单位:字节数,范围0~65535(通过窗口扩大因子可扩展)

校验和

  • 作用:验证tcp报文段(包括头部和数据)在传输过程中是否损坏
  • 计算范围:tcp头部、数据部分,以及伪首部(包含ip地址和协议号)

紧急指针

  • 作用:当urg标志位为1时,若当前段起始序列号为seq,紧急指针为ptr,则紧急数据的范围就是seqseq + ptr - 1
  • 注意:紧急数据会被识别并提前处理,但紧急数据是tcp中的一种特殊机制,实际中较少使用

选项与填充

常见选项

  • 最大段长度:协商每次传输的最大数据量
  • 时间戳选项:用于计算往返时间和防止序号回绕
  • 填充:确保头部长度为4字节的整数倍

数据部分

  • 内容:封装上层协议(如http、ftp)的数据
  • 注意:tcp头部不含长度字段,数据长度通过ip头部的总长度减去ip头部长度和tcp头部长度计算得出

tcp与udp的对比

特性tcpudp
连接性面向连接(需三次握手)无连接(直接发送)
可靠性可靠(重传、校验)不可靠(尽力而为)
首部开销20~60字节(含选项)8字节
适用场景文件传输、http等视频流、dns查询等

通过以上结构,tcp能够实现可靠、有序、流量可控的数据传输,是互联网核心协议之一

二、tcp协议机制

tcp拥有发送缓冲区和接收缓冲区两个缓冲区,发送信息的流程是:

  • 写入缓冲区:应用程序需要发送信息时,将信息写入用户缓冲区
  • 写入内核:调用wirte函数,将信息从用户缓冲区复制到发送缓冲区
  • 发送数据:通过网卡和内核tcp模块处理将数据存入另一用户的接受缓冲区
  • 写入用户区:调用read函数,将信息从接收缓冲区拷贝到用户缓冲区中
  • 应用程序获取数据:应用程序从用户缓冲区读取数据

这里发送和接收的数据就是上面我们提到的协议格式下的报文

三、确认应答机制

tcp确认应答机制是确保数据可靠传输的核心机制之一,也是区别于udp的核心特点之一,在保证可靠性的同时,尽可能优化传输效率

基本概念

  • 作用:接收方通过发送确认消息,告知发送方数据已成功接收,避免数据丢失
  • 可靠性保证:发送方在超时未收到确认消息时,会重传数据,叫做超时重传

工作流程

序号

  • 每个tcp报文段都会携带一个序号,标识该段数据在数据流中的位置

确认号

  • 接收方通过确认消息返回确认号,表示下一个期望接收的数据序号
  • 规则:确认号 = 已成功接收的最后一个字节序号 + 1
    • 示例:若接收方成功接收序号1000~1999的数据段,确认号为2000,表示期望接收后续数据

确认应答机制

  • 单次确认:发送方发送数据后,等待接收方的确认消息
  • 批量确认:滑动窗口技术允许发送方连续发送多个数据段,接收方只需确认最后一个连续收到的序号,也叫累积确认

确认类型

累积确认

  • 特点:接收方仅确认最后一个连续收到的数据段,忽略中间丢失的段
  • 优点:实现简单,减少确认消息数量
  • 缺点:若中间某个段丢失,发送方需重传后续所有段,这也叫做线头阻塞

选择性确认

  • 机制:接收方通过选择性确认选项告知发送方哪些段已接收,哪些段丢失
  • 优点:发送方仅重传丢失的段,避免冗余重传
  • 适用场景:高带宽延迟网络,如卫星链路

优化策略

延迟确认

  • 机制:接收方延迟发送确认消息(通常最多200ms),合并多个确认以减少网络流量
  • 适用场景:批量数据传输,如文件下载

确认应答压缩

  • 机制:在高速网络中,减少冗余确认消息的发送频率

示例说明

  • 发送方发送数据段:序号1000(1000字节) → 序号2000(1000字节) → 序号3000(1000字节),接收方收到序号1000和3000的段:
  • 发送确认应答 2000(累积确认,仅确认连续段),那序号2000和序号3000的数据段都会重传
  • 若支持选择性确认,额外告知序号3000已接收,发送方根据确认应答和选择性确认,仅重传序号2000的段

这个确认应答呢我有一个小技巧来记忆,发送方发送数据段之后,比如说发送了序号1000,它代表着1000~1999,那我下一个是不是就要要2000了,那么我们确认应答发送的就是2000

四、捎带应答

我们将捎带应答这个解释过程简化为两张图,黑色斜线表示通信双方,正常情况下如下图所示,左边给右边发送一个报文,右边要给左边一个应答,表示已经收到数据,当然这里的应答也是严格按照tcp报文结构来的,发送的也是一个完整的tcp报文(至少有报头),之后右边再给左边发送报文,左边再给右边发送一个应答

但是这样的效率会很低,在正常情况下,双方不会这样进行通信,而是将应答和要发送的tcp数据整合成一条报文,此时发送的这条报文既是应答又是数据,减少开支

五、三次握手和四次挥手

1、应用层行为

这边我们举一个客户端和服务端的例子

三次握手

  • 服务端应用层行为(服务器初始化):服务端是要先开启的,应用层通过调用socket分配一个文件描述符,然后调用bind函数将这个文件描述符与服务器地址端口绑定,然后调用listen函数进入监听状态,然后调用accept函数阻塞等待客户端的连接,此时服务端开启完毕
  • 客户端应用层行为(建立连接):客户端后开启,应用层通过调用socket分配一个文件描述符,然后调用connect函数向服务器发起将文件描述符与服务器地址端口连接请求,connect函数会发出syn段并阻塞等待服务器应答(第一次握手)
  • 服务器收到客户端syn,会应答一个syn-ack段表示同意建立连接(第二次握手)
  • 客户端收到syn-ack后会从connect函数返回,同时应答一个ack段(第三次握手)

数据传输

  • 建立连接后,tcp协议会提供全双工的通信服务,即同一条连接同一时刻,通信双方可以同时写同时读
  • 服务器从accept函数返回后立刻调用read函数,读socket就和读管道一样,没有数据就阻塞等待
  • 这时客户端调用write发送请求给服务器,服务器收到后从read返回,对客户端的请求进行处理,在此期间客户端调用read函数阻塞等待服务器的应答
  • 服务器调用write函数将处理结果发回客户端,再次调用read函数阻塞等待下一条请求
  • 客户端收到后从read函数返回,发送下一条请求
  • 以①~⑤循环

四次挥手

  • 客户端调用close关闭连接,此时客户端会向服务器发送fin段(第一次挥手)
  • 服务器收到fin后,回应一个ack,同时read返回0(第二次挥手)
  • read返回之后,服务器就知道客户端关闭了连接,也调用close关闭连接,这个时候服务器会向客户端发送一个fin(第三次挥手)
  • 客户端收到fin,返回一个ack给服务器(第四次挥手)

2、三次握手—建立连接

三次握手的机制就是建立在捎带应答上的,捎带应答不仅是通信时的一种策略,并且是建立连接时的策略

三次握手也可以是四次握手,理由和上面一样,这里的第二次握手本来也是两条消息合并发送而已

  • 对于客户端来说,当我们将ack发出了,我们就认为连接已经建立成功了,此时客户端的状态就是上上图的established,建立描述该连接的客户端属性结构体就被建立了,我们tcp协议对于连接的管理当然也是先描述后组织的,此时客户端连接的属性结构体就通过指针被队列组织管理了
  • 对于服务器来说,在开启监听状态listen后,收到建立连接报文syn,会对客户端进行确认并请求建立连接ack+syn,然后在收到客户端确认报文ack之后建立描述该连接的服务器属性结构体,然后这个结构体也会被管理起来

3、四次挥手—断开连接

  • 对于客户端来说,当没有数据要读取或发送的时候,发送结束报文fin,进入等待状态1,fin_wait1,然后一直等待,在接收到服务器的应答ack后进入等待状态2,fin_wait2,然后一直等待,在收到服务器fin报文时,发送应答ack并转为time_wait状态,等待一个2msl(报文最大生存时间)的时间,然后进入closed状态
  • 对于服务器来说,在接收到客户端发来的结束报文fin之后,如果自己也没有啥要发给客户端的,那么发送应答ack并转为等待状态close_wait,处理之前的数据,处理完后向客户端发送结束报文fin,并转为最终回应状态last_ack,在接收到客户端的ack的报文后,关闭连接

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com