TCP协议

  1. TCP头部格式

    1 ) 16位端口号:
    告知主机该报文段是来自哪里以及传给哪个上层协议或者应用程序的。在TCP通信时,客户端通常使用系统自动选择的临时端口号,而服务器则使用知名服务端口号。知名服务端口号定义在/etc/services中。

    2 ) 32位序号:
    一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号。
    假设主机A和主机B进行TCP通信,A发给B的第一个TCP报文段中,序号值被初始化为某个随机值ISN,那么在这个传输方向上,后续的TCP报文段中的序号值被系统设置为ISN+该报文段所携带数据的第一个字节在整个字节流中的偏移。
    例子:某个TCP报文段传送的数据是字节流中的第1025~2048字节,那么该报文段的序号值就是ISN+1025。

    3 ) 32位确认号:
    用作对另一方发送的TCP报文段的相应。其值是收到的TCP报文段的序号值加1。

    4 ) 4位头部长度:
    标识TCP头部有多少个4Byte。4位能表示0~15,所以TCP头部最长为60Byte。

    5 ) 6位标志位
    URG:表示紧急指针是否有效。
    ACK:表示确认号是否有效。一般携带ACK标志的TCP报文段为确认报文段。
    PSH:提示接收端应该立即从TCP接受缓冲区中读走数据,为接受后续数据腾出空间。
    RST:表示要求对方重新建立连接。一般称携带RST标志的TCP报文段为复位报文段。
    SYN: 表示请求建立一个连接。一般称携带SYN标志的TCP报文段为同步报文段。
    FIN: 表示通知对方要关闭连接了。一般称携带FIN标志的TCP报文段为结束报文段。

    6 ) 16位窗口大小:TCP流量控制的一个手段。指的是接受通告窗口,告诉对方本端TCP接受缓冲区还能容纳多少字节的数据,这样对方可以控制发送数据的速度。

    7 ) 16位校验和:由发送端填充,接收端对TCP报文段执行CRC算法,验证是否损坏。

    8 ) 16位紧急指针:是一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一个字节的序号。确切的说,这个字段是紧急指针相对当前序号的偏移。

    总结:

    1 ) TCP的包没有IP地址,但是有源端口和目的端口。
    2 ) 一个TCP需要4个元组(src_ip、src_port、dst_ip、dst_port)来表示是同一个连接。(还有一个是协议)
    3 ) sequence number是包的序号,用来解决网络包乱序问题。
    4 ) acknowledgement number是ack,用于确认收到。
    5 ) window也就是滑动窗口,用于解决流控问题。
    6 ) TCP Flag,包的类型,用于操控TCP的状态。

  2. TCP的3次握手与4次挥手
    TCP所谓的连接,是在通信双方维护一个连接状态。

    1 ) 建立连接(3次握手)
    第一次握手:建立连接时,客户端发送SYN=J到服务器,进入SYN_SEND状态,等待服务器确认。
    第二次握手:服务器收到SYN=J的包,确认客户的SYN=J(ACK=J+1),同时自己也发送一个SYN=K包,此时服务器进入SYN_RECV状态。
    第三次握手:客户端收到SYN=K以及ACK=J+1包,向服务器发送ACK=K+1包。此包发送完毕,双方进入ESTABLISHED状态。
    至此,双方开始传送数据,也就是ESTABLISHED状态。

    2 ) 结束连接(4次挥手)
    TCP有一个概念是半关闭:TCP的连接是全双工,因此在关闭时,必须关闭传和送两个方向的连接。客户端给服务器一个FIN,然后服务器返回一个ACK,服务器再发送一个FIN,当客户端回复ACK时,连接正式结束,也就是4次挥手。

    3 ) 握手和挥手的次数
    可以注意到握手时,服务器将SYN和ACK同时发送过来,显得次数减少,那为什么挥手时必须分开呢?
    因为TCP是全双工的,意味着客户端向服务器停止发送以后,服务器还可能继续发送数据,因此要等待服务器传完数据后,主动发起FIN。

  3. TCP状态转换图
    分为客户端主动关闭连接,服务器主动关闭连接,客户端服务器同时关闭三种情况。
    TCP状态转换图参考

    1 ) 客户端主动关闭连接:

    CLOSED:表示初始状态。

    LISTEN:表示服务器端的某个socket处于监听状态,可以接受连接。

    SYN_SENT:服务器监听后,客户端socket执行connect连接时,客户端发送SYN,此时客户端进入SYN_SENT。

    SYN_RCVD:表示服务器接受到了SYN,是服务器socket在建议TCP3次握手过程中一个中间状态,很短暂。

    FIN_WAIT_1:建立连接之后,其中一方socket请求终止连接,等待对方的FIN。当对方回应ACK后,进入到FIN_WAIT_2状态。

    FIN_WAIT_2:半连接状态,主动关闭方依旧可以接受数据,被动关闭方依旧可能传送数据。

    TIME_WAIT:收到了对方的FIN,并发送了ACK,再等待2MSL后即可回到CLOSED。如果在FIN_WAIT_1的状态下,同时收到了对方FIN和ACK的报文,可以直接进入到TIME_WAIT状态。

    CLOSE_WAIT:等待关闭,即被动关闭的一方,在发送完ACK以后,观察是否还有数据要发送给对方,如果没有,自己也可以关闭socket了。

    LAST_ACK:被动关闭一方在发送FIN后,等待对方ACK。

    需要注意的是,listen状态的socket与其后状态(如SYN_RECV的socket)其实不是一个socket。每次TCP连接,客户端和服务器端都会新建一个5元组socket。最后close关闭的也是这个新创建的socket,而不是监听socket。

    2 ) 服务器主动关闭连接:

    3 ) 客户端服务器同时关闭

    CLOSING:指主动关闭方发出FIN以后没有先收到ACK,而是先收到了对方的FIN,这意味着双方都正在进行socket关闭。

    上图是两端的FIN同时到达的情况,先进入CLOSING,直到两端再次收到对方的ACK,再进入TIME_WAIT,等待2MSL后关闭连接。

    假如有一方的FIN是先到的:

    当客户端先收到服务器端的FIN,由于FIN早于ACK,客户端进入CLOSING,直到收到ACK,再进入TIME_WAIT。而服务器端先收到了ACK,那么先进入FIN_WAIT_2,再收到了客户端的FIN,然后响应了ACK,进入TIME_WAIT。

  4. TCP超时重传
    当网络出现超时或者丢包时
    1 ) 数据顺利到对端,对端顺利相应ACK。
    2 ) 数据包中途丢失。
    3 ) 数据包顺利到达,但ACK中途丢失。
    4 ) 数据包顺利到达对端,但对端未响应ACK或被对端丢弃。

    出现这些异常情况时,TCP就会超时重传。TCP每发送一个报文段,就会对其设置一次计时器。只要重传时间到了,但没有ACK,就要重传这一段报文。

    RTO:Retransmission TimeOut,指发送端发送数据后,重传数据前等待接收方收到该数据报文的ack时间。

    RTO=t2-t1

    如果RTO设长了,重发就慢,效率性能差;
    如果RTO设短了,重发快,增加网络堵塞,导致更多超时,更多超时导致更多重发。

    TCP协议必须适应两个方面的时延差异:
    达到不同目的端的时延差异;
    同一连接上的传输时延随环境变化出现的差异。
    为此TCP必须使用自适应算法应对。

    为了动态的设置,TCP引入了RTT(Round Trip Time)。指发送端从发送TCP包开始到接受它的立即响应所消耗的传输时间。

    RTT=t3-t1

    对一个连接而言,若能了解端点间的RTT,就可以根据RTT设置一个合适的RTO。以下是自适应算法通过对当前RTT的准确估计,适时调整RTO。

    但是这个算法在重传时会有一个问题:如果用第一次的时间和ACK回来的时间做RTT样本,或是用第二次重传的时间和ACK时间做RTT样本,都会有重传的多义性问题。

    下图中如果算t3-t1就会偏大,t2-21就会偏小。

    因此在1987年出现了Karn/Partridge Algorithm,特点为忽略重传,不把重传的RTT做采样。但是又引发了另一个bug——如果某一时间网络突然变慢产生了大延时,这个延时导致要重传所有的包(因为之前的RTO相对延时来说很小),这会导致RTO不被更新。
    使得发送时间小于重发时间,不断的重发。
    于是Karn算法用了一个取巧的方法:只要发生重传,就对现有的RTO翻倍。

    当不再重传时,才根据报文段的往返时延更新RTT和RTO。

用telnet和tcpdump来做个实验:
首先在第一个终端输入:

 tcpdump-ieth1 'port 1055'//用来抓取网卡eth1上的1055端口上的包

然后在第二个终端输入:

 telnet 218.111.111.111 1055

过了一会可以看到:

这时切换到第一个终端:

可以发现重发的包相隔时间为:1s、2s、4s和8s,符合Karn算法对重传时RTO的处理。

5.TCP滑动窗口
主要作用:体现了TCP的可靠性;提供了TCP的流量控制特性;体现了TCP面向字节流的设计思路。


TCP窗口是16bit位字段,代表窗口的字节容量,最大为65535字节。
另外TCP选项中包含了一个TCP窗口扩大因子,可把16bit窗口,扩大为32bit。

对于TCP会话的发送方,在其发送缓存内的数据分为4类:
1 ) 已经发送且得到对端ACK。
2 ) 已经发送但还未收到对端ACK。
3 ) 未发送但对端允许发送。
4 ) 未发送且对端不允许发送。
其中2)和3)的两部分数据称为发送窗口。


当收到接收方新的ACK对于发送窗口中后续字节的确认时,窗口会进行滑动:

对于TCP会话的接收方,接受缓存有3种状态:
1 ) 已接受。
2 ) 未接受准备接受。
3 ) 未接受并未准备接受。
其中未接受准备接受为接受窗口。

将接收方与发送方对比,发现接收方没有“已接受但未回复ACK”,这是因为ACK直接由TCP协议栈回复,默认无应用延迟,因此不存在这种情况。

流量控制的实现:
TCP是双工的协议,双方都可以接受、发送数据。其中各自的接受窗口大小取决于应用、系统、硬件的限制(TCP的传输速率不可大于应用的数据处理速率)。各自的发送窗口则取决于对端的接受窗口。

滑动窗口面向流的可靠性:
来源于确认重传机制。发送窗口只有收到对端对于本端发送窗口内字节的ACK确认,才会移动发送窗口的左边界。接受窗口只有在前面所有的段确认的情况下才会移动左边界。(在前面还有字节未接受但收到后面字节的情况下,窗口不会移动,并不会对后续字节进行确认,保证了两端数据的重传)

应用程序在需要时,通过API通知TCP协议栈缩小TCP的接受窗口。然后TCP协议栈在下个时间段发送时包含新的窗口大小通知对端。对端按通知的窗口改变发送窗口,以此达到减缓发送速率的目的。

6 拥塞控制

网络资源:计算机网络中的带宽、交换结点中的缓存和处理机等。
拥塞:在某段时间中,若对网络中某以资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏。

拥塞控制:防止过多的数据注入到网络中,使得网络中的路由器或者链路不致过载。

拥塞控制与流量控制的区别:
区别的参考
流量控制解决的是发送方和接收方速率不匹配的问题,发送方发送过快接收方就来不及接受和处理。采用滑动窗口的机制。是点对点通信量的控制。

拥塞控制解决的是避免网络资源被耗尽的问题,通过大家自律的采取避让,防止有限的网络资源耗尽。是一个全局性的过程。

TCP的拥塞控制由4个核心算法组成:

1 ) 慢开始和拥塞避免
发送方维持一个拥塞窗口cwnd(congestion window)。cwnd的大小取决于网络的拥塞程度,动态变化。发送方让自己的发送窗口等于或这小于cwnd。

慢开始算法思路:不要一开始就发送大量数据,先探测一下网络拥塞程度,从小到大增加cwnd窗口的大小。

慢开始原理:(用报文段个数的拥塞窗口大小举例,而实时拥塞窗口大小以字节为单位)
在刚开始发送报文段时将cwnd设置为一个最大报文段的MSS的数值。在每收到一个对新报文段的确认后,将cwnd增加至多一个MSS的数值。当cwnd足够大的时候,为了防止cwnd增长引起的网络拥塞,需要另外一个变量,即慢开始门限ssthresh。

在cwnd达到ssthresh之前,增长是2的x次幂,为指数增长。
当cwnd=ssthresh,执行拥塞避免算法,cwnd每次加1,为 线性增长。
当网络发生拥塞,把ssthresh更新为拥塞前ssthresh的一半,并重新开始慢开始算法。

2 ) 快重传和快恢复
快重传:要求接收方在收到一个失序的报文段后就立即发出重复确认。当发送方只要一连收到3个重复确认就应当立即重传对方尚未收到的报文段,而不是等待重传计时器时间到期。

注意m3还没确认,m4、m5、m6对于m2失序,连续3次重复确认后,不等RTO,立即重传m3。

快重传配合使用的还有快恢复算法:
当发送方连续收到3个重复确认,执行乘法减小,把ssthresh减半,但并不执行慢开始。
不执行慢开始是因为能连续收到3个重复确认,则当前网络并不拥塞,因此只是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。

后台开发核心技术(七)TCP协议相关推荐

  1. 《后台开发核心技术与应用实践》读后感和一些思考

    今天是1024程序员节,先祝大家节日快乐! 前言: 最近拜读了腾讯的<后台开发核心技术与应用实践>,其实这本书很早之前就听说过,可以说是"大名鼎鼎",也可以说是&quo ...

  2. Linux后台开发必看!

    来自:我是程序员小贱 一 自我介绍二 面试情况三 相关知识点汇总1 c/c++相关2 计算机网络3 数据结构相关4 数据库相关5 操作系统6 Linux基础知识及应用编程(后台必备!)7 大数问题8 ...

  3. 【Linux】C++后台开发面试

    本文将讲述(Linux)服务器后台开发岗位的要求,包含了大部分会遇到的面试题目.掌握文中提到的技术,也算少许入门水平了,此文既是面经,也是后台开发的入门手册.无论社招还是校招,都可作为一个参考. 本文 ...

  4. 「Linux」C++后台开发面试总结(献给进击BAT的你)

    本文将讲述(Linux)服务器后台开发岗位的要求,包含了大部分会遇到的面试题目.掌握文中提到的技术,也算少许入门水平了,此文既是面经,也是后台开发的入门手册.无论社招还是校招,都可作为一个参考. 本文 ...

  5. 零基础C++后台开发学习路线

    个人介绍: 首先介绍一下自己吧,我是一名非科班硕士,本硕某985,本科对于编程这块的学习很浅显,数据结构都没学过,基本上到了研一才开始认真学习这块知识.这篇文章实际上是我自己入门编程过程的总结,在大学 ...

  6. php即时聊天的框架_workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

  7. TCP协议调试工具TcpEngine V1.3.0使用教程

    简介 这里说的TCP协议调试定义是在开发长连接TCP协议应用时,为了验证代码流程或查找bug,需要与对端交互数据过来,当需要时可以暂停发送:单条发送:跳过发送:正常发送:发送时修改数据等. TcpEn ...

  8. 软件开发架构介绍||OSI七层协议之物理层、数据链路层、网络层、传输层(mac地址、ip协议、断开协议、tcp协议之三次握手四次挥手)

    阅读目录 一.网络编程 一.网络编程 软件开发架构 C/S架构 C:客户端 想体验服务的时候才会去找服务端体验服务 S:服务端 24小时不间断的提供服务,即时监听,随时待命 B/S架构 B:浏览器 想 ...

  9. Day09: socket网络编程-OSI七层协议,tcp/udp套接字,tcp粘包问题,socketserver

    今日内容:socket网络编程     1.OSI七层协议     2.基于tcp协议的套接字通信     3.模拟ssh远程执行命令     4.tcp的粘包问题及解决方案     5.基于udp协 ...

最新文章

  1. springmvc开启事务_java面试题 一 :SpringMvc的流程
  2. 全国大学生智能汽车竞赛-讯飞智慧餐厅
  3. 资源盗链困扰站长 安全狗内置盗链保护功能
  4. Laravel 向视图传递变量的3种方法
  5. Linux 下监控系统几个重要组件
  6. JS 操作cookie
  7. 8/7-8/8-8/9 今日TF训练
  8. java 开发银行支付、对账时证书相关的操作总结
  9. C++ 实现简易 log 日志系统
  10. Hibernate性能优化2( 转)
  11. latex做ppt_用Markdown可以做什么
  12. mysql hy000 死锁_mysql 数据库死锁-解决
  13. linux 内核模块 定时器,linux内核定时器__backup_timer_hour_struct_定时器_模块__169IT.COM...
  14. 常见API漏洞解释以及应用层解决方案
  15. opencms的安装
  16. 迅雷离线下载节点分布
  17. Kali新安装时软件安装及配置[自用 欢迎补充]
  18. C语言——数组定义及用法
  19. 防封策略(适用所有游戏)
  20. zoj 2675 Little Mammoth 圆与四边形的公共面积

热门文章

  1. nasa 开源_3D打印的小提琴,NASA的新工具以及更多开源新闻
  2. LV.11 嵌入式系统驱动初级
  3. PHP如何讲值输出到文本框,PHP转换文本框内容为HTML格式的方法
  4. 基于Labview的图像傅里叶变换研究-含Labview程序
  5. 音视频之解析flv文件实战
  6. 谷歌浏览器自带网页截屏工具的使用
  7. cadence 仿真器 licence 相关命令 FLEXlm licence 管理工具
  8. Windows 10/11 中的快速录屏的 5 种方法
  9. GitGUI出现 Unable to obtain your identity
  10. 微软小娜APP的案例分析