赞
踩
注:本文多处引用了图解TCP的图
目录
1.有连接
2.可靠传输
3.面向字节流
4.全双工
这个和UDP一样,是为了排版方便,容易给我们造成误解,其实真正的结构是这样的
源端口和目的端口分别表示源主机地址和目的主机地址
序号是为了给这段数据打上标记,从而让目的主机知道某个数据是否已经接收,同理确认序号是为了确认这段序号是正确的
头部长度
是为了描述TCP报头有多长,这里只有4字节,但是我们的选项位,可以给到头部长度里面
保留位
保留位是留给以后完善TCP的时候使用的
SAFURP
S:SYN是用来建立连接的
A:ACK是用来确认应答的
F:FIN是用来断开连接的
U:URG是紧急指针位
R:RST使用了重置连接的
P:PSH当两个应用程序进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应.就给数据标志上P
确认应答机制是保证TCP可靠传输的关键因素
发送方在发送一条数据之后,接收方会立即返回一个ACK表示已经收到数据,这就是确认应答
ACK包含的信息其实是向发送方索要下一条信息
当发送方在发送一条数据之后,并没有收到接收方的ACK信息,那么在等待一段时间之后,发送方会重新发送一条数据,这就叫超时重传,一般系统里面会有一个配置项,来描述超时的时间阈值,超时重传的时间不是一直不变的,当发送一条数据,无响应之后,下一次发送无响应,超时时间是更长的,当我们的重复的重传,一直得不到回应,那么就可能是断网了
这就是三次握手的模型图,当主机一想要和主机2建立连接时,发送syn,请求连接,主机2做出相应,发出ack,并且发送syn请求进行连接,主机1收到之后,发送给主机2ack表示收到请求连接数据,一套流程走完,三次握手也就完成了,连接也就建立成功了,建立连接的时候,TCP还会协商一些参数,这里就不详细介绍了
重要的TCP状态:
1.LISTEN:服务器启动,端口号绑定之后,表示可以与别人进行通信了
2.ESTABLISHED:表示连接已经建立好了,并且趋于稳定
这里为什么syn和ack可以一起传输,而fin和ack不可以呢?
因为在我们三次握手的过程中,主机2 的syn是接收到主机1syn后立即发送的,并且和ack一样,都是内核触发的,时机相同,所以可以一并发过去
而我们的四次挥手中,这个fin是在我们程序调用socket的close方法才开始发送的,而ack是收到主机1的fin之后立即发送的,所以两次发送的时间不相同,就没有合并传输
重要的TCP状态:
CLOSE_WAIT:等待代码中的close操作
TIME_WAIT:主动发起fin的一方,在等待断开连接时,会先进入这个状态,防止丢包
滑动窗口的出现时为了提高TCP传输效率的,我们没有引入滑动窗口之前,主机1的大量时间都浪费在了等待ack上面,这时候我们便想到了一个办法
一次传输多个数据,
这里我们会想到乱序问题和丢包问题,但是这些都不会影响的,我的ack的含义时前面4000个数据都收到了,现在我去索要第4001个数据,所以,假如我们1000~2000数据丢了,那我们ack就会返回1001,这样我们就会重新发送一次1000~2000,而且2000后面的数据并不需要发送,因为在上一次的传输中,已经发送过去了,这样就可以节省了等待ack的时间,这种不需要等待,可以直接发送的量,就叫做滑动窗口.
主机1收到一个ACK之后,就会继续发送一条数据,而不是等到所有的ACK都到了,才发下一组的
这里我们看一下出错的情况,我们TCP时如何处理的
情况1:ACK丢失
这里可以看到,我们的ACK即使丢了,也无妨,下一条ACK只要能到达,ACK就不需要重新传送,因为发送5001的意思是前5000个数据全部收到了
情况2:数据包丢失
这里可以看到,即使是数据包丢失了也无所谓,主机2会持续的返回1001,这样主机1就会重新发送一次1001
所以滑动窗口,是很好的一种提高TCP传输速率的方法
在滑动窗口的基础之上,主机2需要对主机1发送的流量做出限制,否则发送的数据太多了,主机2无法处理,那么主机2就会将一些数据包丢失
所以,在主机2使用接收缓冲区的剩余大小作为参考,来确定发送数据的多少
当剩余量多时,主机1就扩大滑动窗口的大小,剩余量少时,就缩小滑动窗口,那这个剩余量又如何让主机1 知道呢?
当我们主机2收到主机1 的数据之后,会在ACK报文中,把当前缓冲区的剩余空间大小返回给主机1,这样,主机1 就可以根据发送过来的数据,对滑动窗口做出相应的更改
其实我们不仅 要考虑主机2 的接收能力,还需要考虑主机1 传输数据到主机2 路径上的一些路由器的承受能力,中间节点的接收数量是无法量化的,所以我们把中间的这些转发节点作为一个整体,通过一步一步的试探,来测试出发多少是合适的,这样我们的数据会达到一个动态的平衡,这个其实就i是拥塞控制
拥塞控制就是从小的开始,一点一点试探,反复的动态平衡调整
TCP引入一个慢启动机制,先发少量数据,然后一点一点试探,如果不丢包,那就加大数据量
刚开始的时候,呈现指数增长,然后到达一定的阈值,开始线性增长
就如上图所示,当我们达到一个阈值的时候,就会调整阈值,回到最初的起点,重新进行调整,所以阈值是动态分配的
那么问题来了,如果同时有拥塞控制和流量控制,那我们该听谁的呢?
答案是:谁小听谁的
延迟应答也是TCP提高效率的一种机制,
如图,当我们主机1每发送两条数据,我们主机2 就做出一次回应,这就是延迟应答机制,当然,延迟应答也可以是延迟一定 的时间,延迟一定的时间作用是在我们主机1给主机2 发送数据的时候,主机2 并不第一时间回应,而是等待一会,等应用消费一些缓冲区的数据的时候,再进行应答,这时候,我们的滑动窗口大小,就会更大,传输速率也就会更快
在网络通信中,通常情况是一发一收,但是 由于延迟应答机制,ack等一会返回,这时候就可以把一些数据给捎过去,就比如
这张图中,本身ack和吃了不是同一个时期发送的,但是我们由于延迟应答机制,导致ack过一会传输,这样就可以把吃了,也给捎过去了
当TCP发送多条数据,数据都存储再缓冲区中,由于我们的数据是字节流的,所以我们的数据很有可能会粘到一起,无法区分出哪些是一条数据
粘包问题处理方法:
1.通过分隔符:比如指定一个分隔符作为包的结束标记,这样每一个包就区分开来了
2.通过指定报的长度:比如再报文开头位置声明长度,这样读数据的时候,只读取指定长度的数据,就不会发生粘包问题了
1.程序崩溃了
进程异常退出了,这时候操作系统会回收进程的资源,释放文件描述符表,相当于socket中的close操作,然后就会发生四次挥手
2.正常关机
和1一样,操作系统会回收进程资源,完成四次挥手操作
3.主机掉电
1.接收方掉电:
发送方持续发送数据,等待ack,多次重发之后未得到响应,就重新尝试连接,但是还是得不到响应.然后接收方就只能放弃连接了
2.发送方掉电:
这时候接收方就等待发送方发送数据,在等待一会之后,发送一个"心跳包",确认以下对方是否还在,这时候发送方无法返回一个心跳包,这时候说明发送方挂了,就会放弃连接
心跳包:是周期性触发的,是一个简单的,不携带业务数据的包,只是为了确认对方还在
4.网络断开
和3一样分析
附:
其实是考察TCP,我们只需要基于UDP在应用层,实现确认应答,超时重传,引入序列号等待操作就可以了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。