热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TCPIP协议笔记

最近在读《图解TCPIP》,主要是想解决以下困惑:1.为什么TCP是面向连接的。2.为什么TCP是可靠的(数据包不会乱序,不丢包)3.为什么TCP适合传

最近在读《图解TCP/IP》,主要是想解决以下困惑: 1.为什么TCP是面向连接的。 2.为什么TCP是可靠的(数据包不会乱序,不丢包) 3.为什么TCP适合传输大量数据 4.为什么TCP传输速度比较慢

什么是TCP/IP协议

TCP协议是OSI(Open System Interconnect)中的第4层传输层,IP协议位于OSI中的第3层的网络层,传统的OSI中有7层,现行的tcp/ip协议族选用了5层架构,把会话层和表示层的功能整合在了应用层。从字面上看TCP/IP是指TCP和IP两种写一下,但是IP或ICMP(Internet Control Message Protocol)、TCP和UDP、FTP、HTTP都属于TCP/IP协议,所以才会说是tcp/ip协议族。 它是为了解决传输的稳定性,连续性,和安全性而产生的。

为什么TCP是面向连接的

其实端到端之间的连接是没有连接这一说的,TCP之所以说是面向连接的,是因为发送方和接收方各自维护了一组状态,以保证双方的状态能够同步,从而看上去是有连接的。TCP协议维护了以下状态

状态状态描述
CLOSED每个连接开始建立之前默认的状态
LISTEN一台设备(通常是服务器)等待接受来自客户端的SYN(Synchronize Sequence Numbers 同步序列号),这时候还没发送自己的SYN
SYN-SENT一台设备(通常是客户端)发送了SYN,并且等待匹配来自其他设备(通常是服务端)的SYN
SYN_RECEIVED两端设备都接收到SYN并发送了自己的SYN,现在就等待接受ACK(Acknowledgement Number)从而建立连接
ESTABLISHED一个TCP连接在两端都已准备就绪,两端能够自由的交换数据,直到这个连接被某一端主动关闭
CLOSE-WAIT设备收到来自另外一端的关闭连接请求FIN(Finish Number),这时候设备会接受这个请求并生成对应ACK
LAST-ACK当设备收到一个FIN并发送了对应的ACK,然后发送了自己的FIN并等待对方的ACK回复
FIN-WAIT-1处于这个状态下的设备等待自己发送FIN后对方的ACK应答,或者是等待接收另一端终止连接的请求
FIN-WAIT-2处于这个状态下的设备已经接收到自己发送出去的FIN对应的ACK,并等待另一端的FIN请求并发送自己的ACK
CLOSING设备收到了另一端的FIN并且发送了对应的ACK给了对方,但是还没收到他自己发送的FIN对应的ACK
TIME-WAIT双方设定都发送了FIN,并都接收到了对应的ACK,这时候连接已经完成了,但是连接不会立刻关闭,防止有新的连接复用

再放上状态改变图,对照表格更好的理解状态改变

TCP协议有这么多连接状态,也就意味着这个协议有多复杂。再加上网络环境的复杂性和不可预知性,因此要是想把TCP协议写完整不是一朝一夕的事情。

为什么TCP是可靠的(数据包不会乱序,不丢包)

在网络OSI(Open System Interconnection)中,TCP位于第4层,我们的网络数据会放在TCP的Segment(一段网络数据会划分成许多Segment)的body中,然后Segment会放到IP层的Packet中,再放到数据链接层的Frame中,传到另一端后,逐层解析各自的协议,然后交给上层处理。 一个TCP Segment的Header里有如下字段:

当完成TCP三次握手后,建立连接。当我们有一段数据需要传输时,TCP会将数据拆分成一个个Segment,每个Segmen会有一个序号。假设我们有40个Segment需要传输:

Seq代表了建立连接后的一个数字,不一定从1开始,双方都会确立一个ISN(Inital Sequence Number)确立一个初始化序列号,在一个连接周期内(RFC定义为4.55小时)会不断增加,确保不重复。发送数据端的Seq会随着数据包传输的长度进行累加。 TCP用以下机制来保证数据的完整性和顺序性: 超时重传机制:当发送端连续发送数据包而没有收到接收端的ack时,会动态计算一个timeout,当在发出数据后,在timeout内没有收到ack,会启动重传机制,以接收方最后一个ack序号,往后发送数据,若依旧没有在timeout内有ack回复会进入timeWait。这个机制重度依赖于timeout的计算算法。

快速重传机制:当接收方返回的ack序号连续保持一致时,可以认为数据包丢失,需要启动快速重传,以接收方最后一个ack序号,往后发送数据。

快速重传机制和超时重传机制有一个问题无法解决,那就是无法决定只重传ack所确定的那个包,还是往后的所有包。 比如有5个包,12已收到ack,发送345后没有收到ack,这时候是选择只重传3呢,还是重传345呢。这时候就需要SACK出马了。 **SACK(Selective Acknowledgment)**在TCP头部中会添加一个SACK字段用来表示接收到的字段区间。当接收端将ack和SACK发送给发送端后,发送端就知道哪些数据需要重传。

为什么TCP适合传输大量数据

因为大量数据会被tcp协议分成一个个segment,然后给每个segment编号,根据SequenceNumber发送数据,接收端根据SequenceNumber来拼接数据,保证数据的完整性。

为什么TCP传输速度比较慢

首先TCP作为传输层协议,不但要对端对端的连接负责,还要对整个网络的连接负责。因此既要保证单一连接的我稳定性,也要保证整个网络的稳定性,当网络情况出现波动时,TCP有能尽量的调整自己的发包速度,避免加重网络堵塞。 因此TCP头部利用Window字段和RTT(Round Trip Time,也就是一个数据包从发出去到收到ack的时间)以及RTO(Retransmission TimeOut)来动态改变传输的速度。 决定传输速度的是cwnd(Congestion Window),单位是MSS(Max Segment Size),以太网标准MSS是1460字节,最初慢启动的cwnd大小是3MSS。 Window : 也就是Sliding Window,滑动窗口,发送方根据接收方传过来的这个字段来决定发送多少数据。 慢启动 :当tcp开始传输后,每收到一个RTT,就会将cwnd * 2,很明显这是是一个指数增长的算法,直到达到threshhold,进入拥塞避免算法。因此我们下载东西,初期速度都会很小,网络条件好的情况下,几秒钟后就能达到最大速度。 拥塞避免 每收到一个ACK时,cwnd = cwnd + 1/cwnd,每过一个RTT时,cwnd = cwnd + 1,进入线性增长 拥塞发生 当RTT > RTO时,tcp认为网络条件差, threshhold = cwnd / 2, cwnd = 1,然后进入慢启动。 另外一种情况是两端都支持ECN的TCP连接中,假如在传输过程中出现拥塞,路由器会在传输的IP包的头部将ECN字段置为11,接收端收到这个ECN为11的包后,会将ACK包的ECE(Explict Congestion Notification Echo)字段置为11,发送端收到这个Ack后检查ECE,假如为11,也会进入慢启动和拥塞避免算法。

快速恢复 当收到多个重复Ack,cwnd = cwnd /2,sshthresh = cwnd,然后进入拥塞避免

参考文章

TCP 的那些事儿 关于TCP重连 图解TCP/IP The-TCP/IP-Guide TCPIP-Ref



推荐阅读
author-avatar
叶韵
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有