TCP协议详解(一)
Tcp协议作为传输层的重要协议之一,想必每个稍有网络编程知识的人都不会感觉到陌生,三次握手/四次挥手这些基本概念也都是耳熟能详。但是当你们进行具体的网络编程的时候发现有很多事情并没有想象中的那么简单,会遇到很多·奇奇怪怪·的问题,说白了还是对于tcp协议的了解太过浮于表面。作为一个开发人员而言可能经常会去网上搜索一下有没有相关答案,但是即便问题解决了也是知其然不知其所以然。而不停的搜索答案试错是一种十分低劣的解决问题手法,个人观点认为当你遇见一个陌生的问题时如果时间允许的话先去了解它,这样解决问题会事半功倍(虽然前期效率可能会低一些)。
为了我们以后在网络编程的时候少挖一些坑,我们来仔细扒一扒tcp协议,下面的内容都引用于《计算机网络技术自上向下》第六版,话不多说开整。
一、tcp协议的数据结构

上图是tcp的段数据结构:
source port:数据来源端口 16bit
dest port:数据目的端口 16bit
sequence number:数据序列号 32bit
acknowledge number:数据应答编号 32bit
Header Length:头部长度 4bit
Unused:保留位 6bit
flage filed:标识位 6bit
receive window:接受窗口大小 16bit
internet checksum:校验位 16bit
urgent data pointer: 16bit
options:可选数据域 长度可变
data: 负载数据 长度可变
一般情况下options的长度为0,此时tcp协议数据段头部为20bytes,相比udp协议数据段头部多12bytes。这里要对数据序列号和确认号进行一下单独的说明,所谓的序列号与直观印象上的报文编号(1、2、3、4)这种不一样,我们举一个例子会直观一些比较:
例子: Alice 向 Bob 发送一个4M的文件:
假设Alice 的Seq起始值是 0,
第一个报文:
Seg0( Alice send to Bob): ....|Seq 0 | .... | Data (0~999 bytes)
Ack0 (Bob to Alice): ....| Ack 1000 ....
第二个报文
Seg1( Alice send to Bob): ....|Seq 1000 | Data (1000~2999 bytes)
Ack2 (Bob to Alice): .... Ack 3000 ....
... ...
细心的大佬就会发现了,这里的序列号和确认号实际上嘞是传输字节的序列,而不是报文的顺序,而确认号是接收方期待的下一个报文的序列号。
二、tcp的逻辑描述
我们在这里对tcp进行一个比较简单的逻辑上的描述,大家都知道网络层ip协议是管杀不管埋的,你报文能不能发送到?发送的完不完整?它一概不管,反正我是发了。所以tcp就在ip上封装了一层,来完成“全双工的可靠传输”--通过超时机制和冗余确认技术进行报文恢复,从而保证可靠传输。
tcp它不是一个停等协议,而是一个流传输协议。在整个tcp的传输流程中,有三个比较重要的事件:
Event 0:进程下发数据
Event 1:定时器超时
Event 2:Ack确认消息
下面附上书中的一段伪代码:
/* Assume sender is not constrained by TCP flow or congestion control, that data from above is less
than MSS in size, and that data transfer is in one direction only. */
NextSeqNum=InitialSeqNumber
SendBase=InitialSeqNumber
loop (forever) {
switch(event)
event: data received from application above
create TCP segment with sequence number NextSeqNum
if (timer currently not running)
start timer
pass segment to IP
NextSeqNum=NextSeqNum+length(data)
break;
event: timer timeout
retransmit not-yet-acknowledged segment with smallest sequence number
start timer
break;
event: ACK received, with ACK field value of y
if (y > SendBase) {
SendBase=y
if (there are currently any not-yet-acknowledged segments)
start timer
}
break;
} /* end of loop forever */
这段伪代码很好理解,主要就是处理我们上面说的三种重要的event:
event0 检查是否开启定时器 + 发送数据 + 序列号递增;
event1 从没有收到确认信息的最小序列号报文开始重传 + 开启定时器;
event2 更新sendBase+ 如果当前没有未被确认的seg就开启下一轮计时
ps:这里面start time后就会重新计时,timer只有一个,不是每发送一个报文就要开启一个timer。
逻辑上是不是很简单?这是那个搞得人头晕的tcp吗?没错,它的抽象逻辑就是这么简单,就是这么简单的逻辑,实现了我们现在网络的基石协议之一。当然这只是一个概述而已,实际情况要比这个复杂的多,不要误以为tcp实现起来很简单。我们要在这个简单模型的基础上不断的去完善它,我下面说三种情况,大家来思考一下有什么启发,理解一下这个模型有什么精妙之处,看看这个模型是怎么来保证可靠传输的:
我们假设这三种情况之前都是正常的!

第一种情况:
1)ACK缺失,timout时间内未收到确认;
2)timeout 触发event1,这时从序列号最小的未被确认报文重传 seq92,重启timer;

第二种情况比较复杂那么一点点:
1)我们可以看到在第一个timeout 内 Seq 92、Seq 100的Ack并未返回;
2)当timeout时 event1 被触发,我们重传了Seq 92 ,重置了timer;
3) 在 第二次time out 之前 Ack 100和 Ack 120收到 ,此时没有未被确认的segments(这样我们就不需要重传seq100), 重置timer;
4)再次收到 Ack 120
ps:这里面有老铁会迷惑:我在第二个timeout中重传了Seq92,为对方返回的是Ack 120? 这个问题容我等下解答。

第三种情况:
1)发送seq 92和 Seq 100
2)ack100丢失
3)在timeout 前Ack120收到,此时无需进行重传。
ps:这里又多了个疑点,为啥Ack100丢失不用重传Seq92?明明在情况一种需要重传啊。
这都在下一回合解答。
TCP协议详解(一)的更多相关文章
- TCP协议详解
TCP协议详解 一.TCP协议 1.TCP 通过以下方式提供可靠性: · ◆ 应用程序分割为TCP认为最合适发送的数据块.由TCP传递给IP的信息单位叫做报文段. · ◆ 当TCP发出一个报文段后 ...
- 第3章 TCP协议详解
第3章 TCP协议详解 3.1 TCP服务的特点 传输协议主要有两个:TCP协议和UDP协议,TCP协议相对于UDP协议的特点是 面向连接使用TCP协议通信的双方必须先建立连接,完成数据交换后,通信双 ...
- TCP协议详解7层和4层解析(美团,阿里) 尤其是三次握手,四次挥手 具体发送的报文和状态都要掌握
如果想了解HTTP的协议结构,原理,post,get的区别(阿里面试题目),请参考:HTTP协议 结构,get post 区别(阿里面试) 这里有个大白话的解说,可以参考:TCP/IP协议三次握手和四 ...
- TCP协议详解(理论篇)
TCP协议详解(理论篇) 2012-08-20 0个评论 作者:陈立龙 收藏 我要投稿 TCP协议详解(理论篇) 1. 与UDP不同的是,TCP提供了一种面向连接 ...
- linux高性能服务器编程 (三) --TCP协议详解
第三章 IP协议详解 TCP协议是TCP/IP协议族中的另外一个重要的协议,与IP协议相比,TCP协议更高进应用层.一些重要的socket选项都和TCP协议相关.这一章主要从如下方面学习: 1)TCP ...
- 网络通信协议八之(传输层)TCP协议详解
传输层协议 分段是为了提高传输效率,封装是指给每个数据段添加一个编号 端到端的传输是逻辑上的端到端,并不是真正意义上的发送方某层与接收方某层之间的传输 IP协议只是保证数据报文发送到目的地,为主机之间 ...
- 服务器编程入门(3)TCP协议详解
问题聚焦: 本节从如下四个方面讨论TCP协议: TCP头部信息:指定通信的源端端口号.目的端端口号.管理TCP连接,控制两个方向的数据流 TCP状态转移过程:TCP连接的任意一 ...
- TCP协议详解---上
TCP头格式 注意以下几点: TCP的包是没有IP地址的,那是IP层上的事.但是有源端口和目标端口. 一个TCP连接需要四个元组来表示是同一个连接(src_ip, src_port, dst_ip, ...
- Linux 高性能服务器编程——TCP协议详解
问题聚焦: 本节从如下四个方面讨论TCP协议: TCP头部信息:指定通信的源端端口号.目的端端口号.管理TCP连接,控制两个方向的数据流 TCP状态转移过程:TCP连接的任意一 ...
随机推荐
- 基于 Vue.js 的移动端组件库mint-ui实现无限滚动加载更多
通过多次爬坑,发现了这些监听滚动来加载更多的组件的共同点, 因为这些加载更多的方法是绑定在需要加载更多的内容的元素上的, 所以是进入页面则直接触发一次,当监听到滚动事件之后,继续加载更多, 所以对于无 ...
- Principle of Computing (Python)学习笔记(7) DFS Search + Tic Tac Toe use MiniMax Stratedy
1. Trees Tree is a recursive structure. 1.1 math nodes https://class.coursera.org/principlescomputin ...
- hdu4932 Miaomiao's Geometry (BestCoder Round #4 枚举)
题目链接:pid=4932" style="color:rgb(202,0,0); text-decoration:none">http://acm.hdu.edu ...
- xml解析(4)
本节要点: DOM解析方式 SAX解析方式 DOM4J对XML的解析 XML用于将数据组织起来,形成文档用于存储和传输: 更多时候我们需要的是将xml中的数据解析出来,甚至是在程序中动态生成xml. ...
- JSR系列开篇
JSR是Java Specification Requests的缩写,意思是Java 规范提案.是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求.任何人 ...
- gulp实现公共html代码复用
在开发网站的时候,尤其是类似于官网这样的项目,顶部都会有一个导航栏,底部会有一些其他信息,而这两个部分在每一个页面都是有的.我们不可能在每个html页面都写一遍,这样也不便后期维护等操作,所以可以把顶 ...
- 《Effective Java(中文第二版)》【PDF】下载
<Effective Java(中文第二版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382186 Java(中文第二版)& ...
- Python笔记·第十一章—— 函数 (二) 装饰器
一 为何要用装饰器 有的时候写完一段代码,过段时间需要对它进行升级.添加一些新功能,但是如果要直接修改原来的代码会影响其他人的调用,所以就需要一个不修改源代码且不修改原函数的调用方式的东西又能为原函数 ...
- list对象数组,xpath复杂定位校验,POST入参为number数组,POST入参为JSON对象数组
list对象数组: POST入参为number数组: { "typeIds":[1,2,3]} POST入参为JSON对象数组,举例: [{ "itemId& ...
- 【java设计模式】【创建模式Creational Pattern】单例模式Singleton Pattern
//饿汉式:资源利用率较低(无论是否需要都会创建),性能较高(使用前无需判断实例是否存在,可直接使用) public class EagerSingleton{ private static fina ...