TCP(一)
TCP的特点:三次握手、四次挥手、可靠连接、丢包重传。所有的关键词都围绕着可靠传输。
实现可靠传输的核心机制:seq+ack。通过ack判断是否有丢包,是否需要重传。
三次握手
1)初始状态:client为CLOSED,server为LISTEN,此时client 发送 syn 到server ,client状态变为SYN_SENT;
2)server 收到 syn后回复syn+ack给client,client状态变为SYN_RCVD;
3)client 收到syn+ack后,回复ack向server表示收到了server的syn+ack(此时client连接状态已经是established),当Server收到ack后,状态变成established。
为什么要握手?
1)最重要的目的:告诉对方自己的seq,对方回复ack(收到的seq+包的大小),用于判断是否有丢包;
2)其他目的:协商信息,例如:MSS–最大传输包、SACK_PERM–是否支持Selective ack(用户优化重传效率)等。
四次挥手
1)client发送fin包给server,client连接状态变为FIN-WAIT-1;
2)server收到fin包后回复ack给client,表示server知道client要断开了,server连接状态变为CLOSE-WAIT;client收到ack后连接状态变为FIN-WAIT-2;
3)server发送fin包给client,表示server也可以断开了,server连接状态变为LAST-ACK;
4)client收到fin包后回复ack给server,此时client端连接状态先变为TIME-WAIT,等待一段时间后变为CLOSED状态;server收到ack后状态变为CLOSED。
为什么三次握手、四次挥手?
之所以绝大数时候我们看到的都是四次挥手,是因为收到fin后,知道对方要关闭了,然后OS通知应用层要关闭啥的,这里应用层可能需要做些准备工作,有一些延时,所以先回ack,准备好了再发fin 。 握手过程没有这个准备过程所以可以立即发送syn+ack。
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答用,而SYN起同步作用)在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可关闭,这里的ACK报文和FIN报文多数情况下都是分开发送的.
为什么是三次握手,而不是两次?
因为tcp是可靠传输协议,靠seq+ack实现,因此建立一个可靠的单向通道至少需要一次seq+ack;又因为tcp是双向通信协议,所以服务端也需要进行一次seq+ack;为了优化通信效率,服务端发送ack和seq消息合并,所以需要3次握手。
为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比STABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
怎么确定是否丢包?
ack总是等于seq+len,len为包的大小,(SYN、FIN、ACK包除外,len为0),发送方通过ack知晓接收方是否收到消息。ack表示这个数字前面的数据都收到了。
MSS
MTU(maximum transmission unit,最大传输单元),由硬件规定,如以太网的MTU为1500字节。
MSS(maximum segment size,最大分段大小),为TCP数据包每次传输的最大数据分段大小,一般由发送端向对端TCP通知对端在每个分节中能发送的最大TCP数据。MSS值为MTU值减去IPv4 Header(20 Byte)和TCP header(20 Byte)得到。
SACK_PERM
SACK_PERM 用于丢包的话提升重传效率,比如client一次发了1、2、3、4、5 这5个包给server,实际server收到了 1、3、4、5这四个包,中间2丢掉了。这个时候server回复ack的时候,都只能回复2,表示2前面所有的包都收到了,给我发第二个包吧,如果server 收到3、4、5还是没有收到2的话,也是回复ack 2而不是回复ack 3、4、5、6的,表示快点发2过来。
但是这个时候client虽然知道2丢了,然后会重发2,但是不知道3、4、5有没有丢啊,实际3、4、5 server都收到了,如果支持sack,那么可以ack 2的时候同时告诉client 3、4、5都收到了,这样client重传的时候只重传2就可以,如果没有sack的话那么可能会重传2、3、4、5,这样效率就低了。
抓包实例验证
flags 标志由S(SYN), F(FIN), P(PUSH), R(RST), 在10.18.222.22上抓包 tcpdump -i eth0 -nn -S -vv host 10.18.222.22 and 10.18.101.91 and port 9188 and tcp ==1==客户端10.18.101.91向服务端10.18.222.22发送一个SYN消息,seq为3105852613。
08:02:13.454857 IP (tos 0x0, ttl 126, id 14184, offset 0, flags [DF], proto TCP (6), length 52)
10.18.101.91.63376 > 10.18.222.22.9188: Flags [S], cksum 0x9640 (correct), seq 3105852613, win 8192, options [mss 1428,nop,wscale 8,nop,nop,sackOK], length 0
==2==服务端向客户端发送确认消息,其中ack为上一行seq+1,ack 3105852614;同时向客户端发送SYN消息,seq 536849585。
08:02:13.454955 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52)
10.18.222.22.9188 > 10.18.101.91.63376: Flags [S.], cksum 0x57bc (incorrect -> 0xb057), seq 536849585, ack 3105852614, win 14600, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
==3==客户端向服务端发送确认消息,ack为上一行seq+1,ack 536849586。到此三次握手结束,连接建立。
08:02:13.455633 IP (tos 0x0, ttl 126, id 14185, offset 0, flags [DF], proto TCP (6), length 40)
10.18.101.91.63376 > 10.18.222.22.9188: Flags [.], cksum 0x2932 (correct), seq 3105852614, ack 536849586, win 256, length 0 ==4==客户端向服务端发送数据,长度为161字节,请求序号seq 3105852614:3105852735
08:02:13.488717 IP (tos 0x0, ttl 126, id 14191, offset 0, flags [DF], proto TCP (6), length 161)
10.18.101.91.63376 > 10.18.222.22.9188: Flags [P.], cksum 0x836f (correct), seq 3105852614:3105852735, ack 536849586, win 256, length 121
==5==服务端收到数据后向客户端发送确认ack 3105852735
08:02:13.488816 IP (tos 0x0, ttl 64, id 44515, offset 0, flags [DF], proto TCP (6), length 40)
10.18.222.22.9188 > 10.18.101.91.63376: Flags [.], cksum 0x57b0 (incorrect -> 0x2946), seq 536849586, ack 3105852735, win 115, length 0
==6==服务端向客户端发送数据
08:02:19.534769 IP (tos 0x0, ttl 64, id 44516, offset 0, flags [DF], proto TCP (6), length 130)
10.18.222.22.9188 > 10.18.101.91.63376: Flags [P.], cksum 0x580a (incorrect -> 0xd5db), seq 536849586:536849676, ack 3105852735, win 115, length 90 ==7==客户端向服务端发FIN消息
08:02:19.660406 IP (tos 0x0, ttl 126, id 14360, offset 0, flags [DF], proto TCP (6), length 40)
10.18.101.91.63376 > 10.18.222.22.9188: Flags [F.], cksum 0x285e (correct), seq 3105852735, ack 536849676, win 256, length 0
==8==服务端向客户端发送确认,同时发送FIN消息
08:02:19.661757 IP (tos 0x0, ttl 64, id 44517, offset 0, flags [DF], proto TCP (6), length 40)
10.18.222.22.9188 > 10.18.101.91.63376: Flags [F.], cksum 0x57b0 (incorrect -> 0x28ea), seq 536849676, ack 3105852736, win 115, length 0
==9==客户端向服务端发送确认。
08:02:19.662960 IP (tos 0x0, ttl 126, id 14362, offset 0, flags [DF], proto TCP (6), length 40)
10.18.101.91.63376 > 10.18.222.22.9188: Flags [.], cksum 0x285d (correct), seq 3105852736, ack 536849677, win 256, length 0 1、2、3是TCP三次握手的过程
7、8、9是TCP四次挥手的过程 疑问:为什么TCP四次挥手只抓到3个包?
TCP总是尽可能的捎带需要回复给对方的数据
tcp连接状态转换图
附录:抓包工具----tcpdump
安装:yum install -y tcpdump
查看帮助:tcpdump --help
-i 指定监听的网络接口(网卡)。
-w 直接将分组写入文件中。
-vv 输出详细的报文信息。
-X,可以列出十六进制 (hex) 以及 ASCII 的数据包内容,对于监听数据包内容很有用。
-A,数据包的内容以 ASCII 显示,通常用来捉取 WWW 的网页数据包资料。
-nn 不进行端口名称的转换。
-D 打印出系统中所有可以用tcpdump截包的网络接口。
常用命令
1)我截取本机(192.168.31.147)和主机114.114.114.114之间的数据
tcpdump -n -i eth0 host 192.168.31.147 and 114.114.114.114
2)截取全部进入服务器的数据
tcpdump -n -i eth0 dst 192.168.31.147
服务器有多个IP 可以使用参数
tcpdump -n -i eth0 dst 192.168.31.147 or 192.168.31.157
3)抓取全部进入服务器的TCP数据包
tcpdump -n -i eth0 dst 192.168.31.147 and tcp
4)从本机出去的数据包
tcpdump -n -i eth0 src 192.168.31.147 or 192.168.31.157
5)从本机出去的数据包且端口不为22的tcp数据包
tcpdump -n -i eth0 src 192.168.31.147 or 192.168.31.157 and port ! 22 and tcp
参考资料:
TCP(一)的更多相关文章
- Tcp/ip 报文解析
在编写网络程序时,常使用TCP协议.那么一个tcp包到底由哪些东西构成的呢?其实一个TCP包,首先需要通过IP协议承载,而IP报文,又需要通过以太网传送.下面我们来看看几种协议头的构成 一 .Ethe ...
- C#高性能TCP服务的多种实现方式
哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...
- Android实现TCP断点上传,后台C#服务实现接收
终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证, ...
- 漫谈TCP
不得不承认,tcp是一个非常复杂的协议.它包含了RFC793及之后的一些协议.能把tcp的所有方面面面具到地说清楚,本身就是个很复杂的事情.如果再讲得枯燥,那么就会更让人昏昏欲睡了.本文希望能尽量用稍 ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- TCP/IP基础
TCP/IP 是用于因特网 (Internet) 的通信协议. 计算机通信协议是对那些计算机必须遵守以便彼此通信的规则的描述. 什么是 TCP/IP? TCP/IP 是供已连接因特网的计算机进行通信的 ...
- TCP/IP之TCP_NODELAY与TCP_CORK
TCP/IP之Nagle算法与40ms延迟提到了Nagle 算法.这样虽然提高了网络吞吐量,但是实时性却降低了,在一些交互性很强的应用程序来说是不允许的,使用TCP_NODELAY选项可以禁止Nagl ...
- TCP/IP之Nagle算法与40ms延迟
Nagle算法是针对网络上存在的微小分组可能会在广域网上造成拥塞而设计的.该算法要求一个TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组确认到达之前不能发送其他的小分组.同时,TCP收集这 ...
- TCP的数据传输小结
TCP的交互数据流 交互式输入 通常每一个交互按键都会产生一个数据分组,也就是说,每次从客户传到服务器的是一个字节的按键(而不是每次一行) 经受时延的确认 通常TCP在接受到数据时并不立即发送ACK: ...
- TCP服务和首部知识点小结
服务 应用程序会被TCP分割成数据段,而UDP不分割. TCP有超时重传和确认 如果检验和出错将丢弃 IP数据包可能会失序或者重复,所以TCP会处理 滑动窗口来进行流量控制 对字节流的内容不做任何解释 ...
随机推荐
- Python连接符的种类和使用区别
python的连接符主要有 加号(+).逗号(,).空格( ) .反斜线(\).join()的方式. 加号(+),demo如下: #注意,+只能连接字符串,如果一个是字符串一个是数字就会报错 pr ...
- ABP框架插件开发
http://personball.com/abp/2017/08/21/abp-how-to-use-plugin
- 每天一个Linux命令(13):apt命令
apt-get和apt-cache命令是Debian Linux发行版中的APT软件包管理工具.所有基于Debian的发行都使用这个包管理系统.deb包可以把一个应用的文件包在一起,大体就如同Wind ...
- 12.0 Excel表格读取
Pycharm安装 xlrd 首先在xuexi目录下创建一个ExcelFile文件,让后在ExcelFile下创建一个Excel表格 创建表格时记得把单元格的格式设置为[文本] 我们设置为文本之后,存 ...
- coia阻止事件上浮
1.阻止事件上浮 选择默认地址li 时 选中整个div使其为默认地址 此时点击编辑按钮也会触发选中默认事件 为事件添加event.stopPropagation();阻止事件上浮 2.js给页面inp ...
- CVPR2018: Generative Image Inpainting with Contextual Attention 论文翻译、解读
注:博主是大四学生,翻译水平可能比不上研究人员的水平,博主会尽自己的力量为大家翻译这篇论文.翻译结果仅供参考,提供思路,翻译不足的地方博主会标注出来,请大家参照原文,请大家多多关照. 转载请务必注明出 ...
- Python标准模块logging
http://blog.csdn.net/fxjtoday/article/details/6307285 开发Python, 一直以来都是使用自己编写的logging模块. 比较土...... 今天 ...
- MQTT在平台中的应用【本文摘自智车芯官网】
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台,几乎可以把所有联 ...
- Android Studio 添加模块依赖
原文地址: http://fanjiajia.cn/2018/09/27/Android%20Studio%20%E6%B7%BB%E5%8A%A0%E6%A8%A1%E5%9D%97%E4%BE%9 ...
- epc笔记
http://wenku.baidu.com/view/5e921520dd36a32d7375812a.html 1. 先注册, EPC注册EPS业务或non-EPS服务 ?? HSS做什么? 2 ...