2、TCP/IP基础回顾:IP地址、端口号、三次握手与四次挥手

各位同学,咱们今天聊点实在的。Modbus TCP 说到底,就是把 Modbus 报文塞进 TCP 包里跑。所以,TCP/IP 的基础不过关,后面组网调试你会很痛苦。我见过太多工程师,拿着抓包软件一脸懵,就是因为搞不清握手和挥手。

这一节,咱们把 IP 地址、端口号、三次握手、四次挥手这几个核心概念,用实战的眼光捋一遍。别嫌基础,基础不牢,地动山摇。

2.1 IP地址:设备在网络中的门牌号

IP 地址,说白了就是设备的门牌号。你想想看,整个工厂几百台设备,PLC、HMI、变频器、传感器,它们之间要通信,总得知道对方在哪吧?IP 地址就是干这个的。

目前主流还是 IPv4,32 位,写成四个十进制数,比如 192.168.1.100。每个数范围 0~255。嗯,这里要注意,0255 有特殊用途,别乱用。

重要概念:IP 地址 = 网络号 + 主机号。子网掩码决定哪部分是网络号,哪部分是主机号。

举个例子:192.168.1.100/24,这里的 /24 就是子网掩码 255.255.255.0。前 24 位是网络号,后 8 位是主机号。所以这个网段里,可用的主机地址是 192.168.1.1192.168.1.254

我在项目中遇到过一件事:有个现场,PLC 和上位机怎么都连不上。我过去一看,PLC 设的是 192.168.1.100,上位机设的是 192.168.2.100,子网掩码都是 255.255.255.0。这俩根本不在一个网段,能通才怪!

实战建议:Modbus TCP 组网时,我习惯把所有设备放在同一个网段。如果非要跨网段,记得配好网关和路由。别给自己找麻烦。

2.2 端口号:区分同一台设备上的不同服务

IP 地址找到了设备,但设备上跑着好多服务呢。比如一台 PLC,既跑 Modbus TCP,又跑 Web 配置页面,还跑 FTP 上传程序。数据包来了,该交给谁?

端口号就是干这个的。它是一个 16 位的数字,范围 0~65535。其中:

  • 0~1023:知名端口,系统服务用。比如 HTTP 是 80,HTTPS 是 443。
  • 1024~49151:注册端口,应用程序用。Modbus TCP 默认就是 502。
  • 49152~65535:动态/私有端口,客户端临时用。

Modbus TCP 的默认端口是 502。这个端口是 IANA 分配给 Modbus 协议的。不过,我建议你在实际项目中,如果可能,尽量用默认端口。为什么?因为很多防火墙和交换机默认放行 502 端口,你改了反而可能被拦。

避坑指南:我曾经遇到一个项目,客户把 Modbus TCP 端口改成了 5000,结果现场调试时,IT 部门死活不给开 5000 端口,说是安全策略。最后折腾了两天才协调好。所以,非必要不改端口。

端口号在 TCP 报文里是这么放的:

TCP 报文头结构(20 字节):
+--------+--------+--------+--------+
| 源端口 (16位)    | 目的端口 (16位)   |
+--------+--------+--------+--------+
| 序列号 (32位)                     |
+-----------------------------------+
| 确认号 (32位)                     |
+-----------------------------------+
| 数据偏移 | 保留 | 标志位 | 窗口大小 |
+--------+--------+--------+--------+
| 校验和 (16位)    | 紧急指针 (16位)  |
+--------+--------+--------+--------+

你看,源端口和目的端口就在最前面。发送方随机选一个高位端口(比如 50001),目的端口固定为 502。这样,PLC 收到报文后,一看目的端口是 502,就知道这是 Modbus 请求,交给 Modbus 处理模块。

2.3 三次握手:建立连接的可靠保障

TCP 是面向连接的协议。什么叫面向连接?就是通信之前,先得把路修好。三次握手就是修路的过程。

我画了一张图,帮你理解这个过程:

客户端 (上位机/PLC) 服务端 (PLC/从站) CLOSED LISTEN ① SYN=1, seq=x SYN_SENT ② SYN=1, ACK=1, seq=y, ack=x+1 SYN_RCVD ③ ACK=1, seq=x+1, ack=y+1 ESTABLISHED ESTABLISHED 数据交互(Modbus 请求/响应) 图例: 客户端 → 服务端 服务端 → 客户端 数据交互 SYN:同步序列号标志位 | ACK:确认标志位 | seq:序列号 | ack:确认号

三次握手的流程,我用人话给你讲一遍:

  1. 第一次握手:客户端说:「喂,服务端,我要跟你说话。这是我的序列号 x。」(发送 SYN 包)
  2. 第二次握手:服务端说:「收到。我准备好了,这是我的序列号 y,我确认收到了你的 x。」(发送 SYN+ACK 包)
  3. 第三次握手:客户端说:「好,我确认收到了你的 y。咱们开始聊吧。」(发送 ACK 包)

为什么非要三次?两次不行吗?你想想看,如果只有两次握手,服务端发了 SYN+ACK 后就认为连接建立了。但如果这个 SYN+ACK 丢了,客户端没收到,客户端会重发 SYN。服务端收到重发的 SYN 后,又发一个 SYN+ACK,然后认为又建立了一个新连接。这样就会产生多个无效连接,浪费资源。

三次握手解决了这个问题:客户端必须再确认一次,服务端才知道客户端确实收到了自己的响应。

实战经验:我在调试 Modbus TCP 时,如果发现连接建立失败,第一件事就是抓包看三次握手。常见问题有:
  • 客户端发了 SYN,服务端没回 SYN+ACK → 服务端没开机或端口没监听
  • 服务端回了 SYN+ACK,客户端没回 ACK → 客户端防火墙拦了
  • 三次握手完成,但马上发 RST 断开 → 应用层不匹配,比如 Modbus 功能码不对

2.4 四次挥手:优雅地断开连接

聊完了,要挂电话。四次挥手就是挂电话的过程。为什么是四次?因为 TCP 是全双工的,两边都要独立地关闭自己的通道。

流程是这样的:

  1. 第一次挥手:客户端说:「我说完了,我要挂了。」(发送 FIN 包,seq=u)
  2. 第二次挥手:服务端说:「收到你的 FIN,我确认。但我还有话没说完,你先别挂。」(发送 ACK 包,ack=u+1)
  3. 第三次挥手:服务端说:「好了,我也说完了,现在可以挂了。」(发送 FIN 包,seq=v)
  4. 第四次挥手:客户端说:「收到,我确认。我等你一会儿,怕你还有话要说。」(发送 ACK 包,ack=v+1)

这里有个关键点:客户端发送第四次挥手后,会进入 TIME_WAIT 状态,等待 2MSL(最大报文生存时间)后才真正关闭。为什么?

嗯,原因有两个:

  • 确保服务端收到了最后的 ACK。如果 ACK 丢了,服务端会重发 FIN,客户端还能再回应。
  • 防止旧连接的数据包干扰新连接。等待足够长的时间,确保网络中所有属于这个连接的数据包都消失了。
避坑指南:我曾经遇到一个 Modbus TCP 网关,频繁断开重连。抓包发现,每次断开后,客户端进入 TIME_WAIT 状态,要等 2 分钟才能释放端口。而网关那边急着重连,端口被占着,连不上。最后我调整了客户端的 TCP 参数,缩短了 TIME_WAIT 时间,问题解决。

2.5 小结:这些基础对 Modbus TCP 意味着什么?

好了,咱们把 IP 地址、端口号、三次握手、四次挥手都过了一遍。你可能会问:这些跟 Modbus TCP 到底有什么关系?

关系大了去了:

  • IP 地址决定了你的 Modbus 客户端要去找哪个设备。
  • 端口号 502告诉设备,这个包是 Modbus 协议,不是 HTTP 也不是 FTP。
  • 三次握手确保 Modbus 请求/响应在可靠的连接上传输,不会丢包乱序。
  • 四次挥手保证连接优雅关闭,数据不会丢失。

说白了,Modbus TCP 就是 Modbus 协议穿上 TCP/IP 的外衣。TCP/IP 负责把数据可靠地送到对方手里,Modbus 负责解释数据里到底要干什么——读寄存器还是写线圈。

下一节,咱们就正式进入 Modbus TCP 的报文结构,看看这个「穿了外衣」的协议到底长什么样。


公众号:蓝海资料掘金营,微信 deep3321