TCP入门与实例讲解

内容简介

TCP是TCP/IP协议栈的核心组成之一,对开发者来说,学习、掌握TCP非常重要。

本文主要内容包括:什么是TCP,为什么要学习TCP,TCP协议格式,通过实例讲解TCP的生命周期(建立连接、传输数据、断开连接)

TCP简介

传输层控制协议(Transport Control Protocol),TCP/IP协议栈的核心之一。位于应用层与网络层之间,提供面向连接的、可靠的字节流服务。

记住关键词“面向连接”、“可靠”、“字节流”,这是学习掌握TCP的关键:

  • 面向连接:客户端、服务端交换数据前,需要建立连接;
  • 可靠:通过特定机制,在不可靠的网络之上,确保报文准确送达,
  • 字节流:数据的最小单位为字节。至于字节中存储内容的含义,由于应用层的程序决定。

TCP如何确保服务可靠性

TCP花了大量的功夫在确保传输层服务的可靠性上,具体举措包括(但不限于)以下:

  • 应用数据切割:应用数据被分隔成TCP认为最适合发送的多个报文段(由特定的算法和机制来确认)
  • 接收端确认:接收端收到报文段后,会向发送端发送确认报文;
  • 超时重传机制:发送端发送一个报文段后,会启动定时器,等待接收端确认收到这个报文;如果没有及时收到确认,发送端会重新发送报文;
  • 数据校验和:发送端发送的报文首部中,有个叫做校验和(checksum)的特殊字段,它是根据报文的首部、数据计算出来的。这是一个端到端的校验和,用来检测传输过程数据的变化。接收端收到报文后会对校验和进行检查,如果校验和存在差错,则丢弃这个报文,且不确认收到此报文(等待发送端超时重发)
  • 报文段排序:TCP报文包裹在IP数据包里进行传输,而IP数据包的到达次序是不固定的。接收端会对接收到的报文段重新排序,这个对应用层是无感知的;
  • 去重复:接收端丢弃重复的报文(比如,因某些原因,虽然接收端已经收到报文,且给发送端发送了接收确认,但接收端没有收到该确认,超时后重新发送了同样的报文);
  • 流量控制:TCP连接双方都有固定大小的缓冲空间,且只允许发送端发送缓冲空间能够容纳的数据,避免缓冲区溢出;

TCP传输服务的可靠性对应用层的开发者来说至关重要。作为应用层的开发者(比如HTTP server),除了业务逻辑之外,如果还需要操心数据是否正常送达,接收到的数据是否完整,开发效率会相当低下。

参考自《TCP/IP详解卷一》,推荐阅读

TCP首部格式

TCP首部格式如下图所示,在不包含可选字段的情况下,大小通常为20个字节。部分字段定义可能并不直观,如果读者觉得某些首部字段不好理解,建议先跳过,结合后文的实例可能更容易理解些。

比如 Sequence Number/Acknowledgment Number/ACK/SYN,结合TCP建立连接的过程来看,会更好理解。

这里留个小问题给读者:怎么知道TCP报文段数据(data)的长度是多少?

Source Port(来源端口):16位

Destination Port(目的端口):16位

Sequence Number(序号):32位

TCP报文段中的数据部分,每一个字节都有它的序号(递增)。根据控制标志(Control Bits)中的SYN是否为1,Sequence Number 表达不同的含义:

  • SYN = 1:当前为连接建立阶段,此时的序号为初始序号(ISN)。当数据传输正式开始时,数据的第一个字节的序号为 ISN + 1;
  • SYN = 0:当前报文段中,数据部分的第一个字节的序号。

Acknowledgment Number(确认序号):32位

当控制标志的ACK为1时,表示发送方希望收到的下一个报文段的序号(Sequence Number)。一旦连接建立成功,ACK值一直为1。

Data Offset(数据偏移量):4位

TCP报文段的首部长度,单位是word(4字节)。字面含义是:TCP报文段的数据的起始处,距离TCP报文段的起始处 的偏移量。4个字节最大能表示的数字是15,所以首部最大60字节。

Reserved(保留字段):6位

预留作为后续用途,必须是0。

Control Bits(控制标志):6位

一共有6个控制标志,其中SYN/ACK、FIN/ACK主要用于连接的建立、断开阶段。

  • URG: 当置为1时,表示紧急指针(Urgent Pointer)字段有效;
  • ACK: 确认序号字段(Acknowledgment Number)有效;
  • PSH: 接收方应立即把这个报文段交给应用层;
  • RST: 重建连接;
  • SYN: 同步序号,用于建立连接;
  • FIN: 发送端不再发送数据;

Window Size(窗口大小):16位

允许对方发送的数据量。告诉对方自己缓冲区还能容纳多少字节,用来控制对方发送数据的速度。

比如,服务端发送给客户端的TCP报文段中,确认序号是701,窗口字段(Window Size)是1000,表明服务端能够接受客户端发来的,序号从701开始的1000字节数据。

Checksum(校验和):16位

发送端对TCP首部、数据进行CRC运算得出的结果。接收端收到数据后,对接收到的TCP报文段的首部、数据进行CRC运算,并跟TCP首部中的校验和进行对比,确保数据在传输过程中没有损坏。

计算、校验规则这里先不展开。

Urgent Pointer(紧急指针):16位

仅在URG=1时才生效,它的值是一个偏移量,和序号字段中的值相加得到紧急数据最后一个字节的序号。

options(可选字段):大小不固定

最常见的可选字段是MSS(Maximum Segment Size),表示最长报文大小,通信双方通常在连接的第一个报文段中指明这个选项。(只能出现在SYN报文中)

建立连接 vs 断开连接

TCP的两段正式开始传输数据前,需要先建立连接。一旦数据传输完成,则需要断开连接。

后面章节中,会通过实际例子说明TCP数据传输的完整生命流程。在这之前,先简单介绍下TCP是如何建立连接以及断开连接的,也就是我们所熟悉的3次握手以及4次挥手。

这里留几个问题给读者朋友:

  1. 建立连接的主要目的是什么?做了哪些事情?
  2. 建立连接为什么是3次握手,可不可以是2次?
  3. 断开连接一定要4次挥手吗?

Seq => Sequence Number,Ack => Acknowledgment Number,[SYN] => 控制标志SYN,[ACK] => 控制标志ACK

建立连接

一般情况下,握手流程如 下图 所示,主要做了两件事情:

  1. 互相确认对方当前可以建立连接
  2. 互相交换确认初始序列号(ISN)

断开连接

一般情况下,TCP断开连接需要4次挥手。假设 TCP A 主动断开连接,流程如下。主要就是告知对方,自己准备断开连接了,并且等待对方的确认。

从实例看TCP生命周期

在这一小节,会通过例子,阐述TCP从建立连接,到数据传输,到最后断开连接的整个过程,并通过wireshark抓包探究一些通信的细节。

首先,打开wireshark监听网络请求。然后,在终端输入如下命令发送HTTP请求。

curl http://id.qq.com/index.html

下面为wireshark抓包截图,分为3个部分,分别为 (1)建立连接,(2)数据传输,(3)断开连接。

建立连接

1、本地 -> 服务端:[SYN] Seq=0;

备注:本例子中中,客户端、服务端的初始Seq值其实不是0,截图中展示的0是个相对值,是wireshark为了方便开发者进行抓包分析转化过来的。

2、服务端 -> 本地:[SYN, ACK] Seq=0, Ack=1;

3、本地 -> 服务端:[ACK] Seq=1, Ack=1

到这里,双方连接建立,开始交换数据

数据传输

数据交换是双向的,这里以服务端的HTTP响应为例子。响应内容较大,被拆成了多个TCP包。整个数据发送的过程,就是服务端向客户端发送数据,客户端向服务端发送确认的过程。

1.1、服务端->客户端:Seq=1,TCP数据长度273。也就是说,服务端发送的报文段中,第一个数据字节的序号是1;下一个TCP报文段,第一个数据字节的序号应该是274。

1.2、客户端->服务端:Ack=274。表示客户端已经收到序号274之前的所有字节;也就是说,服务端如果继续给客户端发送TCP报文,应该发送序号274及以后的数据。

2.1、服务端->客户端:Seq=274,TCP数据长度1400。也就是说,服务端发送的报文段中,第一个数据字节的序号是274;下一个TCP报文段,第一个数据字节的序号应该是1674(274 + 1400)。

2.2、。。。

后面的分析过程同上。

断开连接

从抓包中看到比较有意思的点。当服务端收到客户端的断开请求时(FIN=1),服务端在同一个响应包里发送了FIN、ACK,达到了减少一个数据包的效果。

为什么要学习TCP

笔者在前端招聘的面试中,经常会问一些网络基础方面的问题,经常会有面试者感到困惑:为什么要问这些问题?这些知识是他们需要掌握的吗?好像跟工作关联不大?

这可能是普遍的误区。

掌握HTTP协议的重要性不用强调,WEB开发者的基础要求之一。但是,有必要学习TCP吗?这个问题倒是值得思考一下。

答案是:很有必要。

举个例子:

WebSocket是基于TCP的,并复用了HTTP的握手通道。如果开发者对HTTP、TCP没有一定的了解,那么在使用WebSocket的时候,WebSocket对他来说就像一个黑盒,充满了各种黑科技。WebSocket、HTTP两者有什么关联?WebSocket跟Socket.io有什么关联?为什么服务端开启多个Socket.io实例,并通过反向代理进行转发后,连接握手就会失败?

如果开发者对HTTP、TCP足够了解,在遇到上面的问题时,就不至于毫无头绪。

再举个例子:

在探究性能优化时,经常会提到HTTP/2。什么是HTTP/2,为什么说HTTP/2的性能比HTTP 1.1好?什么是HTTP/2的多路复用?是怎么实现的?有什么好处?

同样的,如果对HTTP、TCP足够了解,上面的问题并不难回答,翻翻书或协议,至少能够回答个大概。

写在后面

TCP/IP由复杂的协议栈组成,而TCP是协议栈中的核心部分。TCP协议本身非常复杂,本文只是对基础部分进行了讲解,还有许多内容尚未覆盖到,比如TCP的超时重传机制、拥塞控制机制等,后面有时间再继续展开。

如有错漏,敬请指出。

相关链接

《TCP/IP详解卷一》

Difference between push and urgent flags in TCP

Calculate size and start of TCP packet data (excluding header)

Why do we need a 3-way handshake? Why not just 2-way?

原文地址:https://www.chyingp.com/posts/understanding-tcp/

原文地址:https://www.cnblogs.com/chyingp/p/understanding-tcp.html

时间: 2024-08-08 05:49:56

TCP入门与实例讲解的相关文章

【智能算法】粒子群算法(Particle Swarm Optimization)超详细解析+入门代码实例讲解

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 算法起源 粒子群优化算法(PSO)是一种进化计算技术(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源于对鸟群捕食的行为研究 .该算法最初是受到飞鸟集群活动的规律性启发,进而利用群体智能建立的一个简化模型.粒子群算法在对动物集群活动行为观察基础上,利用群体中的个体对信息的共享使整个群体的运动在问题求解空间中产生从无序到有序的演化过程,从而获得最优解.

Nodejs进阶:核心模块net入门与实例讲解

模块概览 net模块是同样是nodejs的核心模块.在http模块概览里提到,http.Server继承了net.Server,此外,http客户端与http服务端的通信均依赖于socket(net.Socket).也就是说,做node服务端编程,net基本是绕不开的一个模块. 从组成来看,net模块主要包含两部分,了解socket编程的同学应该比较熟悉了: net.Server:TCP server,内部通过socket来实现与客户端的通信. net.Socket:tcp/本地 socket的

10,Scrapy简单入门及实例讲解

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. Scrapy 使用了 Twisted异步网络库来处理网络通讯.整体架构大致如下 Scrapy主要包括了以下组件: 引擎

数学建模学习笔记(第二章:7个入门建模实例讲解)

第二章:初等模型(初等数学方法建模) 1.    席位分配: a)      问题描述:三个系学生共200名(甲系100.乙系60,丙系40).代表会议共20席,按比例分配,三个系分别为10,6,4席. b)     问题存在:现因学生转系,三系人数分别变为:103,63,34.问20个席位如何分配?才能使得尽量"公平". c)      解决方法:提出不同的假设,进行不同方法的讨论,对不同方法进行对比分析(满足哪些公平条件),得出结论. 2.    双层玻璃窗的功效: a)     

scrapy简单入门及实例讲解

爬虫是python最常见的一类应用,但是如何自己动手来写一个爬虫,这可能是很多人关心的问题,这次准备用30分钟来教会大家如何自己动手编写一个Scrapy爬虫的应用 推荐一个不错的Scrapy视频教程给大家,可以直接点击观看:https://www.bilibili.com/video/av27042686/ 一.理解爬虫原理 首先,我们需要理解爬虫的原理,只是拿一个库来用谁都会,但理解它的原理才对大家有好处 通过上图我们可以对爬虫的工作原理(不仅限于Scrapy框架)有一个认识: 数据源:需要知

OSGI入门实例讲解(一)

开放服务网关倡议(OSGi)定义了开发和部署模块应用程序和库的体系结构.作为介绍OSGi的第一篇文章,本文旨在让你了解OSGi开发的一些概念,并向你展示了如何使用Eclipse的OSGi容器(Equinox)实现建立一个简单的Hello World应用.此外还简要介绍了使用OSGi构建面向服务的应用程序以及OSGi的servicefactory和servicetracker类. OSGI(Open Services Gateway Initiative),也叫JAVA动态模块系统,定义了一套模块

基于tcpdump实例讲解TCP/IP协议

前言 虽然网络编程的socket大家很多都会操作,但是很多还是不熟悉socket编程中,底层TCP/IP协议的交互过程,本文会一个简单的客户端程序和服务端程序的交互过程,使用tcpdump抓包,实例讲解客户端和服务端的TCP/IP交互细节. TCP/IP协议 IP头和TCP头格式如下: Internet Header Format 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+

[转帖]linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)

https://www.cnblogs.com/caozy/p/9261224.html 总结的挺好的 我之前想总结 一直懒 这次国庆加班 也本来计划来着 感冒了 作罢 .. 作者:蓝藻(罗蓝国度) 创建时间:2018.7.3编辑时间:2019.7.16 前言 本文特点 授之以渔:了解命令学习方法.用途:不再死记硬背,拒绝漫无目的: 准确无误:所有命令执行通过(环境为centos7),拒绝复制粘贴: 实用性高:命令多为实际工作中用到的,实例讲解,拒绝纯理论: 条理清晰:分类归纳,快速找到想要的命

Java入门系列:实例讲解ArrayList用法

本文通过实例讲解Java中如何使用ArrayList类. Java.util.ArrayList类是一个动态数组类型,也就是说,ArrayList对象既有数组的特征,也有链表的特征.可以随时从链表中添加或删除一个元素.ArrayList实现了List接口. 大家知道,数组是静态的,数组被初始化之后,数组长度就不能再改变了.ArrayList是可以动态改变大小的.那么,什么时候使用Array(数组),什么时候使用ArrayList?答案是:当我们不知道到底有多少个数据元素的时候,就可使用Array