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

TCPdump抓包命令详解

原文地址:https://www.cnblogs.com/zaizhoumo/p/8888056.html

时间: 2024-11-09 17:25:57

TCP(一)的相关文章

TCP拥塞控制机制

我们知道TCP是拥有拥塞控制机制的,而UDP是没有的,为什么需要拥塞控制机制呢,就是防止丢包过多导致传输效率低下.网络中传输的包太多,路由器的缓存又不够,每一个发送端都以自己想要的发送速率发送包,自然会导致网络拥塞.所以我TCP就包括了拥塞控制机制. 有几种拥塞控制方法? 2种 1.端到端拥塞控制.网络层没有显示的告知传输层此时网络出现拥塞了,传输层通过报文段的丢失(超时或3次冗余确认得知)认为网络出现拥塞了,TCP会缩减其拥塞窗口,减小发送速率. 2.网络辅助的拥塞控制.网络层显示的告知发送端

winform学习日志(二十三)---------------socket(TCP)发送文件

一:由于在上一个随笔的基础之上拓展的所以直接上代码,客户端: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using Sys

TCP四次挥手(断开连接)(未完待续)

正常情况下,调用close(),其中产生的一个效果就是发送FIN. 断开为什么需要四次握手: TCP协议是一种面向连接的.可靠的.基于字节流的运输层通信协议.TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了:但是,这个时候主机1还是可以接受来自主机2的数据:当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的:当主机2也发送了FIN报文段时,这个时候就表示主

JAVA网络编程TCP通信

Socket简介: Socket称为"套接字",描述IP地址和端口.在Internet上的主机一般运行多个服务软件,同时提供几种服务,每种服务都打开一个Socket,并绑定在一个端口上,不同的端口对应于不同的服务.Socket和ServerSocket类位于java.net包中.ServerSocket用于服务端,Socket是建立网络连接时使用的.连接成功时,应用程序两端都会产生一个Socket实例,通过操作这个实例完成所需会话. Socket常用方法: -int getLocalP

《TCP/IP具体解释》读书笔记(22章)-TCP的坚持定时器

TCP通过让接收方指明希望从发送方接收的数据字节数(即窗体大小)来进行流量控制. 假设窗体大小为0会发生什么情况呢?这将有效阻止发送方传送数据,直到窗体变为非0为止. ACK的传输并不可靠,也就是说,TCP不正确ACK报文段进行确认,TCP仅仅确认那些包括有数据的ACK报文段. 1.坚持定时器 假设一个场景:假设一个确认丢失了,则两方就有可能由于等待对方而使连接终止,接收方等待接收数据(由于它已经向发送方通告了一个非0的窗体),而发送方在等待同意它继续发送数据的窗体更新.为防止这种死锁情况的发生

使用TCP时序图解释BBR拥塞控制算法的几个细节

周六,由于要赶一个月底的Deadline,因此选择了在家VPN加班,大半夜就爬起来跑用例,抓数据...自然也就没有时间写文章和外出耍了...不过利用周日的午夜时间(不要问我为什么可以连续24小时不睡觉,因为我觉得吃饭睡觉是负担),我决定把工作上的事情先放下,还是要把每周至少一文补上,这已经成了习惯.由于上周实在太忙乱,所以自然根本没有更多的时间去思考一些"与工作无关且深入"的东西,我指的与工作无关并非意味着与IT,与互联网无关,只是意味着不是目前我在做的.比如在两年前,VPN,PKI这

可以将TCP BBR算法模块化到低版本内核取代锐速吗

上周的文章引发了比较火爆的争论并带来了争议,我比较满意或者遗憾,尽管如此,如果有人真的能明白在文章的背后我真正想表达的意思,我也就深感欣慰了.还像往常一样,我花周末的时间来总结结束,写点技术散文,同时我希望能在技术上引发同样的争论.        在跟温州皮鞋厂老板聊天时,老板让我从非技术角度重新思考了Google的BBR算法.        很多测试似乎表明BBR的表现非常不错,虽不能保证包打天下,至少相比锐速而言,它是免费的啊,那么疑问也就随之而来了,既然BBR是免费的,且效果不错,那么那些

【Linux 网络编程】常用TCP/IP网络编程函数

(1)函数socket 1 /**************************************************************** 2 ** 功能:创建一个套接字用于通信 3 ** 参数:domain 指定通信协议族 4 ** type 指定socket类型,流式套接字 SOCK_STREAM 5 ** 数据报套接字 SOCKDGRAM 6 ** 原始套接字 SOCKRAW 7 ** protocol 协议类型 (习惯上填写0) 8 ** 返回值:成功返回非负整数,它

TCP/UDP网络连接的固定写法

java.net包中定义的两个类Socket(client) ServerSocket(server)建立连接时所需寻址信息为远程计算机的IP地址和端口号(自己指定端口号>1024,小于1024的可能被系统征用)TCP,UDP端口哥含65536个 TCP: Server端与Cilent端同时写,启动时必须先启动Server端 import java.net.*; public class TCPServer{ public static void main(String [] args) thr

tcp滑动窗口与拥塞控制

TCP协议作为一个可靠的面向流的传输协议,其可靠性和流量控制由滑动窗口协议保证,而拥塞控制则由控制窗口结合一系列的控制算法实现.一.滑动窗口协议     所谓滑动窗口协议,自己理解有两点:1. "窗口"对应的是一段可以被发送者发送的字节序列,其连续的范围称之为"窗口":2. "滑动"则是指这段"允许发送的范围"是可以随着发送的过程而变化的,方式就是按顺序"滑动".在引入一个例子来说这个协议之前,我觉得很有必