源端口号:数据发起者的端口号,16bit
目的端口号:数据接收者的端口号,16bit
序号:32bit的序列号,由发送方使用
确认序号:32bit的确认号,是接收数据方期望收到发送方的下一个报文段的序号,因此确认序号应当是上次已成功收到数据字节序号加1。
首部长度:首部中32bit字的数目,可表示15*32bit=60字节的首部。一般首部长度为20字节。
保留:6bit, 均为0
紧急URG:当URG=1时,表示报文段中有紧急数据,应尽快传送。
确认比特ACK:ACK = 1时代表这是一个确认的TCP包,取值0则不是确认包。
推送比特PSH:当发送端PSH=1时,接收端尽快的交付给应用进程。
复位比特(RST):当RST=1时,表明TCP连接中出现严重差错,必须释放连接,再重新建立连接。
同步比特SYN:在建立连接是用来同步序号。SYN=1, ACK=0表示一个连接请求报文段。SYN=1,ACK=1表示同意建立连接。
终止比特FIN:FIN=1时,表明此报文段的发送端的数据已经发送完毕,并要求释放传输连接。
窗口:用来控制对方发送的数据量,通知发放已确定的发送窗口上限。
检验和:该字段检验的范围包括首部和数据这两部分。由发端计算和存储,并由收端进行验证。
紧急指针:紧急指针在URG=1时才有效,它指出本报文段中的紧急数据的字节数。
选项:长度可变,最长可达40字节
简单理解就是,接收方需要对发送方进行回复确认,这是保证可靠传输的基础。
为了保证报文的有序性,那就必须对自己的报文按顺序进行编号,这样不但可以记录自己发送到了哪个包,接收方也可以根据序号对报文进行排序串接。
相对于UDP的不可靠,TCP是可靠的,要做到整个过程的可靠性,那么就需要对每个传输报文都进行发送确认,包括连接建立、数据交互、连接断开中,都可以拆分成无数个最基本的发送确认过程。
TCP对有序性机制的利用,因为发送确认机制的存在,可以知道对方收到了第几个包,这就顺便可以知道哪些包是否需要重传。
报文的初始序号是一个跟随时间而改变随机值,原因如下:
如果TCP在建立连接时每次都选择相同的、固定的初始序号,那么设想以下的情况:
(1)假定主机A和B频繁地建立连接,传送一些TCP报文段后,再释放连接,然后又不断地建立新的连接、传送报文段和释放连接。
(2)假定每一次建立连接时,主机A都选择相同的、固定的初始序号,例如,选择1。
(3)假定主机A发送出的某些TCP报文段在网络中会滞留较长的时间,以致造成主机A超时重传这些TCP报文段。
(4)假定有一些在网络中滞留时间较长的TCP报文段最后终于到达了主机B,但这时传送该报文段的那个连接早已释放了.而在到达主机B时的TCP连接是一条新的TCP连接。
这样,工作在新的TCP连接下的主机B就有可能会接受在旧的连接传送的、已经没有意义的、过时的TCP报文段(因为这个TCP报文段的序号有可能正好处在现在新的连接所使用的序号范围之中)。结果产生错误。
因此,必须使得迟到的TCP报文段的序号不处在新的连接中所使用的序号范围之中。
这样,TCP在建立新的连接时所选择的初始序号一定要和前面的一些连接所使用过的序号不一样。因此,不同的TCP连接不能使用相同的初始序号。
因为报文的初始序号是随机的,那就必须想办法让对方知道自己的序号是多少,TCP通信是依靠在双方建立连接的过程中交互了报文初始序号。
请求连接报文:打开了同步标志位SYN=1的报文
回复确认报文:打开了确认标志ACK=1的报文
终止连接报文:打开了终止标志FIN=1的报文
数据传送报文:打开了数据推送标志位PST=1的报文
注意:SYN、FIN、PST控制具体序号seq是同一个,而ACK控制的序号是ack。因为请求连接占用的序号位置是seq,回复确认占用的序号是ack,所以在三次握手的时候,服务端可以同时打开这两个标志位开关。
只有收到了对方发来的标志位ACK=1的报文,并从收到的报文中提取ack值作为自己下次发送的seq,此时:自己seq = 对方ack;
下面的描述是当认为所有报文都一次性成功的情况下进行,不涉及重传机制。
是因为服务端回复给客户端告知自己的初始序号后,得不到客户端的确认;
是因为第二次握手的时候,服务端回复确认客户端的同时,顺便告知了客户端,服务端自己的初始序号,这样就可以优化成三次握手。
发送包:打开同步标志位SYN=1,自己的报文序号是seq=x,然后进入syn_sent状态;
1)先收包:服务端收到报文后知道了客户端的报文初始序号是x。因为收到SYN=1报文,根据递增规则,自身的ack=x+1,然后开始回复客户端:打开确认标志位ACK=1,
2) 回复包:我下次想要收到你的包的序号是ack=x+1;同时为了告知客户端知道自己的初始序号,该报文同时打开同步标志位SYN=1,服务端的初始序号seq=y,然后进入syn_rcvd状态;
1)先收包:收到服务端的报文,知道服务端的报文初始序号是y。
因为服务端报文是【SYN=1,seq=y】报文,所以自身的ack=y+1。
因为服务端的报文是【ACK=1,ack=x+1】,所以自身的seq=x+1。
2)回复包:回复给服务端ACK报文并把状态变成established,服务端收到该ACK后也变成established,此时的服务端因为收到客户端发来的【ACK=1,ack=y+1】,服务端的seq=y+1;
第1个二次握手:客户端没有数据要发送了,通知服务端要断开连接,然后服务端回复确认收到了;
第2个二次握手:服务端也没有数据要发送了,通知客户端要关闭连接,客户端回复服务端确认收到了。
因为当客户端要求服务端关闭后,服务端仍有数据发送,那么客户端肯定就要继续接收数据,如果使用二次握手,服务端发送完数据然后回复了客户端确认收到了报文然后就直接关闭了连接,这样的情况下,并不知道客户端是否接收完数据就把流给断了。同时,客户端在等服务端回复的时间可能过长。
因为客户端通知服务端要关闭,服务端有可能还未发送完数据,如果使用三次握手来关闭,此时服务端要一直等发送完毕所有数据,才能回复客户端收到了报文可以关闭连接了,可能会导致客户端等待时间过长。
客户端没有数据要发送了,通知服务端要关闭连接,【终结标志位FIN=1,序号seq=u】,客户端进入FIN_WAIT1状态。
注意:此时的序号seq是根据前面客户端发了几个数据包决定的,这里当且认为是u。
1)先收包:根据递增规则,服务端的ack=u+1
2)回复包:打开确认标志ACK=1,自身的seq=v;服务端进入CLOSE_WAIT状态,客户端进入FIN_WAIT2状态。
注意:此时的服务端序号seq是根据服务端在之前发了几个数据包决定的,这里当且认为当且的seq是v。
服务端也没有数据要发送了,通知客户端要关闭连接。
因为在第二次握手后,可能继续发了N个包给客户端,所以此时的服务端seq变成了w。
因为在第二次握手后,没有再收到客户端的包了,可以知道此时服务端的ack仍然是ack=u+1;
服务端进入LAST_ACK状态。
先收包:因为服务端的【ACK=1,ack=u+1】所以此时的客户端的seq=u+1;因为服务端的【FIN=1,seq=w】所以客户端的ack=w+1;
回复包:此时客户端方进入TIME_WAIT状态,经过2MSL时间后关闭连接;服务端收到ACK包后立即关闭。