TCP协议学习笔记(一)
传输控制协议,洋文叫Transmission Control Protocol,简称TCP。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。
IP即Internet Protocol是工作在网络层的,其不对网络的可靠性做任何保证,目前互联网中网络的可靠性一般都由TCP来保证,所谓可靠性具体来说就是数据传输不丢失、数据顺序不会发生改变。除了可靠性,TCP还提出了一系列的算法来保证网络数据传输的高效性。
我们先简单的看一下TCP报文的数据结构,其中TCP报文的头部一般都是20个字节,当然根据首部长度字段也可以进行适量的扩充,最大为60字节,跟随在头部信息之后的就是TCP所携带的数据信息。
我们会从两个大的方面来描述TCP的工作方式
- TCP连接的创建和关闭
- TCP的数据传输过程
抓取TCP的报文信息
为了了解TCP的工作方式,我们使用tcpdump来抓取TCP报文进行分析。首先我们启动一个HTTP服务器
$ python -m SimpleHTTPServer 5800
Serving HTTP on 0.0.0.0 port 5800 ...
随后启动tcpdump并让其监听指定端口的数据信息
$ tcpdump tcp port 5800 -S
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
最后我们使用curl请求HTTP服务器
$ curl -v http://172.21.3.92:5800
这次操作使得tcpdump获得如下输出
1 | 15:18:45.635203 IP 172.19.3.44.59480 > lin-21-3-92.5800: Flags [S], seq 586172531, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1351103125 ecr 0,sackOK,eol], length 0 |
其中的标志含义如下
标志 | 三字符缩写 | 描述 |
---|---|---|
S | SYN | 同步序号 |
F | FIN | 发送方完成数据发送 |
R | RST | 复位连接 |
P | PSH | 尽可能快的将数据发往接受进程 |
. | 以上4个标志bit均置为零 |
下面我们就基于这次实验的结果来了解TCP。
TCP连接的建立
TCP是一个面向连接的协议,双方在进行数据传输前需要先建立连接,上面的实验的前三行就是所谓的“三次握手”。
- 客户端向服务端发送一个SYN的数据,其中的seq为586172531
- 服务端接收到SYN报文之后,将报文中的seq+1并作为ACK返回给客户端
- 服务端自己也生成了一个seq并将这个seq 2988380519发送给客户端
- 客户端收到了服务端的seq之后,将报文中的seq+1并作为ACK返回给服务端
以上就是建立连接时客户端和服务端之间的数据交互,我们可以看到建立连接时最重要的就是告知对方自己当前的seq的值,这个seq的初始值随时间变化,不会发生重复。
以上建立连接过程的行为不是需要4步操作吗,怎么会称为“三次握手”呢。其实很简单,因为步骤二和步骤三都是由服务端向客户端发送数据,所以这两步操作其实被合并为一步操作了。所以最终三次握手如下
- 客户端发送seq给服务端
- 服务端收到seq,将seq+1作为ACK,并且生成一个自己的seq,把客户端的ACK和服务端的seq发送给客户端
- 客户端收到ACK并校验,知道服务端已经知道了自己的seq了;同时客户端还知道了服务端的seq,其把服务端的seq+1并作为ACK返回给服务端,最终服务端知道客户端也已经知道了自己的seq了。连接建立成功。
TCP连接的关闭
建立连接需要3次握手,断开连接却需要4次挥手,这是因为TCP的半关闭特性造成的。简单来说,TCP允许只关闭某一个方向上的连接。我们知道TCP连接是全双工的,而关闭单向的连接之后,另一个方向上的连接还可以正常的发送数据,此时连接变成单工。
上面的报文信息7、9、10、11行显示了这个4次挥手的过程
- 第07行:服务端发送FIN标志给客户端
- 第09行:客户端收到了FIN标志后,将服务端的seq+1并返回ACK给服务端,此时 服务端->客户端 的连接关闭
- 第10行:客户端发送FIN标志给服务端
- 第11行:服务端收到FIN之后,将客户端的seq+1并发送ACK给客户端,客户端收到了ACK,客户端->服务端 的连接关闭
TCP连接断开的过程和连接过程非常相似,区别只在于客户端收到了服务端发送的FIN标志后,在发送给服务端的ACK中没有附带自己的FIN标志,这是TCP的半关闭特性所导致的。
需要注意的是一旦TCP连接建立成功,此时连接双方在传输数据或者断开连接时,都是处于完全对等的状态,不存在身份上的差别。简单来说客户端发送数据给服务端和服务端发送数据给客户端是一样的;而最终断开连接的操作可以由客户端率先发起,也可以由服务端率先发起,它们也都是一样的。
总结
关于TCP的笔记暂时先到这里,我们已经了解了TCP连接的建立和关闭,在下一篇文章中我们再继续了解一下TCP的数据传输过程。
最后放一张TCP中连接的状态转移图,这之中的状态变化主要是在连接建立和关闭时所产生的。俺认为作为非网络方向的程序员并不需要记得这张图,只需要在进行网络分析的时候能够对照着这张图进行分析即可,不过俺对自己的要求一向较低,还请读者不要学我。