Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端网络预科 - TCP #31

Open
baixiaoji opened this issue Dec 23, 2019 · 0 comments
Open

前端网络预科 - TCP #31

baixiaoji opened this issue Dec 23, 2019 · 0 comments
Labels

Comments

@baixiaoji
Copy link
Owner

baixiaoji commented Dec 23, 2019

前端网络预科 - TCP

根据前文的「预备知识」部分,我们已经获得了目标的IP地址和MAC地址,现在已经可以构建完整的请求包了。

于是客户端和服务端开始建立连接,此刻使用面向连接的协议就是传输控制协议( TCP - Transmission Control Protocol )。 TCP 建立连接的过程便是「三次握手」。

概念部分

在介绍「三次握手」之前,我们着重看看TCP头部信息。

  • Source portDestination port :都占16位,分别代表源端口号和目标端口号;

  • Sequence number :表示在当前TCP报文中,第一个数据字节在数据流中的序号;主要用来解决网络包乱序的问题;

  • Acknowledgment number :确认序号表示ACK发送者期望的下一个Sequence number。因此确认序号应该是上次已经成功接受字节序号 + 1;

  • Data offset :数据偏移量,表示TCP开始到实际数据的偏移量;

  • Reserved:保留位,为将来预留的字段;

  • Flags:控制位,曾今只有6个控制位,现在已经新增到9个。主要用于操控TCP的状态机的,依次为NS,CWR,ECE,URG,ACK,PSH,RST,SYN,FIN。主要介绍和握手相关的几个控制位的含义:

    • ACK:此标志表示应答域有效,就是说前面TCP的确认序号将会包含在TCP数据包中(其实就是你发的上一个序号为Acknowledgment number的包我已经收到了);有两个取值:0和1,为1的时候表示应答域有效,反之为0;
    • SYN:同步序列号,只有两端发送的第一个数据包中含有此标志。
    • FIN:表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。
  • Window :窗口大小,用来流量控制,这是一个复杂的问题,本文并不涉及;

  • Checksum:校验和,用来校验这个TCP包的信息是否正确。

开始讲述三次握手:
三次握手
一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,然后处于 LISTEN 状态。

  1. 第一次握手:客户端主动发起请求,其中报文中开启了SYN,以及设置里 Sequence number 为x,然后客户端进入 SYN_SEND 状态。
  2. 第二次握手:服务端收到客户端的 SYN 报文段,需要对 SYN 报文段进行确认(开启ACK控制位),然后设置了 Acknowledgment number 为 x + 1;同时在自己的报文中开启了SYN,设置Sequence number为 y ;将两者信息合并发在一个报文段中,一并发给客户端,此时服务器进入 SYN_RCVD 状态。
  3. 第三次握手:客户端收到了服务端的 SYN + ACK 报文段,然后同样开启 ACK 控制位,然后调整 Sequence number 为 x + 1,Acknowledgment number 为 y + 1,然后发送给服务器 ACK 报文段。这个报文发送完毕以后,客户端和服务器都进入了 ESTABLISHED 状态,完成了三次握手。

完成了三次握手,客户端和服务器就可以发送数据了。而三次握手的目的并不仅仅是建立连接,同时消息双方沟通好TCP包的起始序号。

当然你或许看不明白,如果不是很清楚真想弄清楚的话,建议还是看看上面列举出来 TCP 头部信息代表的含义;当然如果仅仅是想要一个模糊的影响的话,大致记住:「消息双方都要有去有回」 就行了。

当数据传输完毕,就开始断开 TCP 连接。而断开TCP连接的过程便是「四次挥手」。

四次挥手

  1. 第一次挥手:主机 A (可以是客户端,也可以是服务器端),设置了 Sequence number 和开启了 FIN 控制位,向主机B发送了FIN报文段,此时,主机A进入了 FIN_WAIT_1 状态;表明主机A已经没有数据发送给主机B了;
  2. 第二次挥手:主机 B 收到了主机A的报文段,设置里Acknowledgment number为收到报文中的 Sequence number + 1,然后开启了ACK控制位(表明前面你发的包我已经收到了),发送给主机 A。此时,主机A进入 FIN_WAIT_2 状态;
  3. 第三次挥手:主机 B 发送像主机 A 断开连接时候的FIN报文给主机 A,请求断开连接,同时主机 B进入LAST_ACK状态;
  4. 第四次挥手:主机 A 收到了 主机 B 的 FIN报文,向主机B发送ACK报文,然后主机A进入TIME_WAIT状态;主机 B 收到主机A的ACK报文段以后,就关闭连接;此时,主机A等待2MSL后依然没有收到回复,则证明Server端已正常关闭,主机A也可以关闭连接了。

至此,TCP 基本的概念已经介绍结束了,但是你依旧很疑惑的话,这时候你需要自己实践看一下了。

实践部分

想要继续下去的同学们,你需要去下载 wireshark

创建一个名为tcp-server.js 的文件,代码如下:

// tcp-server.js
const net = require('net');

const server = net.createServer(function(client) {
    client.on('data', (data) => {
        console.log(data.toString());
        client.write(data);
    })
})

server.listen(10086, () => {
    console.log('listening 10086 port');
})

打开 wireshark 软件,过滤器选择取决于你是如何创建的tcp-server。若在本地去连接本地创建的tcp-server,过滤器请选择 Loopback,若是连接你远程服务器上的请选择对应的网络过滤器(可能是WLAN或是Wi-Fi)。

因为下述演示在本地进行,所以我选择的是 Loopback,然后在自定义过滤条件中输入 tcp.port == 10086 的过滤条件,这里的 10086 就是创建 TCP Server 时候监听的端口号。

然后在对应的目录下面执行 node tcp-server.js,然后另外创建一个终端,进入node环境,然后执行 net.connect(10086,'自己的IP地址'),你就可以看到 wireshark 中拦截的 三次握手包。

三次握手

然后选中对应的包可以便可以查看 TCP 报文信息,具体查看方法

然后你退出连接 TCP Server 的 node 环境,这时候查看 wireshark ,它拦截的 四次挥手包。

四次挥手抓包

同样选中对应包,然后进行查看 TCP 报文信息。以上就是实践查看 三次握手和四次挥手 TCP包的过程。

以上表述并非十分严谨,想要查看严谨表述请查看教材

参考文献

  1. 网络是怎样连接的
  2. TCP-wikipedia
  3. 通俗大白话来理解TCP协议的三次握手和四次分手
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant