网络编程杂谈之TCP协议

TCP协议属于网络分层中的传输层,传输层作用的就是建立端口与端口的通信,而其下一层网络层的主要作用是建立”主机到主机”的通信,所以在我们日常进行网络编程时只要确定主机和端口,就能实现程序之间的数据交流,在Unix系统中就把主机+端口,叫做”套接字”(socket),所以一般网络编程都是基于对于socket的操作来做的。

TCP协议其实是一个非常复杂的协议,做过网络编程开发的都听过一句话”TCP本身是一种可靠的协议”,但正是为了保证可靠性,TCP 内部使用了如各种重传与控制算法,所以 TCP 是一个内部原理复杂,但是使用起来比较简单的协议。

下面我们对TCP协议进行一个基本的介绍,本文只是站在应用的角度上阐述,相比与真正的深入还是比较浅显的。

一、TCP协议格式

首先主要看下TCP协议的头格式

网络编程杂谈之TCP协议

其中各字段的意义如下:

1、TCP源端口(Source Port):16位的源端口其中包含发送方应用程序对应的端口。源端口和源IP地址标示报文发送端的地址。

2、TCP目的端口(Destination port):16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。

3、包序号(Sequence Number):32位的SN序列号标识了TCP报文中第一个byte在对应方向的传输中对应的字节序号,用来记录网络包顺序,解决传输中的乱序、重复问题,比如发送端发送的一个TCP包净荷(不包含TCP头)为10byte,SN为5,则发送端接着发送的下一个数据包的时候,SN应该设置为5+10=15。通过序列号,TCP接收端可以识别出重复接收到的TCP包,从而丢弃重复包,同时对于乱序数据包也可以依靠系列号进行重排序,进而对高层提供有序的数据流。另外如果接收的包中包含SYN或FIN标志位,逻辑上也占用1个byte,应答号需加1。

4、确认号(Acknowledgement Number):32位的ACK标识了报文发送端期望接收的字节序列,如果设置了ACK控制位,这个值表示一个准备接收的包的序列码,注意是准备接收的包,比如当前接收端接收到一个净荷为10byte的数据包,SN为5,则会回复一个确认收到的数据包,如果这个数据包之前的数据也都已经收到了,这个数据包中的ACK Number则设置为10+5=15,表示之前的数据都已经收到了,准备接受SN=15的数据包。

5、窗口(Advertised-Window):著名的滑动窗口(Sliding Window),用于TCP的流量控制。

6、状态位(TCP-FLAG):包的类型,用于操作TCP的状态机,其8位状态分别表示如下含义

  • CWR(Congestion Window Reduce) 0x80:拥塞窗口减少标志set by sender,用来表明它接收到了设置ECE标志的TCP包。并且sender 在收到消息之后已经通过降低发送窗口的大小来降低发送速率。
  • ECE(ECN Echo) 0x40:ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的。在数据传输过程中也用来表明接收到的TCP包的IP头部的ECN被设置为11。
  • URG(Urgent) 0x20:该标志位表示紧急(The urgent pointer) 标志有效,设置为1时,首部中的紧急指针有效;为0时,紧急指针没有意义。紧急数据不进入接收缓冲区直接交给上层进程处理;
  • ACK 0x10:取值1代表Acknowledgment Number字段有效,这是一个确认的TCP包,取值0则不是确认包。后续文章介绍中当ACK标志位有效的时候我们称呼这个包为ACK包,使用大写的ACK称呼。
  • PSH(Push) 0x08:该标志置位时,一般是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的连接时,该标志总是置位的。如果PSH=1的话,就不用等到整个缓存都填满,直接把缓存区中的所有数据进行交付。
  • RST(Reset) 0x04:用于reset相应的TCP连接。通常在发生异常或者错误的时候会触发复位TCP连接。
  • SYN 0x02:同步序列编号(Synchronize Sequence Numbers)有效。该标志仅在三次握手建立TCP连接时有效。
  • FIN(Finish) 0x01:No more data from sender。当FIN标志有效的时候我们称呼这个包为FIN包。

7、校验位(Checksum):16位TCP头。发送端基于数据内容计算一个数值,接收端要与发送端数值结果完全一样,才能证明数据的有效性。接收端checksum校验失败的时候会直接丢掉这个数据包。CheckSum是根据伪头+TCP头+TCP数据三部分进行计算的。

8、紧急指针(Urgent Pointer):16位,指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。

9、选项(Option):长度不定,但长度必须以是32bits的整数倍。常见的选项包括MSS、SACK、Timestamp等等。

二、TCP状态机

关于TCP的状态机理解我们从几张经典的示意图开始

TCP状态转换图

网络编程杂谈之TCP协议

TCP三次握手、四次挥手时序图

网络编程杂谈之TCP协议

基于TCP的网络编程中链接的建立断开、数据发送都是依赖TCP状态转换实现的,例如所谓的建立链接并不是真正的链接,而是一种状态的维持,表面上的链接其实是通讯双方共同维护了一个”链接状态”,而建立链接–数据传输–断开链接的TCP通信过程,也是这些状态转换的过程,这其中状态的转换一部分是收到或发送的某个控制位字段的变化而引起的,如SYN、FIN、ACK等,还有一些是由于应用程序的动作或计时器超时引发的。

了解了以上的内容,下面我们就结合实际报文数据,对TCP链接三次握手,数据传输,断开四次挥手,进行一个简单的跟踪验证;

三、TCP通讯

1、三次握手

建立链接的三次握手的作用主要是初始化Sequence Number 的初始值,同时把这个值通过Synchronize Sequence Numbers(SYN包)告知对端。

通过Wireshark可以捕获到三次握手的报文

网络编程杂谈之TCP协议

握手流程:

  • 1、client首先初始化该值,发送一个SYN包给server端,告诉server端一个初始化的SN值
  • 2、server收到client发送的数据,回复一包数据,包括ACK确认与SYN, 既要告诉client端收到了数据,同时告知对方SYN值;
  • 3、client回复ACK确认包,告知server端收到了数据;

2、数据传输

通过Wireshark,我们可以看下TCP传输中一包数据的组成,对照前面的协议组成,可以看到这里我们发送的是0x11,0x11两个字节的数据

网络编程杂谈之TCP协议

可以看到接收一段回复的确认包里ACK从1变成了3,为保证数据的顺序性与可靠性,TCP是有一整套的机制来控制的,如大家熟悉的滑动窗口、超时重传等;

网络编程杂谈之TCP协议

这里有一个需要注意的细节,这里ACK确认号的真实值其实是从0xffeb49ed 变为 0xffed49ef的,这是由于当某个主机开启一个TCP会话时,他的初始序列号与确认号是随机的,可能是0和4,294,967,295之间的任意值,在Wireshark里显示的都是相对序列号/确认号,而不是实际序列号/确认号,相对序列号/确认号是和TCP会话的初始序列号相关联的。这里Wireshark为方便大家跟踪查看显示的是相对值,因为比起真实序列号/确认号,跟踪更小的相对序列号/确认号会相对容易一些。

3、四次挥手

断开链接的四次挥手的作用主要是回收资源,停止数据传输。由于TCP是全双工的,需要client与server两端分别断开各自的通向对方的通道。

通过Wireshark可以捕获到四次挥手的报文

网络编程杂谈之TCP协议

挥手流程:

  • 1、client端发送一个FIN包告诉server服务端已经没有数据要传输了,准备断开链接;
  • 2、server端回复一个ACK确认包,也就是告诉cient端,好,我知道你要断开了;
  • 3、server端这时要看自己还有没有数据要发送给client,如果没有了,也要发送一个FIN包告诉client端,我也没有数据要传输了,准备断开链接;
  • 4、client端回复一个ACK确认包,告诉server端,好的,我知道你要断开了;

四次挥手的流程中,sever端在接收到client端的断开要求后,ACK确认包与FIN包是否可以合并为一个包来发送,也就是四次挥手是否可能变成三次挥手,答案是可能的,但由于TCP是全双工的,server端与client端数据传输的终止在时序上是独立且可能相隔较长时间,那么一般情况下一个完整的断开链接操作都是需要四次挥手来完成的。

到这里针对TCP协议,以及链接->传输->断开链接流程的基本介绍与说明就结束了,后续针对网络编程这一块我会接着写几篇文章,一是对自己工作中涉及到一些网络编程的内容进行梳理与总结,另一方面希望能从下至上的加强自己对网络编程这块认知的深度,也希望对大家能有所帮助,其中如有不足与不正确的地方还望指出与海涵。

关注微信公众号,查看更多技术文章。

网络编程杂谈之TCP协议

转载说明:未经授权不得转载,授权后务必注明来源(注明:来源于公众号:架构空间, 作者:大凡)

Original: https://www.cnblogs.com/dafanjoy/p/12831106.html
Author: DaFanJoy
Title: 网络编程杂谈之TCP协议

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/593445/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • linux基本命令

    cd 切换文件夹 cd /home 绝对路径 以包目录开头 cd admin 相对路径 不以包目录开头 cd .. 返回上级目录 cd ~ 到自己的家目录 /home/admin …

    Java 2023年6月16日
    077
  • Ingress Nginx v0.30 Hostnetwork高性能模式安装

    Ingress Nginx v0.30 Hostnetwork模式安装 `apiVersion: v1kind: Namespacemetadata: name: ingress-…

    Java 2023年5月30日
    0100
  • 今天发布的一个程序一直提示Microsoft.mshtml的强名称验证失败

    软件发布后,在客户的电脑上一再提示缺失该文件或强名称验证失败, 本机的Microsoft.mshtml就两个文件, 拷到客户的机子上,均出同样提示。 后在网络上找个这个dll,该版…

    Java 2023年6月14日
    0106
  • 别被带节奏

    很多人说”好佩服某某某,他总能问出精彩的问题”,其实原因很简单,你跟着讲师节奏做无用功时,他在思考。 今天老婆跟我讲了一件事。她约了几个宝妈,带小孩去游乐场…

    Java 2023年6月16日
    078
  • Java 发布 Jar 到 maven中央仓库

    Java 发布 Jar 到 maven中央仓库 1、简介 Maven中央仓库并不支持直接发布jar包。我们需要将jar包发布到一些指定的第三方Maven仓库,然后该仓库再将jar包…

    Java 2023年5月29日
    092
  • Android studio打开项目一直卡住

    修改/gradle/wrapper/gradle-wrapper.properties文件中的最后一行distributionUrl=;(可找一个可用项目的复制过来) Origin…

    Java 2023年6月9日
    057
  • 企业级微服务API网关Fizz-服务编排内置函数

    概述 在前面的教程里已经介绍过服务编排的功能,服务编排主要是基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。在进行入参或结果处理时,常要进行数据转换或计算。此时可用常…

    Java 2023年6月9日
    080
  • Java-Mybatis动态SQL整理

    SQL映射文件的几个顶级元素: cache – 该命名空间的缓存配置 cache-ref – 引用其他命名空间的缓存配置 resultMap –…

    Java 2023年6月8日
    079
  • 基于注解的自动配置

    显式配置并不怎么方便。我们必须备好配置文件,把Bean的创建信息一个不差地填写进去之后交给Spring容器,Spring容器才能进行Bean的创建。若是需要创建的Bean不多,只有…

    Java 2023年6月5日
    079
  • lambda表达式常用01

    1、 优化线程代码 以前我们使用线程可能是这么使用的: 使用lambda: 再次进行优化写法: 2.Arrays.sort 排序优化 在代码中,我们会使用Arrays.sort对数…

    Java 2023年6月9日
    077
  • 根据ip查询 地址信息

    这次调用了jsoup.jar包,使用它获取网上的资源获取网址https://ip138.com/的数据进行返回数据 import org.jsoup.Jsoup; import j…

    Java 2023年6月7日
    088
  • Springboot2.0WebFlux 开发

    简单了解下其用法。 1. JDK9的Reactive Stream 用法 响应式流,和发布订阅者模式一样,只不过订阅者可以自己控制生产者发送数据的速度。 1. 背压 背压是一种常用…

    Java 2023年5月30日
    086
  • 回溯法:数组总和III

    题目 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:只使用数字1到9每个数字 最多使用一次返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任…

    Java 2023年6月8日
    093
  • 手把手教你使用 Spring Boot 3 开发上线一个前后端分离的生产级系统(六)-本地缓存 Caffeine 和 分布式缓存 Redis 集成与配置

    Caffeine 是 Java 8 对 Google Guava 缓存的重写,是一个提供了近乎最佳命中率的高性能的缓存库。我们按照如下步骤集成和配置: 使用 spring-boot…

    Java 2023年6月8日
    074
  • Java基础-JVM篇

    1.1 .线程 ​ 这里所说的线程指程序执行过程中的一个线程实体。JVM 允许一个应用并发执行多个线程。Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关…

    Java 2023年6月8日
    067
  • SpringBoot接入两套kafka集群

    引入依赖 compile ‘org.springframework.kafka:spring-kafka’ 第一套kafka配置 package myapp.kafka; impo…

    Java 2023年6月6日
    062
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球