版权声明:本文为做者原创文章,能够随意转载,但必须在明确位置代表出处!!!windows
以前有一篇文章介绍了http协议「初识http协议」, http协议协议是基于tcp协议的,因此做者以为有必要针对tcp协议作一个介绍,但愿各位读者可以静下心来认真阅读,也能够本身去看看TCP/IP协议详解这本书,必定要让本身成为那20%的人。服务器
TCP(Transmission Control Protocol 传输控制协议)是一种面向链接的、可靠的、基于字节流的传输层通讯协议,对TCP协议的文章网上已经很成熟了,今天我只是想总结一下知识,加深印象,所谓好记心不如烂笔头麻。网络
TCP/IP分层结构
TCP/IP协议栈主要分为4层:应用层,传输层,网络层,数据链路层tcp
-
应用层工具
应用层负责处理特定的应用程序细节,像远程登录,FTP传输,SMTP邮件传输,SNMP简单网络管理。大数据
-
传输层3d
运输层主要提供两台主机之间端到端的通讯,在TCP/IP协议族中,TCP和UPD是两种大相径庭的传输协议,TCP(传输控制协议)为主机之间提供可靠传输,它把从应用层获得的数据分红适当的数据包交给下面的(IP)网络层,肯定接收到的分组,设置发送最后确认分组的超时时钟等,因运输层提供了高可靠性的端到端的通讯,应用层就不须要再去关注这些细节,而UDP(用户数据协议)提供的是不可能性的传输,它只负责从一台主机发送到另外一台主机,并不保证此数据必定到达另外一端主机,任何须需的可靠性必须由应用层来提供。指针
-
网络层blog
网络层主要处理分组在网络中的活动,网络层协议包涵IP,ICMP,IGMP协议。接口
-
链路层
链路层组要包涵网卡驱动程序,它处理和电缆或者其它传输介质的物理接口细节。链路层的主要目的有三个
-
为IP模块接收和发送IP数据报
-
为ARP模块发送ARP请求和接收ARP应答
-
为RARP模块接收RARP应答和发送RARP请求
所谓的协议就是通讯双方都须要遵照的规则,这样才能明白对方要表达什么,就像两我的打电话同样,A说的是重庆话,B说的是广东话,这两人打电话确定不知道对方说的是什么,这就叫他们没有遵照协议,如果都让他们说普通话这样俩儿人就都能听懂对方说的是什么意识了,普通话这里就至关于协议你们都要遵照。下面我将结合Wireshark抓包工具来分析TCP/IP协议
封装
数据进入协议栈的封装过程
当通过以太网层的封装后,就要经过网线或者其它传输介质把此封装好的数据报文发送到另外一端去,另外一段收到数据报后最早接触的是以太网层也就是咱们的数据链路层协议,该层协议复制把以太网首部解析掉,让后把解析后的数据报上送到IP层,IP层把IP首部解析掉,而后上传到TCP层,依次类推每层协议解析其首部并判断其首部中的协议标识以肯定接收数据的上层协议,而后上送到他的上一层。这就是封层结构的好处之一,每层协议只作本身的事,不是本身的事就交给别人去作。
TCP报文格式
Wireshark的抓包结果
原端口/目的端口(16bit):
咱们都知道网络以前的通讯是不通主机之间的通讯,就windows系统而言经过查看任务管理器咱们能够知道一台主机有许多进程,当咱们发送数据时怎么知道要发送到对方主机那个进程里呢,因此这就是端口号的做用,在TCP报文中包涵了源端口/目的端口,源端口标识了发送进程,目的端口标识了接收方进程。在此报文中咱们的源端口号是0x8572 = 34162, 目的端口是0x01bb = 443以下图所示
序列号(32bit)
Sequence Number这个是发送序列号,用来标识从源端向目的端发送的数据字节流,它表示在这个报文端中的第一个数据字节的顺序号,系列好是32位的无符号类型,序号表达达到2^32 - 1后又从0开始, 当创建一个新的链接时,SYN标志为1,系列号将由主机随机选择一个顺序号ISN(Initial Sequence Number)。此报文中的序列号是0x9e546d6b早已超过了2^32 - 1 因此这里的序列号为0,以下图
确认号(32bit)
Acknowledgment Number它包涵了发送确认一端所指望收到的下一个顺序号。所以确认序列号应当是上次成功接收到数据的顺序号加1。只有ACK标志为1时确认序号字段才有效。TCP为应用层提供全双工服务,这意味着数据能在两个方向上独立的进行传输,所以链接的两断必需要保证每一个方向上的传输数据顺序。
偏移(4bit)
这里的偏移实际指的是TCP首部的长度,它用来代表TCP首部中32bit字的数目,经过它能够知道一个TCP包它的用户数据从哪里开始,这个字段占4bit,若此字段的值为1000,则说明TCP首部的长度是8 * 4 = 32字节,因此TCP首部的最大长度是该字段的值为1111 = 15, 15 * 4 =60字节。此报文咱们的偏移量在0x80中,又因它占4bit,0x80等于二进制的1000 0000 因此咱们的偏移量是 1000 = 8,因此咱们的TCP报文头为8 * 4 = 32字节。
Reserved(6bit)
目前没有使用,它的值都为0
标志(6bit)
在TCP首部中有6个标志比特,他们中的多个可同时被置为1
-
URG(Urgent Pointer Field Significant):紧急指针标志,用来保证TCP链接不被中断,而且督促中间设备尽快处理这些数据
-
ACK(Acknowledgement Field Signigicant):确认号字段,该字段为1时表示应答字段有效,即TCP应答号将包含在TCP报文中。
-
PSH(Push Function): 推送功能,所谓推送功能指的是接收端在接收到数据后当即推送给应用程序,而不是在缓冲区中排队。
-
RST(Reset the connection): 重置链接,不过一搬表示断开一个链接,以下图,主机192.168.3.27 访问主机211.150.84.8;但主机84.8并无监听对于端口,这时它会向主机3.27发送一个RST位置的TCP包断开链接。
-
SYN(Synchronize sequence numbers):同步序列号,用来发起一个链接请求
-
FIN(No more data from sender):表示发送端发送任务已经完成(既断开链接)
窗口大小(16bit)
表示源主机最大能接收多少字节。
校验和(16bit)
包含TCP首部和TCP数据段,这是一个强制性的字段,必定是由发送端计算和存储,由接收端进行验证
紧急指针(16bit)
只有当URG标志置为1时该字段才有效,紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另外一段发送紧急数据的一种方式。
TCP选项
至少1个字节的可变长字段,标识哪一个选项有效。Kind=0:选项表结束, Kind=1:无操做, Kind=2:最大报文段长度,Kind=3:窗口扩大因子, Kind=8:时间戳。
TCP的三次握手和四次挥手
整个过程以下图所示
TCP的三次握手
TCP的三次握手过程以下图所示,咱们经过数据包来分析一下握手过程是否是和图中所画一致。
第一次握手
主机192.168.3.27向主机111.13.100.91发起链接请求,能够看在这时的SYN被置为1了,序列号Seq = 0,以下图
第二次握手
主机111.13.100.91应答主机192.168.3.27,能够看到这个时候的应答包含了SYN,ACK,ACK = Seq + 1 = 1, 这里的Seq是第一次握手发起请求的Seq值,并非下图报文中红框表示的Seq值。
第三次握手
主机192.168.3.27应答主机111.13.100.91,能够看到这个时候的应答包是ACK, ACK = Seq + 1 = 1,这里的Seq是第二次握手主机111.13.100.91产生的序列值
在回头看看咱们的svr4.1037主机和bsdi.discard以前的链接创建是否是和咱们的报文分析的一致,第一次握手 SYN Seq = 1415531521; 第二次握手 SYN ack = 1415531521 + 1 = 1415531522 Seq = 1823083521;第三次握手 ack = 1823083521 + 1 = 1823083522;到这里就能够看出此过程和咱们的报文分析是一致的。
能够看到三次握手后肯定了双方包的序列号,最大接收数据的大小以及MSS(Maximum Segment Size)最大分片大小 MSS = MTU - IP头部长度 - TCP头部长度,MTU最大传输单元一班为1500字节,若TCP/IP报文都不带选项时MSS = 1500 - 20 - 20 = 1460,MSS的意思是最大分片大小,这里如果1460的话,那么如果应用程序发送大于1460个字节那么超过1460个字节数会分片为下一个包,下图是应用层发送4096个字节。
因为数据大小是4096个字节,因此用了三次进行传递(1448 + 1448 + 1200)。细心的人会问为何每次传送的最大数据大小不是1460个字节呢?由于这里的TCP携带可选项,TCP头长度 = 20 + 12(可选选项大小) = 32字节。 这样能传输的最大数据为:1500 - 20 - 32 = 1448个字节。
TCP四次挥手
第一次挥手
将设客户端首先发起断开链接,那么客户端回想服务端发送FIN置为1的TCP包,请求断开链接,意思就是我要断开和你的链接了,可是若是你还有数据没有发送完给我你没必要当即关闭链接。
第二次挥手
服务端收到客户端的断开链接请求当即响应一个ACK报文,意思是告诉客户端你发起的断开链接请求我已经收到了,可是我尚未准备好,你在等一会,这个时候服务器端可能还有数据要发送给客户端,也可能正在准备释放资源。这个时候客户端进入FIN_WAIT状态,继续等待服务端的FIN报文。
第三次挥手
服务端确认已经发往客户端的数据已经发送完成,则向客户端发送FIN报文,告诉客户端我已准备好关闭链接了。
第四次挥手
客户端收到服务端的FIN报文后就知道能够关闭链接了,当时它仍是不肯定,怕服务端仍是不知道我要关闭链接了,因此发送一个ACK包后进入TIME_WAIT状态,若是服务端没有收到ACK那么服务端则能够发起重传,若是收到了ACK报文,客户端等待2MSL后已然没有收到回复,则证实服务端已经正常关闭了,那我也就能够关闭链接了。