TCP 可靠传输的实现(一)TCP的三次握手和四次挥手

1、介绍TCP

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接、可靠的、基于字节流的传输层通信协议。

TCP将通过以下方式来提供可靠性传输:

TCP 可靠性传输实现(一)TCP的三次握手和四次挥手;

TCP 可靠性传输实现(二)TCP的重传机制;

https://www.jianshu.com/p/f7f75a0f6384

TCP 可靠性传输实现(三)TCP的流量控制和拥塞机制;

TCP 可靠性传输实现(四)TCP的保活机制;

TCP面向连接意味着两个使用TCP的应用(通常是一个客户端和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。这一过程和打电话相似,先拨号振铃,等待对方接通后说“喂”,然后才说明是谁。在本文将介绍TCP是如何建立连接的,以及当一方通信结束后如何断开连接。

2、TCP的首部

TCP数据被封装在一个IP数据报中,如图:

TCP数据在IP数据报中的封装

下图显示TCP首部的数据格式。如果不计任选字段,它通常是20个字节。

TCP包首部

每个TCP段都包含源端和目的端的端口号,用于寻找发端和收端应用程序。这两个值加上IP首部中的源端IP地址和目的端IP地址唯一确定一个TCP连接

一个IP地址和一个端口号也称为一个插口(socket)插口对(socket pair)(包含客户IP地址、客户端端口号、服务器IP地址和服务器端口号的四元组)可唯一确定互联网络中每个TCP连接的双方。

下面介绍下TCP首部字段

序列号:用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的第一个数据字节。如果把字节流看做在两个应用程序间的单向流动,则TCP用序号对每个字节进行计数。序号是32bit的无符号数,序号到达2^32-1后又从0开始。序号用来解决网络包乱序问题。接收端根据这个编号进行确认

确认号:是接收确认端期望收到的下一个序列号。确认号应当是上次已成功收到的数据字节序号加1,只有当标志位中的ACK标志为1时该确认号的字段才有效。主要用来解决丢包问题。

若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。

首部长度

TCP 首部总长度由该字段决定。该字段占 4bit,取最大值1111时,也就是十进制的 15,TCP 首部的偏移单位是 4 byte, 那么TCP 首部最长是 15 * 4 = 60 字节。 TCP 首部总长度有20个固定字节,所以该字段最短是 20byte / 4byte = 5,即 0101。首部长度也叫做数据偏移,因为首部长度实际上指示了数据区在报文段的起始偏移值。

保留位

为将来定义新的用途保留,现在一般置 0。

控制位:TCP首部中有6个标志比特,它们中的多个可同时被设置为1,主要是用于操控TCP的状态机的,依次为URG 、 ACK、  PSH、 RST、 SYN、 FIN。

\bullet  URG:紧急指针有效,是发送端向接收端发送紧急数据的一种方式。

\bullet  ACK:该位为1时表示【确认应答号】有效,TCP规定除了最初建立连接时的 SYN 号之外,该位必须设置为1。

\bullet  PSH:接收方应该尽快将这个报文段交给应用层。

\bullet  SYN:该位为1时表示希望建立连接,同步序号用来发起一个连接。

\bullet  RST:该位为1时表示TCP连接出现异常,必须强制断开连接。

\bullet  FIN:该位为1时表示希望断开连接。

窗口大小

TCP的流量控制由连接的每一端通过声明的窗口大小来提供。

校验和

是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证。

紧急指针

当URG标志置1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。

选项字段

选项字段的长度 = TCP 首部总长度 - 20 字节固定长度。 由于 TCP 首部总长度最大为 60字节, 那么选项字段的长度最大为 40 字节;

一个选项字段占 4个字节


最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size)。每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志的那个段)中指明这个选项。它表明本端所能接收的最大长度的报文段。

数据

数据部分是可选的,在连接建立和终止时,双方交换的报文段仅有TCP首部,如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。

3、TCP连接的建立

TCP连接的建立与关闭

第一次握手:客户端发送请求报文将 SYN = J 的初始序列号发送给服务端,发送完之后客户端处于SYN_SENT状态。

第二次握手:服务端收到SYN请求报文后,如果同意连接,会以自己的SYN(服务端) = K  的初始序列号和 ack = SYN(客户端) + 1 报文作为应答,服务端处于SYN_RECEIVE状态。

第三次握手:客户端接收到服务端的SYN+ack, 发送 ack = SYN(服务端) + 1确认包作为应答,客户端转为ESTABLISHED状态。

为什么是三次握手?不是两次、四次?

这个问题需要回到TCP的概念上:

TCP连接是为了得到 保证连接可靠性和流量控制所需维护的某些状态信息,这些信息的组合包括 Socket、序列号、窗口大小。 所以问题就是,为什么三次握手才可以初始化Socket、序列号、窗口大小并建立TCP连接。原因有三:

客户端连续发送多次SYN建立连接的报文,在网络拥堵等情况下出现:

\bullet  一个【旧的SYN报文】比【最新的SYN】报文更早到了服务端,那么此时,服务端就会回一个SYN + ACK 报文给客户端;

\bullet  客户端收到后根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示终止这一次的连接;

如果是两次握手连接,就不能判断此次连接是否是历史连接,三次握手可以让客户端准备发送第三次报文时,客户端有足够的上下文来判断当前的连接是否是历史连接。

(2)三次握手才可以同步双方的初始序列号;

TCP的通信双方都必须维护一个【序列号】,序列号是可靠传输的一个关键因素,它的作用:

\bullet  接收方可以丢弃重复的数据;

\bullet  接收方可以根据数据包的序列号按序接收;

\bullet  发送方可以标识哪些数据包是已被对方接收到的;

因此在三次握手中,当客户端方法携带【初始序列号】的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN报文已被服务端成功接收, 那当服务端发送【初始序列号】给客户端的时候,也需要得到客户端的应答回应,这样才能保证双方的初始序列号能被可靠的同步。

四次握手是把 服务端回应客户端的 ACK 请求和服务端发送给服务端的初始序列号(第二步、第三步)合并成了一步,因此就成了【三次握手】。

(3)三次握手才可以避免资源的浪费;

如果只有【两次握手】,当客户端的 SYN 请求连接在网络中阻塞,客户端超时没有收到 ACK 应答报文就会重新发送 SYN,由于没有三次握手,服务端直接就分配资源并建立连接会导致:

建立了多个冗余的无效连接,造成不必要的浪费。

两次握手会导致资源浪费

4、TCP连接的断开

四次挥手

第一次挥手:首先进行关闭的一方(即发送第一个 FIN)将执行主动关闭,而另一方(收到这个 FIN)执行被动关闭。客户端发送完 FIN 报文后,就进入了 FIN_WAIT_1 状态;

第二次挥手:服务器收到这个 FIN ,它发回一个确认应答 ACK,ack = M + 1 (即,收到的序号+1)  表示收到了,接着服务端进入CLOSE_WAIT 状态。客户端收到服务端的 ACK 应答报文后,进入 FIN_WAIT_2 状态。

第三次挥手:等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。

第四次挥手:服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端完成了连接的关闭。

为什么挥手需要四次?

\bullet  关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了,但还是能接收数据。

\bullet  服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端表示同意关闭连接。

服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手多了一次。

5、Socket编程

应用在使用 TCP 或 UDP 时,会用到操作系统提供的类库。这种类库一般被称为API(Application Programming Interface 应用编程接口),使用 TCP 或 UDP 通信时,又会广泛使用到套接字(Socket)的API。

Socket

那么TCP如何利用Socket编程

基于TCP的Socket通信

\bullet  服务端和客户端初始化 socket,得到文件描述符;

\bullet  服务端调用 bind ,将绑定 IP 地址和端口号;

\bullet  服务端调用 listen ,进行监听;

\bullet  服务端调用 accept,等待客户端连接;

\bullet  客户端调用 connect,向服务端的地址和端口发起连接请求;

\bullet  服务端 accept 返回用于传输的 socket 的文件描述符;

\bullet  客户端调用 write 写入数据; 服务端调用 read 读取数据;

\bullet  客户端断开连接时,会调用 close , 服务端 read 读取数据的时候,就会读取到 EOF,待处理完数据后,服务端调用 close 表示连接关闭。

注意:服务端调用 accept 时,连接成功了会返回一个已完成连接的socket,后续用来传输数据。所以,监听的 socket 和 用来传输数据的 socket,是两个 socket,一个是 监听 socket,一个是 已完成连接 socket。

重点讲下三次握手连接请求的实现:

通过队列实现

处于 listen 状态的 TCP socket,有两个独立的队列:

\bullet  SYN 队列(SYN Queue)

存储了收到了 SYN 包的连接,它的职责是回复 SYN + ACK 包,并且在客户端没有收到 ACK包时执行重传。 发送完 SYN + ACK 之后, SYN 队列等待从客户端发出的 Ack 包(三次握手的最后一个包)。当收到 ACK 包时,首先找到对应的 SYN 队列,再在对应的 SYN队列中检查相关的数据是否匹配,如果匹配,则将连接相关的数据从 SYN 队列中移除,创建一个完整的连接(用于传输数据的),并将这个连接加入到 Accept 队列。

\bullet  Accept 队列(Accept Queue)

存放的是已建立好的连接,等待被应用程序取走。 当进程调用 accept() 时, 将 socket 从队列中取出,传递给上层应用程序。


参考文档:
1、TCP/IP 详解

2、图解tcpip

3、https://mp.weixin.qq.com/s/tH8RFmjrveOmgLvk9hmrkw

4、https://mp.weixin.qq.com/s/5VXhL0dTFcWNyfQ7-7NBEg

5、https://mp.weixin.qq.com/s?src=11&timestamp=1592656050&ver=2412&signature=8YnNG5TR2QrxJK4CPHAknP8I4ujYG2voPwedWyH1EJXVSQUKDS5IaHvbMd3S7kpL7GrCaZkQbvgbh5OoX9IZ777abi2e3Ze-Cu1DCoLk9cexKOng3oXRfgt60fOU2gNF&new=1

6、https://blog.csdn.net/mary19920410/article/details/58030147

7、https://blog.csdn.net/Mary19920410/article/details/72857764

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352