Contents
  1. 1. 连接建立
  2. 2. 发送数据
    1. 2.1. 特殊字段
    2. 2.2. 面向字节流
  3. 3. 连接释放
  4. 4. 后记

要理解TCP的连接和断开其实不难,需要自己代入情境,如果是你来设计网络协议你会如何做。

连接建立

情况: 通信质量无法保障(IP层的不可靠性)的情况下,如何保证两者可靠通信。

  1. A: 在家吗,我想过来玩?[SYN]
  2. B: 在,你过来吧。[SYN,ACK]
  3. A: 好的。[ACK]
  4. (完成)A出发…

  所谓三次握手,其实是发了三次包,代表一次握手过程中的三个步骤而已。

  如果少了第三步,可以出现什么情况?因为通信糟糕(TCP设计于70年代,网络确实也较差),A有未收到答复2的可能性,那么B就无法确定A会不会来,只能一直等待(syn flood 攻击)。如果有第三步,系统可以设置较短的等待时间,过时不候。而如果设计上就没第三步,那么等于服务器收到请求即建立连接,这样会造成很多不必要的消耗。

  其实3完成也还有不确定性,因为B没有对此作回复,所以B可能未收到,从而连接未建立,那么A过去就会被拒之门外,但关系不大,重新发起请求就行了。

  或者也可以这么理解:

1 B收到A的SYN,B知道了A-->B可达
2 A收到B回复的SYN ACK,A知道了A-->B,B-->A可达
3 B收到A的ACK, B知道B-->A可达

也就是说如果少了第三步,B无法知道B-->A线路的可用性,而三步是双方都能确认双向可达性的最少步骤。

发送数据

  当然仅靠握手还无法保证TCP的可靠性,于是就有seq和ack编号,来对每个数据块作确认,为了提高效率引入了pipeline思想,多线程同步发送,为了保障效率和控制拥塞又引入了window。

  上图中TCP建立之后,就开始HTTP的GET操作,注意下文的TCP segment len : 140 ,此次GET操作传送的载荷是140Byte,所以紧接的回复ACK号是141,意为接下来准备接收从141字节起始的内容。

  所以接下来的下一个GET,其SEQ为141。

  所以数据传送期间,SEQ就是上次对方发送的ACK号,而ACK则是上次对方发送的SEQ+数据Length

特殊字段

  TCP设计了一些十分有用的标识位,比如URG紧急,远程发出中断指令时可使用,配合紧急指针字段,指令将立即加入到缓存队列的最前端。

  与之对应的是PSH推送,它代表对方收到此报文后应该立即交付应用层,而不是在缓冲中排队。注意这里没有相应的定位指针,因为PUSH总是单独创建的报文段。

  可以看到HTTP GET使用了PSH,以便Server能更快地响应。之后的302回复也使用了PSH。

面向字节流

  TCP没有protoTypea或者类似etherType的标志位,虽然会对数据分块,但是也没有类似IP那样的分片标志。因为TCP是面向字节流的,对PDU的内容不关心,由上层应用去解析。

  Server对二次GET的响应内容较长,使用了多个TCP包来传送,可以看到client没有再逐个ACK
  Server发送数据期间,Client只收不发,所以Server方报文的ACK一直不变,而client的ACK号相应增加。

  另外如果检查TCP的PDU(第一个segment),可以发现其内容直接就是:

1
2
3
4
5
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 27 Apr 2015 02:51:14 GMT
Content-Type: text/html; charset=utf-8
.......

  下图中TCP头部以后,数据段起始前四字节,数值为0x48 0x54 0x54 0x50

  0x48 0x54 0x54 0x50对应ascii就是HTTP

连接释放

TCP连接的释放过程比建立复杂一些,因为TCP是双工的,所以包含两个过程

  1. A数据传送完成,提出断开请求
  2. B确认(此时A—》B方向断开,但是B—》A依然畅通)
  3. B在己方数据传输完成后,(虽然此例中没有再传输数据,但是B是可以继续向A发数据的)也提出断开请求,
  4. A确认
  5. 至此完全断开

可以看到期间ACK一直是置位的,因为协议规定连接存续期间ACK为1。

后记

当然TCP远不止上面提到的那么简单,为了在不确定交付的IP上构建可靠连接,TCP设计了许多巧妙的机制,比如说它的状态机,它的和重传机制,想再一步深入推荐TCP的那些事儿,文章不长,但是信息量却是很大的。

Contents
  1. 1. 连接建立
  2. 2. 发送数据
    1. 2.1. 特殊字段
    2. 2.2. 面向字节流
  3. 3. 连接释放
  4. 4. 后记