# 前言

前段时间在研究 IEC 60870-5-104规约,是一个广泛应用于电力、城市轨道交通等行业的国际标准。一般的使用场景是这样的:

  1. 主站和RTU之间使用 IEC 60870-5-104 规约进行通信,采用网络传输层的可靠传输协议TCP。
  2. 主站和从站处于同一局域网。
  3. 主站(控制侧)为TCP客户端,RTU(被控制端)为服务器端,即主站主动进行TCP连接,而RTU被动响应TCP连接。

# 需求

现应客户需求,RTU即服务器端放在局域网内,而主站即客户端要放在公网上。这样就存在一个问题,处在公网的客户端无法主动连接处于内网的服务器端(局域网IP的限制)。

# 引导

客户在IEC104使用方面有更丰富的经验,给我了点提示,让RTU先以客户端的身份去主动连接处在公网的服务器端(这时主站那边也不在担任客户端的角色的,因为它等待着被RTU连接,转而担任服务器端的角色),然后服务器端再通过这个连接,去继续IEC104规约的通信。

# 实现

只改了一行代码:Socket替换。

原始RTU代码(等待客户端连接部分)

Socket
ServerSocket_accept(ServerSocket self)
{
    int fd;

    Socket conSocket = NULL;

    fd = accept(self->fd, NULL, NULL );

    if (fd >= 0) {
        conSocket = TcpSocket_create();
        conSocket->fd = fd;

        activateTcpNoDelay(conSocket);
    }

    return conSocket;
}

代码修改(Socket替换)

Socket
ServerSocket_accept(ServerSocket self)
{
    int fd;

    Socket conSocket = NULL;

    // fd = accept(self->fd, NULL, NULL );
    fd = sockfd;	// sockfd为上一步RTU作为客户端客户端连接公网服务器的socket,
    			// 直接将此socket当作是从accept分配的socket,
    			// 服务端(公网TCP服务端)和服务端(局域网IEC104服务端)就能够
    			// 通过此socket进行互相通信了。

    if (fd >= 0) {
        conSocket = TcpSocket_create();
        conSocket->fd = fd;

        activateTcpNoDelay(conSocket);
    }

    return conSocket;
}

# 服务端和服务端通信

以上,利用TCP客户端的通信套接字,充当IEC104 Server部分通信套接字,从而达到服务端和服务端通信的目的。