【socket】socket介绍-TCP协议

 TCP/IP协议是网络七层协议中最重要的两个协议,一个负责传输层的数据传输,一个负责网络层的数据传输。它的重要程度之高导致有时候七层协议直接称为TCP/IP协议。所以对TCP/IP协议的了解将决定了在服务器端开发、调试中是否能快速定位到问题,程序优化方向是否正确。在这篇文章中主要是针对TCP的协议格式与链接、断开过程进行简单分析。

  1:基础介绍

  TCP(Transimission Control Protocol)负责传输层的数据传输,并保证数据的完整性与有序性,是面向链接、字节流传输(UDP面向无连接、数据包传输)。它是在协议栈的第四层传输层使用到的协议,通过IP协议传输。因为在IP网络层是点对点,随机选择路由进行跳转转发的,没有办法保证任何一个IP数据包都可以正常准时到达对端。因此在IP层是无法保证数据的完整性,只能依靠更高层的协议保证。TCP是如何保证数据的有序与完整性的那,那需要对TCP协议进行介绍。

首先对TCP的头部进行一个简单的介绍说明。

 1.1:TCP头部简介

【socket】socket介绍-TCP协议_第1张图片

  通过上图可以看到,一般情况下,TCP的头部是20个字节,最后一个四个字节记录检验和与紧急指针。那么TCP的头部是如何解决了数据的有序性与完整性的那?在回答问题之前还要对有序性再多说一句。这里的有序性并不是指的一端发送数据,另一端是有序接收到。不是指发送端先发包A,又发送了包B,而接收端就一定是先接收到A,再接受到B。这里的有序性可以理解成数据最终有序性。因为网络的问题,无论什么协议都不可能保证数据有序接收。因为TCP数据流会以往网络层的IP包来传输,而IP是随机选择路由的(其实也不是随机),不可能保证先后发送的IP报可以先后被对端接收到。虽然TCP接受端不能有序接受到数据,但是它可以有其他机制来保证数据最终有序。下面就对头部简单介绍来分析它是如何保证有序和完整性的。

 1.2:TCP序号和确认号字段

  从上图可以看到TCP头部有各种字段,网络上都可以看到各个的含义,所以在此我们不对每个字段进行说明。上面我们提到两个问题是TCP如何保证最终有序和数据完整的那,这里我们就分析和这两个问题有关的头部。
  从上图的第二个字和第三个字的位置,分别是序号和确认号。这两个字段的主要作用就是用来保证数据的最终有序性和完整性。我们知道TCP报文传输载体是网络层的IP数据包,其实底层还是走的数据链路层和物理层。在底层的协议栈中,也是以数据包的概念来传输数据。底层协议栈拿到一大块数据并不是直接发送对端,而是要进行分包,每个包不能超过固定大小(MTU)。因此IP发送每个数据包大小要受到底层协议的限制,相应的TCP数据也不能超过一个IP包最大数据量。当一个TCP报文超过了IP数据包的长度就要进行分包。每个TCP报文的大小其实不仅和MTU有关,还和TCP连接建立的时候,双方协商的报文大小有关,接下来会有专门介绍。
  既然我们上面说了完整TCP报文被切分成几个报文段,那么就必须有个标识来说明当前报文段在完整的报文段中的位置。当对端收取到所有报文之后,就可以根据头部这个序号字段对数据进行重新排序,组装成完整的数据。序号这个字段就是用来说明当前TCP报文在整个TCP数据中处于什么位置。既然每个发送的TCP报文段有序号,TCP为了保证每个报文段能被接收到,所以就会对每个报文段进行接受确认,这就是确认号字段的作用。 如果没有接受到某个发送序号的确认,发送端就会 自动重传某个特定序号的报文。
  其实严格说来,序号和确认号指的是当前报文从哪一个字节开始发送,确认号是接收端告诉发送端我接收到那个位置之前的数据了。
 这样TCP协议就有每个报文段的发送序号,通过此方法TCP接收端可以通过对发送序号重排保证数据的最终有序性;有对每个报文是否成功接受的确认,就能保证接收端接受数据的完整性。

 1.3:TCP报文段切分

  一个TCP报文不可能很小,因为如果很小那么我们可以计算一下在一次TCP传输中传输非有效字节是多少。这里的非有效字节是指非发送端直接想要发送的数据,而是每一层协议中额外添加的头部,数据检验和,各种标识等字段。我们从传输层开始算起,TCP头部至少20字节,IP头部至少20字节,数据链路层X字节(要看具体协议),我们可以看到非有效数据是肯定要大于40字节的。如果你传输的数据很少,还么有各层协议栈的头部数据大,那么网络资源就很大一部分浪费掉。

  但是又不能很大,这里主要有两个原因。

  第一个因为无论上层数据是采用什么协议,最终都会用底层的物理层进行传输。在这里简单介绍一下以太网的传输机制。由于以太网传输受物理设备方面的限制,每个以太网帧都有最小的大小64B,最大不能超过1500B。对于不在这两个区间的的以太网帧我们都可以视之为无效的数据帧,转发设备会丢弃这些数据帧。对于这两个区间分别减去帧头则是可以传输的上次数据的大小。MAC目的地址6B,MAC源地址6B,Type域2B和帧尾CRC校验部分4B总共18B,所以可以有效传输数据为1500B。当TCP报文过大的时候,就会导致很多分段,不仅没有增加传输效率而且还会降低。

  第二个原因其实是对第一个原因的解释,那就是为什么底层传输不把包设置的很大,这样就不用分片了啊。原因主要是当一个包很大的时候,网络延时会比较大,不可控事件更容易发生;而且包越大,数据越容易有出错的bit出现,导致接受到的数据无效而丢弃。

  2:链接与断开过程


2.1:连接建立过程:

【socket】socket介绍-TCP协议_第2张图片

通过上图可以看出典型TCP连接的三次握手。
第一步:由一端发出连接请求,发出同步序号syn;

第二步:对端收到连接请求之后,如果允许连接,则发出ack(收到的syn+1)与另一个同步序号syn到开始请求连接的一端;
第三步:请求端这个时候收到对端返回的允许连接,请求端发出确认。
这个时候TCP连接成功,可以传输数据。在这个过程中需要注意的几点是:1)每个发送都会有等待时间,当在等待时间内没有收到对端的反映,则重复发送;2)重复发送有次数限制;3)每次发送都会有syn序号,相应必须和序号切合才认为是本次连接的三次握手中的其中一次交互。
针对上面需要注意的几点,有些地方就可以被黑客所利用,制造攻击行为。比如第一点所说, 没收到回复则会重复发送请求 。有一种DDOS攻击则是利用了客户端对务端发送连接请求的第二次握手。简单说明下过程,当客户端请求连接服务器端,发送了syn包,这时候服务器允许连接发送syn+ack给客户端,服务器会一直等待客户发送响应并维护当期这个半连接。当一定时间之后没收到客户端响应,服务器就重复发送syn+ack并还是维护该连接。攻击过程就是控制n个肉鸡发送服务器连接请求,是发送请求之后,不对服务器发送的syn+ack进行响应,或者使用无效IP事服务器发送的syn+ack根本无法发送到客户端。这样服务器就维护了N个的无效半连接,耗费计算资源而且无法接受正常的连接请求。

 2.2:连接断开过程:

【socket】socket介绍-TCP协议_第3张图片


和TCP连接不同的是,TCP断开采用了四次握手的机制。因为对于发送端和接收端来说,谁都可以单独发出断开的请求。因此整个连接的彻底断开需要每个端都发送一对断开请求和对请求的确认。这就会出现断开过程需要四次握手机制。

下面就对图进行介绍,其中有几个关键状态(注意,所有状体都是针对上图说明的;当服务端提出断开的时候,状态正好全部对调):

1:FIN_WAIT_1,客户端首先发送FIN,告诉服务端请求断开,等待服务端确认。这个时刻一般就是客户端发送完数据,已经没有东西发送。

2:FIN_WAIT_2,客户端接收到服务端对FIN的确认ACK,客户端进入当前状态。在这种状态下,客户端只可以接受数据,不可发送数据

3:CLOSE_WAIT,当服务端接受到客户端发送的FIN请求的时候,发送ACK给客户端,进入该状态。

4:LAST_ACK,服务端发送完数据,处理结束,这个时候向客户端发送FIN请求,请求自己端断开连接。

5:TIME_WAIT,客户端接收到服务端发送FIN请求,发送ACK,进入此状态。在这个状态,无论是客户端还是服务端都不能发送和接受数据。TIME_WAIT状态只有谁先提出断开,谁才会进入这个状态。

在TIME_WAIT一段时间以后,进入真正的CLOSED状态,等待时间是为了防止之前发送的FIN或者ACK被下一个连接接受到,而导致误断开的情况。



IP:http://www.infocellar.com/networks/ip/ip-packet.htm

TCP wiki:TCP wiki

你可能感兴趣的:(tcp,socket)