101与104规约解析及源码实现详解

101与104规约解析及源码实现
AI助手已提取文章相关产品:

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在电力自动化系统中,101和104规约是实现设备远程通信的关键协议,广泛应用于SCADA系统中。101规约基于串行通信,适用于主站与RTU之间的数据交互;而104规约基于TCP/IP,更适合现代网络环境。本文详细介绍了101和104规约的基本结构、帧格式及解析流程,并深入解析104规约的源码实现,包括TCP连接管理、ASDU与TCPU结构、序列号控制、错误检测与恢复机制等内容。通过学习规约源码,有助于提升电力系统通信的稳定性与开发调试效率。
101_104规约解析_101_104_104规约源码_104规约_规约解析

1. 电力自动化通信协议概述

在现代智能电网系统中,通信协议扮演着数据交互与控制指令传递的核心角色。其中,IEC 60870-5-101(简称101规约)与IEC 60870-5-104(简称104规约)作为电力自动化领域的关键通信标准,广泛应用于变电站自动化、远程终端单元(RTU)与主站系统之间的信息交互。

101规约基于串行通信,适用于点对点或小规模网络环境,具备结构清晰、实现简单等特点;而104规约则基于TCP/IP协议栈,适用于广域网环境,支持更高效的远程数据通信。两者在设计上均遵循统一的应用服务数据单元(ASDU)结构,体现了良好的兼容性与可扩展性。

随着智能电网的发展,101与104规约不断演进,增强了对时间同步、安全认证、数据压缩等功能的支持,成为构建现代电力监控系统(SCADA)的重要技术基础。

2. 101规约结构与解析方法

IEC 60870-5-101(简称101规约)是电力系统中广泛采用的一种串行通信协议,主要用于变电站自动化系统中主站与子站之间的数据交换。它定义了在物理层、数据链路层以及应用层上的通信规范,适用于点对点或一点多点的串行通信方式。本章将从协议的结构组成、通信机制、解析方法到实际调试工具的应用进行深入剖析,帮助读者全面理解101规约的工作原理与工程实现。

2.1 101规约的协议层次与帧格式

101规约基于OSI模型的三层结构:物理层、数据链路层和应用层。每一层都承担着不同的通信职责,确保数据的可靠传输与正确解析。

2.1.1 物理层与数据链路层的关系

在101规约中,物理层主要负责数据的电气传输,通常使用RS-232或RS-485接口进行通信。数据链路层则定义了帧格式、差错控制、流量控制等机制,确保数据在物理介质上可靠传输。

层次 功能描述
物理层 定义电平、波特率、传输方式(异步/同步)
数据链路层 定义帧结构、差错检测(如校验和)、帧同步
应用层 定义数据语义、信息对象类型、传输服务

数据链路层通过帧结构将上层应用数据进行封装,并添加控制信息如地址、长度、校验码等,形成完整的帧进行传输。

2.1.2 帧类型与基本结构定义

101规约定义了三种主要帧类型:

  • I帧(信息帧) :用于传输应用数据,具有序列号,用于流量控制。
  • S帧(监督帧) :用于确认接收,不携带数据。
  • U帧(非编号帧) :用于控制连接的建立、释放等操作。

帧的基本结构如下:

| 起始字节 | 地址域 | 控制域 | 长度域 | 用户数据 | 校验和 |

例如,一个典型的I帧结构如下所示:

7E 01 03 05 00 01 02 03 04 05 B0

其中:

  • 7E :起始字符,标识帧的开始;
  • 01 :地址域,表示子站地址;
  • 03 :控制域,表示帧类型和序列号;
  • 05 :长度域,表示用户数据长度;
  • 00 01 02 03 04 05 :用户数据;
  • B0 :校验和,用于差错检测。

代码分析

def calc_checksum(data):
    return sum(data) % 256

上述代码用于计算帧的校验和,其中 data 是用户数据部分的字节列表。通过求和并取模256的方式,确保校验和与接收端一致。

2.2 101规约的通信模式与交互流程

101规约采用主从结构的通信方式,主站(调度中心)发起请求,子站(RTU/FTU)响应。通信流程通常包括请求、响应、确认和重传机制。

2.2.1 主从结构与请求-响应机制

主站发送请求帧(如遥测召唤)后,子站需在规定时间内返回响应帧。若主站未收到响应,则触发重传机制。

流程图如下:

graph TD
    A[主站发送请求帧] --> B[子站接收并处理]
    B --> C{子站是否有数据?}
    C -->|是| D[子站发送响应帧]
    C -->|否| E[发送确认帧]
    D --> F[主站接收并校验]
    F --> G{校验通过?}
    G -->|是| H[通信完成]
    G -->|否| I[主站重发请求]

2.2.2 数据召唤与事件上报的实现流程

数据召唤(如总召唤)是主站主动获取子站全部数据的过程。而事件上报则是子站在发生状态变化(如开关变位)时主动上报。

例如,总召唤流程如下:

  1. 主站发送C_IC_NA_1(总召唤命令);
  2. 子站接收后开始准备数据;
  3. 子站逐帧发送遥测、遥信等数据;
  4. 主站接收并确认;
  5. 所有数据完成后发送召唤结束帧。

2.3 101规约的解析方法与实现技巧

正确解析101规约的报文是实现通信的关键。解析流程通常包括帧同步、校验、解码和状态判断。

2.3.1 报文解码的通用流程

完整的解析流程如下:

graph LR
    A[接收原始字节流] --> B[寻找起始字符7E]
    B --> C[读取地址域]
    C --> D[读取控制域]
    D --> E[读取长度域]
    E --> F[读取用户数据]
    F --> G[计算校验和]
    G --> H{校验是否通过?}
    H -->|是| I[解码用户数据]
    H -->|否| J[丢弃帧并记录错误]

2.3.2 关键字段提取与状态判断

在解码用户数据时,需根据类型标识(TypeID)提取信息对象。例如,遥测(TypeID=9)包含信息对象地址、值、时间戳等字段。

例如,遥测信息体结构如下:

| 信息对象地址 | 值 | 品质描述 | 时间戳 |

代码示例:

def parse_measurement(data):
    obj_addr = data[0] * 256 + data[1]
    value = (data[2] << 8) | data[3]
    quality = data[4]
    timestamp = (data[5] << 16) | (data[6] << 8) | data[7]
    return {
        'obj_addr': obj_addr,
        'value': value,
        'quality': quality,
        'timestamp': timestamp
    }

上述代码解析了一个遥测信息体,其中:

  • obj_addr :信息对象地址;
  • value :测量值;
  • quality :品质描述(如有效、溢出);
  • timestamp :时间戳。

2.4 101规约的典型应用场景与调试工具

101规约广泛应用于变电站监控系统、配电自动化系统等领域。调试与分析101报文通常需要借助抓包工具如Wireshark。

2.4.1 工程实例分析与报文示例

以一个遥信信息召唤为例,主站发送如下请求帧:

7E 01 03 04 64 01 06 00 01 00 00 14

其中:

  • 7E :起始字符;
  • 01 :地址;
  • 03 :控制域(I帧);
  • 04 :长度;
  • 64 :功能类型(遥信);
  • 01 06 :信息对象地址;
  • 00 01 00 00 :召唤参数;
  • 14 :校验和。

子站响应如下:

7E 01 01 06 64 01 06 00 01 01 00 00 00 17
  • 64 :功能类型;
  • 01 06 :对象地址;
  • 01 :遥信状态(闭合);
  • 00 00 00 :品质与时间戳。

2.4.2 常用抓包工具(如Wireshark)的应用

Wireshark支持101规约的解码插件,可通过串口或TCP/IP捕获通信流量。配置步骤如下:

  1. 安装Wireshark;
  2. 启用串口捕获(如使用com0com虚拟串口);
  3. 打开Wireshark,选择对应串口设备;
  4. 设置过滤条件(如 101 );
  5. 开始捕获并查看解析后的报文。

提示 :在Wireshark中,可使用如下显示过滤器查看101报文:

iec101

通过Wireshark可以直观地查看帧结构、控制域、信息体等内容,便于调试与问题定位。

通过本章的深入解析,我们已经全面了解了101规约的协议结构、通信流程、解析方法以及工程调试技巧。这些知识为后续深入理解101规约的报文结构与数据处理打下了坚实基础。

3. 101规约报文头、控制域、信息体解析

在电力自动化通信协议中,IEC 60870-5-101(简称101规约)作为底层串行通信协议,其报文结构清晰、功能明确,广泛应用于变电站自动化系统中。理解101规约的报文结构,尤其是报文头、控制域和信息体的组成与解析方法,是实现通信解析、数据采集与系统调试的关键基础。

3.1 报文头的组成与解析方法

101规约的报文头是整个帧结构的起始部分,用于标识帧的开始、长度、地址和协议类型等基本信息,是接收端解析报文的基础。

3.1.1 起始字符、长度字段与地址域

101规约的报文头通常由以下几个关键字段组成:

字段名称 长度(字节) 描述
起始字符(Start Byte) 1 固定为 0x68 ,标识帧的开始
长度字段(Length Field) 1 表示整个帧的长度(包括控制域、地址域和信息体)
控制域(Control Field) 1 包含帧类型和控制信息
地址域(Address Field) 1 表示目标地址,用于主站和子站之间的识别

示意图如下(使用 Mermaid 流程图表示):

sequenceDiagram
    participant Sender
    participant Receiver
    Sender->>Receiver: 发送起始字符0x68
    Sender->>Receiver: 发送长度字段
    Sender->>Receiver: 发送控制域
    Sender->>Receiver: 发送地址域
    Sender->>Receiver: 发送信息体(可变长度)
    Receiver->>Receiver: 解析起始字符是否为0x68
    Receiver->>Receiver: 根据长度字段读取剩余数据

3.1.2 协议标识与控制字段的解析逻辑

控制字段(Control Field)是101规约中用于标识帧类型和控制信息的核心字段。它通常为1个字节,其位结构如下:

位7 位6 位5 位4 位3 位2 位1 位0
PRM FCB FCV 功能码(Function Code)
  • PRM (Primary/Secondary):主站/从站标志位,1表示主站发送,0表示从站发送。
  • FCB (Frame Count Bit):帧计数位,用于确认帧的顺序。
  • FCV (Frame Count Valid):帧计数有效位。
  • 功能码 (Function Code):表示帧的类型,如请求、响应、确认等。

例如,功能码 0x07 表示“确认帧”,功能码 0x0B 表示“召唤帧”。

下面是一个控制字段解析的代码示例(C语言):

typedef struct {
    unsigned char start_byte;  // 固定为0x68
    unsigned char length;      // 帧长度
    unsigned char control;     // 控制字段
    unsigned char address;     // 地址域
} IEC101_Header;

void parse_header(const unsigned char *buffer, IEC101_Header *header) {
    header->start_byte = buffer[0];  // 起始字符
    header->length = buffer[1];      // 长度字段
    header->control = buffer[2];     // 控制字段
    header->address = buffer[3];     // 地址域
}

代码逻辑分析:

  • 从输入缓冲区 buffer 中依次读取四个字节,分别对应起始字符、长度字段、控制字段和地址域。
  • header->control 的位结构可以通过位运算进一步拆解,获取 PRM、FCB、FCV 和功能码的具体值。

3.2 控制域字段的定义与功能解析

控制域字段是101规约通信控制的核心,决定了帧的类型、方向、确认机制等。

3.2.1 控制字节的位结构与功能定义

控制字节(Control Byte)的结构如下:

含义
7 PRM(主从标识)
6 FCB(帧计数位)
5 FCV(帧计数有效)
4-0 功能码(Function Code)

例如,当 control = 0x73 时:

  • 二进制为 0111 0011
  • PRM = 0(从站发送)
  • FCB = 1(当前帧计数位为1)
  • FCV = 1(帧计数有效)
  • 功能码 = 0x03(响应帧)

3.2.2 请求、响应、确认与重传机制的实现

101规约通过控制域中的功能码和帧计数位实现通信的请求-响应机制和确认重传机制。

  • 请求帧 :功能码通常为 0x05 0x0A ,表示主站发起的请求。
  • 响应帧 :功能码通常为 0x0B ,表示子站的响应。
  • 确认帧 :功能码为 0x07 ,表示接收方确认已收到数据。
  • 重传机制 :主站根据帧计数位(FCB)判断是否重传,若未收到确认,则切换 FCB 状态并重发。

示例:请求与响应交互流程

sequenceDiagram
    participant Master
    participant Slave
    Master->>Slave: 发送请求帧(功能码0x05)
    Slave->>Master: 发送确认帧(功能码0x07)
    Slave->>Master: 发送响应帧(功能码0x0B)
    Master->>Slave: 发送确认帧(功能码0x07)

3.3 信息体的结构与数据表示方式

信息体是101规约中承载实际数据的部分,包含遥测、遥信、遥控等信息对象。

3.3.1 信息对象地址与信息元素编码

每个信息体包含:

  • 信息对象地址(Information Object Address) :2字节或3字节,用于标识数据点。
  • 信息元素(Information Element) :包含具体数据值。
  • 时间戳(Timestamp) :可选字段,表示数据采集时间。
  • 品质描述(Quality Descriptor) :表示数据有效性。

例如:

信息对象地址 数据值 时间戳 品质描述
0x0001 0x1234 可选 0x80

3.3.2 时间戳、品质描述与数据类型解析

  • 时间戳 :3字节表示毫秒 + 2字节表示分钟,例如 0x12 0x34 0x56 0x78 0x9A
  • 品质描述 :1字节,每一位表示不同状态(如无效、溢出、替代等)。
  • 数据类型 :如单点遥信(SP)、双点遥信(DP)、测量值(MV)等。

解析信息体的代码示例(Python):

def parse_information_element(data, offset):
    ioa = int.from_bytes(data[offset:offset+2], byteorder='little')
    offset += 2
    value = int.from_bytes(data[offset:offset+2], byteorder='little')
    offset += 2
    quality = data[offset]
    offset += 1
    return {
        'ioa': ioa,
        'value': value,
        'quality': quality
    }

代码说明:

  • ioa :信息对象地址,2字节小端格式。
  • value :数据值,如电压、电流值。
  • quality :品质描述字节,需进一步按位解析。

3.4 典型信息体类型与应用示例

101规约定义了多种信息体类型,常见类型包括:

类型标识 信息体类型 示例
M_SP_NA_1 单点遥信 开关状态
M_DP_NA_1 双点遥信 断路器状态
M_ME_NC_1 测量值(浮点) 电压、电流
C_SC_NA_1 单点遥控 控制开关合闸

3.4.1 遥测、遥信、遥控等信息体解析

遥测信息体(M_ME_NC_1)示例:

typedef struct {
    unsigned short ioa;      // 信息对象地址
    float value;             // 测量值(如电压)
    unsigned char quality;   // 品质描述
} MeasuredValue;

遥信信息体(M_SP_NA_1)示例:

typedef struct {
    unsigned short ioa;
    unsigned char state;     // 0表示断开,1表示闭合
    unsigned char quality;
} SinglePoint;

遥控信息体(C_SC_NA_1)示例:

typedef struct {
    unsigned short ioa;
    unsigned char command;   // 0表示分闸,1表示合闸
} ControlCommand;

3.4.2 实际工程报文解析与代码实现

以下是一个完整的101规约报文示例(16进制):

68 13 07 01 01 00 01 00 00 00 00 00 00 00 00 00 00 00

逐字段解析:

  • 起始字符: 0x68
  • 长度: 0x13 (19字节)
  • 控制字段: 0x07 (确认帧)
  • 地址域: 0x01
  • 信息体:从第4字节开始,包含信息对象地址 0x0001 ,数据值为 0x00 ,品质描述为 0x00

代码实现(Python):

def parse_full_frame(data):
    start = data[0]
    length = data[1]
    control = data[2]
    address = data[3]
    info_body = data[4:]
    print(f"起始字符: {hex(start)}")
    print(f"长度字段: {hex(length)}")
    print(f"控制字段: {hex(control)}")
    print(f"地址域: {hex(address)}")
    print("信息体解析:")
    for i in range(0, len(info_body), 4):
        ioa = int.from_bytes(info_body[i:i+2], 'little')
        value = int.from_bytes(info_body[i+2:i+4], 'little')
        print(f"IOA: {hex(ioa)}, Value: {value}")

执行逻辑分析:

  • 从完整报文中依次读取各字段。
  • 使用 int.from_bytes 解析信息对象地址和数据值。
  • 打印解析结果,便于调试和验证。

本章从101规约的报文头、控制域、信息体结构入手,详细解析了各字段的含义、解析方法,并结合代码示例展示了实际工程中的解析实现,为后续通信协议的开发与调试提供了坚实基础。

4. 104规约结构与网络通信特性

4.1 104规约的体系结构与网络模型

4.1.1 ISO/OSI模型中的位置与协议栈构成

IEC 60870-5-104(简称104规约)是一种基于TCP/IP协议栈的远程控制通信协议,广泛应用于电力自动化系统中,用于站控层与间隔层之间的信息交换。104规约是IEC 60870-5系列协议中的一部分,其设计基于ISO/OSI七层模型。

从协议栈的角度来看,104规约主要位于OSI模型的 应用层(Application Layer) ,其底层依赖于 传输层的TCP协议 网络层的IP协议 以及 链路层和物理层 的以太网或串行通信接口。

OSI 层次 104规约相关协议
应用层(Layer 7) IEC 60870-5-104(APCI + ASDU)
传输层(Layer 4) TCP
网络层(Layer 3) IP
链路层(Layer 2) Ethernet、PPP、HDLC等
物理层(Layer 1) 双绞线、光纤、串口等

在该协议栈中,APCI(Application Protocol Control Information)负责建立、维护和终止通信会话,而ASDU(Application Service Data Unit)则承载具体的遥测、遥信、遥控等应用数据。

4.1.2 104规约在TCP/IP环境中的实现

104规约的实现依赖于TCP/IP协议栈,其通信过程主要通过以下几个步骤:

  1. 建立TCP连接 :主站(SCADA系统)作为客户端主动发起TCP连接,子站(RTU/IED)作为服务器监听特定端口(默认端口为2404)。
  2. 启动APCI握手 :连接建立后,主站发送 STARTDT (Start Data Transfer)指令,子站确认后发送 STARTOK ,正式进入数据交换阶段。
  3. 数据传输 :通过APCI帧封装ASDU数据,进行遥测、遥信、遥控等信息的传输。
  4. 会话终止 :通信结束后,主站发送 STOPDT 指令,子站确认后断开连接。

以下是TCP连接建立和APCI握手的简化流程图:

sequenceDiagram
    participant Master as 主站
    participant Slave as 子站

    Master->>Slave: TCP连接请求(SYN)
    Slave-->>Master: TCP连接确认(SYN-ACK)
    Master->>Slave: TCP连接确认(ACK)
    Master->>Slave: STARTDT(APCI)
    Slave-->>Master: STARTOK(APCI)

代码示例:TCP连接与APCI握手的Python模拟

以下是一个简单的Python代码片段,模拟主站发起TCP连接并发送 STARTDT 指令的过程:

import socket

# 定义子站IP和端口
ip = "192.168.1.10"
port = 2404

# 创建TCP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接子站
sock.connect((ip, port))
print("已建立TCP连接")

# 构造STARTDT指令(APCI帧)
# APCI帧格式:0x68(起始符)+ 0x04(长度)+ 0x07(STARTDT)+ 0x00(保留)+ 0x00(保留)+ 0x00(保留)
apci_startdt = bytes([0x68, 0x04, 0x07, 0x00, 0x00, 0x00])

# 发送STARTDT指令
sock.send(apci_startdt)
print("已发送STARTDT指令")

# 接收子站的STARTOK响应
response = sock.recv(1024)
print("收到响应:", response.hex())

# 关闭连接
sock.close()
代码逻辑分析:
  • socket.socket() :创建TCP客户端Socket对象。
  • sock.connect() :主动连接到子站IP和端口2404。
  • apci_startdt :构造APCI帧,起始符为0x68,长度为0x04,控制域为0x07(表示STARTDT)。
  • sock.send() :发送APCI帧到子站。
  • sock.recv() :接收子站返回的STARTOK响应。
  • sock.close() :关闭TCP连接。

此代码模拟了104规约中TCP连接建立和APCI握手的基本流程,适用于理解协议在网络层和应用层的交互方式。

4.2 104规约的通信机制与会话管理

4.2.1 基于TCP的连接建立与维护

104规约基于TCP协议进行通信,因此其连接建立与维护机制完全依赖于TCP的可靠传输特性。TCP提供了面向连接的、有序的、可靠的字节流传输服务,这使得104规约在数据传输过程中具备了良好的稳定性和错误恢复能力。

在104规约中,主站通常作为TCP客户端主动发起连接,而子站作为服务器端监听2404端口。连接建立后,主站通过发送APCI帧控制会话状态,如 STARTDT STOPDT 等,来启动或终止数据传输。

为了保证连接的持续性,104规约还引入了 心跳机制 (Test Command)和 超时重传机制 ,以应对网络不稳定或设备异常断开的情况。

4.2.2 会话启动、数据交换与会话终止

104规约的通信过程可分为三个阶段:

  1. 会话启动阶段 :主站发送 STARTDT 指令,子站响应 STARTOK ,表示数据传输准备就绪。
  2. 数据交换阶段 :主站与子站之间通过APCI帧封装ASDU进行数据交互,包括遥测、遥信、遥控等信息。
  3. 会话终止阶段 :主站发送 STOPDT 指令,子站响应 STOPDTCONF ,随后关闭TCP连接。

以下是这三个阶段的典型交互流程:

sequenceDiagram
    participant Master
    participant Slave

    Master->>Slave: TCP连接建立
    Master->>Slave: STARTDT
    Slave-->>Master: STARTOK
    Master->>Slave: I-帧(ASDU数据)
    Slave-->>Master: S-帧(确认)
    Master->>Slave: STOPDT
    Slave-->>Master: STOPDTCONF
    Master->>Slave: TCP连接关闭
会话状态机示意

104规约定义了多个会话状态,包括:
- 未连接(Not Connected)
- 等待连接(Wait Connect)
- 等待STARTDT(Wait STARTDT)
- 运行中(Running)
- 等待STOPDT确认(Wait STOPDT Confirm)

状态之间的转换依赖于APCI帧的类型和通信状态。

4.3 104规约的数据传输模式与可靠性保障

4.3.1 无确认与有确认传输机制

104规约支持两种主要的数据传输机制:

  • 无确认传输(Unconfirmed Data Transfer) :适用于周期性上送的遥测、遥信数据,如总召唤(General Interrogation)响应。主站不期望收到确认帧。
  • 有确认传输(Confirmed Data Transfer) :适用于遥控、设点等关键操作,子站必须返回确认帧(S-帧)。

在无确认传输中,主站发送I-帧后不等待确认;而在有确认传输中,主站发送I-帧后需等待子站的S-帧确认,否则将触发超时重传。

4.3.2 序列号管理与数据顺序控制

104规约使用 发送序列号(Send Sequence Number, SN) 接收序列号(Receive Sequence Number, RN) 来管理数据帧的顺序和确认机制。每个I-帧都携带SN,接收方在S-帧中携带RN,用于确认已收到的数据帧。

例如:

帧类型 SN RN 说明
I-帧 1 0 主站发送第一个数据帧
S-帧 0 1 子站确认收到SN=1的数据帧
I-帧 2 1 主站发送第二个数据帧
S-帧 0 2 子站确认收到SN=2的数据帧

这种方式可以有效防止数据丢失和重复,确保数据传输的顺序性和完整性。

4.4 104规约的典型网络部署与配置实践

4.4.1 站控层与间隔层通信的部署方式

在典型的智能变电站中,104规约常用于 站控层(Station Control Level) 间隔层(Bay Level) 之间的通信。具体部署方式如下:

  • 站控层设备 (如SCADA系统、监控主机)作为主站,负责发起通信并接收数据。
  • 间隔层设备 (如保护测控装置、RTU)作为子站,监听TCP端口并响应主站请求。
  • 网络结构 通常采用以太网双网冗余结构,确保通信可靠性。

部署示意图如下:

graph TD
    A[SCADA主站] -- TCP连接 --> B(子站1)
    A -- TCP连接 --> C(子站2)
    A -- TCP连接 --> D(子站3)
    B -- GOOSE/MMS --> E(智能终端)
    C -- GOOSE/MMS --> F(保护装置)
    D -- GOOSE/MMS --> G(测控单元)

4.4.2 工程组网与协议配置实例

在实际工程中,配置104规约主要包括以下几个方面:

  1. IP地址配置 :为主站和子站分配固定IP地址。
  2. 端口设置 :子站监听2404端口。
  3. 心跳周期设置 :主站定期发送 TESTFR 指令检测连接状态。
  4. 超时与重传配置 :设置重传次数和超时时间,防止通信中断。
  5. ASDU地址映射 :定义遥测、遥信、遥控等数据的ASDU地址。
示例配置(基于IEC 60870-5-104配置文件):
[Master]
IP=192.168.1.1
Port=2404
Heartbeat=60s
Timeout=10s
Retries=3

[Slave]
IP=192.168.1.10
Port=2404
Listen=yes

[DataMapping]
ASDU_1=1-100    ; 遥测数据地址范围
ASDU_3=101-200  ; 遥信数据地址范围
ASDU_45=201-250 ; 遥控命令地址范围
说明:
  • Heartbeat=60s :每60秒发送一次测试帧,保持连接活跃。
  • Timeout=10s :每次发送请求后等待10秒响应,否则超时。
  • Retries=3 :失败重试3次后断开连接。
  • ASDU地址映射 :定义不同类型的ASDU数据对应的实际设备地址。

这种配置方式在实际项目中广泛使用,适用于变电站、调度中心等场景。

5. TCP连接建立与释放流程(三次握手/四次挥手)

TCP(Transmission Control Protocol)作为传输层的核心协议之一,以其面向连接、可靠传输和流量控制的特性,广泛应用于工业自动化通信中,尤其是在IEC 60870-5-104规约中,TCP连接的建立与释放是通信过程中的关键环节。本章将深入剖析TCP连接建立的三次握手流程与连接释放的四次挥手机制,结合状态机模型与异常处理机制,进一步探讨在104规约中的连接管理实践与工程调试经验。

5.1 TCP连接建立过程详解

TCP连接的建立是通过三次握手(Three-Way Handshake)来完成的。这个过程确保了通信双方都具备发送和接收能力,并为后续的数据传输建立同步状态。

5.1.1 三次握手的交互流程

三次握手过程如下图所示:

sequenceDiagram
    participant Client
    participant Server
    Client->>Server: SYN(seq=x)
    Server->>Client: SYN-ACK(seq=y, ack=x+1)
    Client->>Server: ACK(ack=y+1)
步骤详解:
  1. 客户端发送SYN段(同步标志位)
    - 客户端选择一个初始序列号 seq=x ,并将SYN标志位置1。
    - 此时客户端进入 SYN_SENT 状态。
    - 报文段不携带数据,但消耗一个序列号。

  2. 服务器响应SYN-ACK段
    - 服务器收到SYN后,回复SYN和ACK标志位为1的段。
    - 服务器选择自己的初始序列号 seq=y ,并将确认号设为 ack=x+1
    - 服务器进入 SYN_RCVD 状态。

  3. 客户端发送ACK段(确认标志位)
    - 客户端收到SYN-ACK后,发送ACK段,确认号为 ack=y+1
    - 此时连接建立完成,双方进入 ESTABLISHED 状态。

示例代码(使用Python的socket库模拟三次握手):
import socket

# 服务端代码
def server():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('0.0.0.0', 8888))
    s.listen(1)
    print("Server is listening...")
    conn, addr = s.accept()
    print(f"Connection from {addr}")
    conn.sendall(b"Hello Client")
    conn.close()

# 客户端代码
def client():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 8888))
    print("Connected to server")
    data = s.recv(1024)
    print("Received:", data.decode())
    s.close()

# 启动服务端和客户端
if __name__ == "__main__":
    import threading
    server_thread = threading.Thread(target=server)
    server_thread.start()
    client()
代码解析:
  • socket.socket(socket.AF_INET, socket.SOCK_STREAM) :创建TCP套接字。
  • s.listen(1) :监听连接请求,队列长度为1。
  • s.connect() :发起连接请求,触发三次握手。
  • s.recv() :接收数据,表示连接已建立。

5.1.2 握手失败与重传机制

TCP握手过程可能因网络丢包、服务器过载等原因失败。系统通常会设置超时机制并进行重传。

常见失败原因及处理机制:
故障类型 描述 处理机制
SYN丢包 客户端发送SYN未被服务器接收 客户端超时后重传SYN
SYN-ACK丢包 服务器回复SYN-ACK未被客户端接收 客户端未收到回复,超时重传SYN
ACK丢包 客户端发送ACK未被服务器接收 服务器未收到ACK,超时重传SYN-ACK

TCP协议中,重传次数由系统内核参数控制,例如Linux中可通过 /proc/sys/net/ipv4/tcp_syn_retries 设置SYN重试次数。

5.2 TCP连接释放过程详解

TCP连接的释放是通过四次挥手(Four-Way Handshake)来完成的。这个过程确保了双方都能确认数据传输的结束,并释放资源。

5.2.1 四次挥手的交互流程

sequenceDiagram
    participant Client
    participant Server
    Client->>Server: FIN
    Server->>Client: ACK
    Server->>Client: FIN
    Client->>Server: ACK
步骤详解:
  1. 客户端发送FIN段
    - 客户端发送FIN标志位为1的段,表示不再发送数据。
    - 客户端进入 FIN-WAIT-1 状态。

  2. 服务器回应ACK段
    - 服务器收到FIN后,发送ACK段进行确认。
    - 服务器进入 CLOSE-WAIT 状态;客户端进入 FIN-WAIT-2 状态。

  3. 服务器发送FIN段
    - 服务器完成数据发送后,发送FIN段。
    - 服务器进入 LAST-ACK 状态。

  4. 客户端发送ACK段
    - 客户端收到FIN后,发送ACK段进行确认。
    - 客户端进入 TIME-WAIT 状态,等待2MSL(Maximum Segment Lifetime)后关闭连接。

示例代码(模拟四次挥手):
def client_shutdown():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 8888))
    print("Connected to server")
    s.sendall(b"Close connection")
    s.shutdown(socket.SHUT_WR)  # 发送FIN
    data = s.recv(1024)
    print("Received:", data.decode())
    s.close()
代码解析:
  • s.shutdown(socket.SHUT_WR) :关闭写通道,触发FIN段发送。
  • s.recv() :等待服务器响应数据或FIN。
  • s.close() :关闭连接,释放资源。

5.2.2 半关闭与连接复用机制

TCP支持“半关闭”机制,即一方关闭写通道,但仍可接收数据。这对于104规约中“单向数据上传”场景非常有用。

半关闭流程图:
graph LR
    A[Client] --> B[Server]
    A -- FIN --> B
    B -- ACK --> A
    B -- 数据传输 --> A
    B -- FIN --> A
    A -- ACK --> B
连接复用机制:
  • TCP连接建立后可重复用于多次数据传输,减少握手开销。
  • 在104规约中,连接复用是提高通信效率的重要手段。

5.3 TCP状态转换与异常处理

TCP协议定义了多个状态,用于表示连接生命周期中的不同阶段。理解状态转换有助于调试连接问题。

5.3.1 各种TCP状态的含义与转换路径

状态 含义
LISTEN 监听来自客户端的连接请求
SYN_SENT 客户端发送SYN后等待服务器确认
SYN_RCVD 服务器收到SYN后发送SYN-ACK等待客户端确认
ESTABLISHED 连接已建立,可进行数据传输
FIN-WAIT-1 客户端发送FIN后等待服务器ACK
FIN-WAIT-2 客户端收到ACK后等待服务器FIN
CLOSE-WAIT 服务器收到FIN后等待本地关闭
LAST-ACK 服务器发送FIN后等待客户端ACK
CLOSING 双方同时发送FIN
TIME-WAIT 客户端发送ACK后等待2MSL释放连接
CLOSED 连接已关闭
状态转换图(部分):
stateDiagram
    [*] --> LISTEN
    LISTEN --> SYN_RCVD: 收到SYN
    LISTEN --> SYN_SENT: 主动连接
    SYN_SENT --> SYN_RCVD: 收到SYN
    SYN_SENT --> ESTABLISHED: 收到SYN-ACK
    SYN_RCVD --> ESTABLISHED: 收到ACK
    ESTABLISHED --> FIN_WAIT_1: 发送FIN
    FIN_WAIT_1 --> FIN_WAIT_2: 收到ACK
    FIN_WAIT_2 --> TIME_WAIT: 收到FIN
    TIME_WAIT --> CLOSED: 2MSL超时

5.3.2 异常断连与恢复机制

常见异常场景:
异常类型 表现 恢复机制
网络中断 连接无响应 心跳机制检测断连,重新连接
应用崩溃 未发送FIN直接断开 客户端检测到连接断开,自动重连
超时未响应 ACK/FIN未收到 设置超时重传机制
端口占用 连接建立失败 释放端口或更换端口号
恢复机制实现建议:
  • 使用心跳包(Heartbeat)定期检测连接状态。
  • 设置连接超时时间(如30秒),超时后主动重连。
  • 记录连接状态日志,便于调试与分析。

5.4 在104规约中的TCP连接管理实践

IEC 60870-5-104规约基于TCP/IP协议栈,因此其连接管理必须遵循TCP规范,同时结合规约自身特点进行优化。

5.4.1 连接超时与心跳机制的配置

心跳机制配置示例(C语言):
// 心跳包发送函数
void send_heartbeat(int sockfd) {
    char heartbeat[] = {0x68, 0x04, 0x07, 0x00, 0x00, 0x00}; // U帧心跳包
    send(sockfd, heartbeat, sizeof(heartbeat), 0);
}

// 定时器触发心跳发送
void *heartbeat_thread(void *arg) {
    int sockfd = *(int *)arg;
    while (1) {
        send_heartbeat(sockfd);
        sleep(30); // 每30秒发送一次心跳
    }
}
参数说明:
  • heartbeat[] :U帧格式的心跳报文,符合104规约U帧结构。
  • send() :发送心跳包。
  • sleep(30) :每30秒发送一次,防止连接空闲超时。

5.4.2 工程案例分析与调试经验分享

案例1:连接频繁断开

现象 :连接建立后不久即断开,无明显数据传输。

分析
- 检查心跳包是否正常发送。
- 检查TCP Keepalive设置是否启用。
- 查看防火墙是否阻断连接。

解决方法
- 启用系统级Keepalive: net.ipv4.tcp_keepalive_time=300
- 调整心跳间隔,缩短为15秒。
- 检查中间设备(如交换机、防火墙)配置。

案例2:连接建立失败

现象 :客户端无法连接到服务器,返回连接超时。

分析
- 检查IP地址与端口号是否正确。
- 检查服务器是否启动并监听端口。
- 使用Wireshark抓包分析SYN是否到达服务器。

解决方法
- 使用 netstat -antp | grep 8888 检查端口监听状态。
- 使用 tcpdump 抓包确认SYN是否到达。
- 检查服务器防火墙规则,是否允许入站连接。

通过本章的深入分析,我们系统性地掌握了TCP连接的建立与释放机制,理解了状态转换逻辑与异常处理策略,并结合104规约的实际应用,提供了连接管理的工程实践与调试经验。这些内容对于深入理解工业自动化通信协议、优化网络连接性能具有重要意义。

6. ASDU与TCPU的构建与拆解

6.1 ASDU数据单元的结构与组成

6.1.1 应用服务数据单元的基本格式

在IEC 60870-5-101/104规约中,ASDU(Application Service Data Unit,应用服务数据单元)是应用层的核心数据结构,用于承载遥测、遥信、遥控等信息。ASDU的基本格式如下:

| 类型标识(TYP) | 可变结构限定词(VSQ) | 传送原因(COT) | 公共地址(ADDR) | 信息对象地址(OA) | 信息元素(INF) |
  • 类型标识(TYP) :定义信息体的类型和结构,如单点遥信、双点遥信、浮点遥测等。
  • 可变结构限定词(VSQ) :用于指示信息对象的数量及地址是否连续。
  • 传送原因(Cause of Transmission, COT) :指示报文发送的原因,如周期上送、变位上送、总召等。
  • 公共地址(ADDR) :标识设备或站的地址,用于多站通信时的区分。
  • 信息对象地址(OA) :信息对象的起始地址。
  • 信息元素(INF) :具体的数据内容,如遥测值、状态位等。

6.1.2 类型标识、可变结构限定词与信息体的组成

以类型标识 M_ME_NA_1 (浮点遥测,无品质描述)为例,其典型结构如下:

字段 长度(字节) 说明
TYP 1 类型标识为 0x0D
VSQ 1 例如:0x01 表示一个信息对象,地址连续
COT 1 例如:0x03 表示总召唤
ADDR 2 站地址,例如 0x00 0x01
OA 3 信息对象地址,例如 0x00 0x00 0x01
INF 4 浮点数数据,如 0x42 0x48 0x00 0x00 表示 50.0

6.2 ASDU的构建与编码方法

6.2.1 信息对象的组装与序列化

ASDU的构建流程如下:

  1. 确定类型标识 :根据数据类型选择合适的TYP值。
  2. 构造VSQ字段 :设定信息对象数量与地址连续性。
  3. 设置COT与ADDR :根据通信上下文设定传送原因和站地址。
  4. 生成信息对象地址 :根据数据点的地址生成OA字段。
  5. 填充信息元素 :将遥测值、状态等数据按规约格式进行编码。

以下是一个构建ASDU的Python伪代码示例:

def build_asdu(type_id, vsq, cot, station_addr, obj_addr, data):
    asdu = bytearray()
    asdu.append(type_id)                # 类型标识
    asdu.append(vsq)                    # 可变结构限定词
    asdu.append(cot)                    # 传送原因
    asdu.extend(station_addr.to_bytes(2, 'little'))  # 站地址
    asdu.extend(obj_addr.to_bytes(3, 'little'))      # 信息对象地址
    asdu.extend(data)                   # 数据内容
    return asdu

6.2.2 时间戳与品质字段的填充方法

某些ASDU类型(如带时标的信息体)需要添加时间戳和品质字段。例如, M_SP_TB_1 (带时间标签的单点信息)包含:

| 类型标识 | VSQ | COT | 地址 | 时间戳(7字节) | 品质描述(1字节) |

时间戳格式为 CP56Time2a ,表示从1970年1月1日00:00:00 UTC到当前时间的毫秒数,采用6字节+1字节的结构。

def add_timestamp(asdu, timestamp_ms):
    # timestamp_ms: 毫秒时间戳
    ts_bytes = timestamp_ms.to_bytes(6, 'little') + b'\x00'
    asdu.extend(ts_bytes)

品质字段用于描述数据的可信度,例如:

含义
0 有效位(0=有效,1=无效)
1 替代值位
2 测试位
3 被封锁位
def add_quality(asdu, quality):
    asdu.append(quality)  # 品质字节

6.3 TCPU协议数据单元的封装与传输

6.3.1 TCP/UDP与IP协议头的构建

在IEC 60870-5-104中,APDU(应用协议数据单元)通过TCP进行传输。完整的TCPU结构包括:

| TCP头 | IP头 | 以太网头 | APDU数据 |
  • TCP头 :包含源端口、目标端口、序列号、确认号等。
  • IP头 :包含源IP、目标IP、协议类型等。
  • 以太网头 :包含源MAC、目标MAC、类型字段(如0x0800表示IP)。

使用Python构建一个基本的TCP/IP头部示例如下:

import socket
import struct

def build_ip_header(src_ip, dst_ip):
    ip_ihl = 5
    ip_ver = 4
    ip_tos = 0
    ip_tot_len = 0  # kernel will fill the correct value
    ip_id = socket.htons(54321)
    ip_frag_off = 0
    ip_ttl = 255
    ip_proto = socket.IPPROTO_TCP
    ip_check = 0
    ip_saddr = socket.inet_aton(src_ip)
    ip_daddr = socket.inet_aton(dst_ip)

    ip_ihl_ver = (ip_ver << 4) + ip_ihl
    return struct.pack('!BBHHHBBH4s4s', ip_ihl_ver, ip_tos, ip_tot_len, ip_id,
                       ip_frag_off, ip_ttl, ip_proto, ip_check, ip_saddr, ip_daddr)

6.3.2 APDU在TCP中的封装方式

APDU在TCP中的封装过程如下:

  1. 构建ASDU数据。
  2. 添加应用协议控制信息(APCI)形成APDU。
  3. 将APDU作为TCP负载进行封装。
  4. 通过socket发送TCP/IP数据包。

APCI包括:

  • 启动字符 :0x68(固定长度为4字节的开始标志)
  • 长度字段 :后续字节数
  • 控制字段 :I、S、U帧的控制信息
def build_apdu(asdu_data):
    apci = b'\x68' + bytes([len(asdu_data)]) + b'\x00\x00'  # 简化处理
    apdu = apci + asdu_data
    return apdu

6.4 报文的解码与完整性校验

6.4.1 报文分片重组与校验流程

在TCP传输中,APDU可能被分片传输。接收端需:

  1. 接收TCP数据流。
  2. 提取APDU长度字段。
  3. 持续接收直到完整APDU接收完成。
  4. 提取ASDU部分并进行解析。

分片重组流程如下:

graph TD
    A[开始接收TCP数据] --> B{是否收到完整APDU?}
    B -->|是| C[提取APDU并解析]
    B -->|否| D[缓存已有数据]
    D --> E[继续接收下一段]
    E --> B

6.4.2 CRC校验与错误恢复机制的实现

虽然IEC 104使用TCP进行传输,但在某些底层链路(如101)中仍需CRC校验。CRC16-CCITT算法如下:

def crc16_ccitt(data):
    crc = 0xFFFF
    for byte in data:
        crc ^= (byte << 8)
        for _ in range(8):
            if crc & 0x8000:
                crc = (crc << 1) ^ 0x1021
            else:
                crc <<= 1
    return crc & 0xFFFF

接收端在接收到数据后,应重新计算CRC并与报文中的CRC值进行比对。若不一致,则丢弃该帧并请求重传。

下一章节将深入讨论IEC 104规约中的应用服务数据单元(ASDU)在不同控制类型下的交互逻辑与实现方式。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在电力自动化系统中,101和104规约是实现设备远程通信的关键协议,广泛应用于SCADA系统中。101规约基于串行通信,适用于主站与RTU之间的数据交互;而104规约基于TCP/IP,更适合现代网络环境。本文详细介绍了101和104规约的基本结构、帧格式及解析流程,并深入解析104规约的源码实现,包括TCP连接管理、ASDU与TCPU结构、序列号控制、错误检测与恢复机制等内容。通过学习规约源码,有助于提升电力系统通信的稳定性与开发调试效率。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值