tcp协议总结

tcp协议和udp协议是传输层的两大协议,今天回顾一下tcp协议。

tcp全名是 传输控制协议,用于可靠传输场景,tcp协议通过复杂的手段保证传输的可靠性和速度,主要包括:

--可靠性方面:校验和、序列号(保证有序到达)、确认应答、超时重传、连接管理、流量控制、拥塞控制

--速度方面:滑动窗口、快速重传、延时应答、捎带应答

我们从tcp协议的报头开始研究tcp是如何通过上述手段实现数据的可靠传输的。

tcp协议报头:

tcp报头

--源端口号&&1目的端口号:和源ip和目的ip唯一确定1个tcp连接

--序号seq:占4个字节32位,标识本次发送数据组的第一个序号;tcp协议中,发送数据的每个字节都会有一个序号,例如,一报文段的序号为300,而且数据共100字节,则下个报文段的序号就是400

--确认序号ack:是期望对方下次发送数据的第一个字节的序号,只有当ACK标志位为1的时候,确认序号才有用;

--4位首部长度:又叫数据偏移量,实际上就是TCP段首部的长度

--6个标志位:

    URG:当URG=1时,注解此报文应尽快传送,和16位紧急指针一起使用。

    ACK:只有ACK=1时确认序号才有用;PSH:PSH=1时接收方应该尽快将本报文段立即传送给其应用层。

    RST:复位报文段,当RST=1时,表示出现连接错误,必须释放连接,然后再重建传输连接。

    SYN:同步报文段,当SYN=1,ACK=0时表示请求建立一个连接,带有SYN标志位的报文段为同步报文;

    FIN:通知对端, 本端即将关闭. 我们把含有FIN标识的报文称为结束报文段

--窗口大小:tcp通过滑动窗口来进行流量控制,可以理解为接收端所能够提供的缓冲区的大小;

--校验和:校验和覆盖整个tcp报文段,包括首部和数据,由发送方计算,接收方校验;

--紧急指针:只有URG为1的时候,紧急指针才有效;紧急指针是1个正的偏移量,序号和紧急指针的值相加,就是紧急数据的最后1个字节的序号;

三次握手

第一次握手:client向server发送连接请求报文,SYN=1, 随机生成初始序列号seq=x;然后client进入SYN-SENT状态;tcp规定SYN=1的同步报文不能携带数据,但是必须消耗1个序列号;

第二次握手:server回复client, 如果同意连接,就发送确认报文:ACK=1,SYN=1,确认号ack=x+1,同时为自己生成1个初始化序列号seq=y;此时server进入SYN-RCVD;

第三次握手:client收到后向server发出确认, ACK=1,序号ack=y+1, 此时连接建立,client进入ESTABLISHED状态;TCP规定,确认报文可以携带数据,如果不懈怠数据则不消耗序列号;

如果没有三次握手,而是两次:那么有可能出现无效的tcp连接;网络中时长会出现延迟,如果client发送了第1个请求由于网络原因一直没有到达server,client等待一会后没有收到回应再次发送了另一次连接请求,并且顺利完成了连接建立,数据传输,断开连接;而随后旧的连接终于到达了server,而server给了回应则tcp连接建立,而这个连接已经没有作用了;而如果是三次握手,client则可以不确认这个连接;

四次挥手

第一次:client发送FIN=1, seq=u(上次收到的报文的序号+1),然后进入FIN-wait-1;tcp规定FIN报文段不携带数据,但是同样消耗1个序号;

第二次:server收到后返回确认,ACK=1, 确认号ack=u+1,并且带上自己的序号seq=v, 随后server进入CLOSE-WAIT状态,client收到后进入FIN-WAIT-2状态;

此时已经进入半断开状态,client已经没有数据发送,但是如果服务端发送数据,client仍然要接受;

第三次:server数据发送完成后,r发送请求断开报文,FIN=1, ACK=1,seq=w, ack=u+1,随后进入LAST-ACK状态,等待client的最后确认

第四次:client向server确认,ACK=1, seq=w+1, seq=u+1,随后client进入2*MSL的TIME-WAIT状态才会进入CLOSED,而服务器只要收到了客户端发出的确认,立即进入CLOSED状态;

为什么最后客户端还要等待 2*MSL的时间呢?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。

第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

TIME-WAIT可能会引起BIND失败问题:

编辑内核文件/etc/sysctl.conf,加入以下内容:

net.ipv4.tcp_syncookies =1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse =1表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle =1表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout 修改系默认的 TIMEOUT 时间

确认应答机制

tcp对每个字节都进行了编号,每次发送端发送完数据,接收端返回确认ACK的时候,都需要告诉发送端自己收到哪里了,你下次从哪里发:


超时重传:


发送端发送完数据如果一直没有收到ACK,就会重发,但是也有可能出现接受端收到了数据,但是ACK请求丢失了的情况,不过没关系,有序号存在,接受端会再次发送自己收到的数据编号;

超时重发的时间间隔会以500ms为单位,后续都是整数倍后重发。

滑动窗口

如果每次发送数据后,都要等待ACK确认后才能继续发送数据,这样显然传输速度不够快,尤其是双方请求往返时间较长的时候;并且,发送方的发送速度&&接收方的接受速度是不一定匹配的,需要一个同步手段防止数据溢出,滑动窗口即是解决上述问题的;

发送方维持一个窗口,只有落在窗口范围的的数据才允许发送,接受方同样维护一个窗口,只有落在窗口内的数据才被接受;

发送方数据分为:

--已发送并收到ACK的数据:这个会从窗口删掉

--已发送未确认的数据:这个是窗口内数据

--缓冲区内待发送数据:这些数据在窗口内,接收端允许发送,需要尽快发送,窗口的大小完全由接收方告知

--待发送数据:这些数据不在窗口内,接受端也不允许发送,因为接收端的缓冲区也有限;

如果出现了丢包,也不用担心,分两种情况:

1--数据收到了,但是ACK丢了:

这种问题不大,因为还会有后续的其它ACK来确认对方收到了哪些包

2--数据丢了

如果数据丢了,接收方发送ACK的时候不会跳过确认序号,如果1~1000收到了,1001~2000丢了,2001~3000收到了,接收方返回的ACK的序号会一直是1001,并且每次收到其它序号的请求都会发送1001,发送端连续收到3次1001后就会重传;随后接收端再次发送的ACk序号就会是当前收到的连续的最大序号了,例如:1~7001,这种机制叫快重传

流量控制

tcp协议会根据接收方的处理速度来调整发送端的发送速度,这个机制叫流量控制。

接受方会将自己可以接受的缓冲区大小放入头部的窗口大小字段,发送ACK确认的时候告知发送端;

窗口越大说明网络吞吐量越高,如果发送端发现自己缓冲区快满了,就会缩小窗口大小;如果接收方处理不过来,缓冲区满了,就会把窗口大小设置为0;随后发送端会暂停发送,但是会定期发送探测请求,等接收端告知窗口大小;

实际的窗口大小计算方法:在选项中会有1个窗口扩大因子选项M,实际的窗口大小是报文窗口大小左移M位,左移1位相当于*2倍;

拥塞控制

虽然有了滑动窗口这个大杀器,但是

拥塞控制是为了解决一开始发送数据速度的问题:

因为一开始并不清楚接收方的网络状态,如果一开始就发送大量的数据有可能会存在问题。所以TCP引入慢启动机制。先发少量的数据, 探探路, 摸清当前的网络状态以后, 再决定按照多大的速度传输数据.

在此引入拥塞窗口的概念:

--发送开始的时候, 定义拥塞窗口大小为1;

--每次收到一个ACK应答, 拥塞窗口加1;

--每次发送数据包的时候, 将拥塞窗口的大小和收到对方窗口的大小比较,取较小的作为窗口大小;

这样拥塞窗口的增长速度是指数级别的,慢启动只是刚开始慢,但是增长非常快。为了防止窗口大小增长过快,会有一个限制,即慢启动的阈值,一旦超过这个阈值,就会变成线性增长, 当TCP开始启动的时候, 慢启动阈值等于窗口最大值,在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1。

少量的丢包, 我们仅仅是触发超时重传;

大量的丢包, 我们就认为是网络拥塞;

当TCP通信开始后, 网络吞吐量会逐渐上升;

随着网络发生拥堵, 吞吐量会立刻下降.

延迟应答

如果在收到数据后立刻返回ACK,这个时候可能缓冲区较小,而接收方有可能处理数据很快,这时候如果延时一小会再发送应答,那么窗口大小(缓冲区大小)就会很大,窗口越大, 网络吞吐量就越大, 传输效率就越高,所以TCP引入了延迟应答机制。

但是也不是所有的数据包都延迟应答,有两个限制:

1:数量限制:每N个包就应答一次

2:时间限制:每超过最大延迟时间就应答一次

一般N取2, 最大延迟时间取200ms

捎带应答

在延迟应答的基础上, 我们发现, 很多情况下

客户端和服务器在应用层也是 “一发一收” 的

意味着客户端给服务器说了 “How are you”

服务器也会给客户端回一个 “Fine, thank you”

那么这个时候ACK就可以搭顺风车, 和服务器回应的 “Fine, thank you” 一起发送给客户端

面向字节流

创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;

调用write时, 数据会先写入发送缓冲区中;

如果发送的字节数太大, 会被拆分成多个TCP的数据包发出;

如果发送的字节数太小, 就会先在缓冲区里等待, 等到缓冲区大小差不多了, 或者到了其他合适的时机再发送出去;

接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;

然后应用程序可以调用read从接收缓冲区拿数据;

另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区,

那么对于这一个连接, 既可以读数据, 也可以写数据, 这个概念叫做 全双工

由于缓冲区的存在, 所以TCP程序的读和写不需要一一匹配

例如:

写100个字节的数据, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;

读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100次;

粘包问题

首先需要明确的是,粘包说的是应用层的数据包;TCP没有UDP一样的报文长度字段,但是有序号,在TCP角度,数据都按照序号在缓冲区中排好了顺序,但是在应用层看来,这些数据都是连续的字节数据,那么程序就不知道从哪到哪是一个完整的应用层数据包。

解决办法:其实各种不同办法目的都是明确边界

1--约定固定大小

2--长度不固定的话,约定数据包长度字段

3--约定明确的分隔符

UDP没有粘包问题,因为UDP只要没有向上层交付数据,就保存有数据包长度;UDP是一个一个将数据交付给应用层的,有明确的界限;

TCP异常情况

--进程终止:进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别.

--机器重启:和进程终止一样

--机器断网:一旦对方有写入操作,就会发现机器不在了,就会RESET;即使一直不写入,TCP的保活计时器也会定期探测对方,如果对方不在就会释放这个连接;

--一些应用层协议也有类似的探活手段

总结:

--保障可靠性手段:

1、校验和

2、序列号(保障有序性)

3、确认应答机制

4、超时重传

5、流量控制

6、拥塞控制

7、连接管理

--保障速度的手段:

1、滑动窗口

2、快重传

3、延迟应答

4、捎带应答

--定时器

1、保活定时器

2、超时重传定时器

3、TIME-WAIT定时器

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

推荐阅读更多精彩内容