JAVA IEC104

使用JAVA写了一个程序做为客户端,用软件创建一个服务端,可以正常接收数据。但是连接非本地的ip端口的时候,程序连接成功的,就是监听不到任何数据。,但是用软件客户端连接这个非本地ip端口 可以接收到数据 ,这是为什么,大家有遇到过这种问题吗

package com.vcom.iec104.client;

import com.vcom.config.IEC104Config;
import com.vcom.config.OpProperties;
import com.vcom.config.TaskConfig;
import lombok.extern.slf4j.Slf4j;
import org.openmuc.j60870.ClientConnectionBuilder;
import org.openmuc.j60870.Connection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.InetAddress;
import java.util.concurrent.TimeUnit;

/**
 * IEC104 启动类
 */
@Component
@Slf4j
public class J60870Client implements Runnable {

    //监听类
    private J60870ClientListener2404 listener2404;
    private J60870ClientListener2405 listener2405;
    private J60870ClientListener2406 listener2406;
    private J60870ClientListener2407 listener2407;
    private J60870ClientListener2408 listener2408;

    @Autowired
    private IEC104Config cfg;

    //连接类
    private Connection connection;
    //连接参数
    private ClientConnectionBuilder clientConnectionBuilder;

    private volatile boolean running = true;

    private static final int MAX_RETRY = 5;
    private static final long MAX_BACKOFF = 10000; // 设置最大重试间隔为10秒

    private static final String ip = "";

    private static final Integer[] ports = {2404,2405,2406,2407,2408};

    public J60870Client() {
        if (!TaskConfig.isEnableIEC()){
            return;
        }
        try {
            //获取server端、从站的ip地址对象,这里使用本地ip
            InetAddress address = InetAddress.getByName(ip);
            //创建连接参数对象
            clientConnectionBuilder = new ClientConnectionBuilder(address);
            //设置socket的连接超时时间
            clientConnectionBuilder.setConnectionTimeout(60000);
            for (int i = 0; i < ports.length; i++) {
                if (!establishConnectionForPort(ports[i])) {
                    // 所有重试失败后,可以选择在此处记录或处理
                    log.error("所有重试失败,无法连接端口: {}", ports[i]);
                    // 可能需要考虑是否继续尝试其他端口,或者直接退出循环
                } else {
                    log.info("启动IEC104端口:{}", ports[i]);
                }
            }
        } catch (Exception e) {
            log.error("初始化 J60870 客户端失败: {}", e.getMessage());
            throw new RuntimeException("初始化 J60870 客户端失败", e);
        }
    }

    private boolean establishConnectionForPort(Integer port) {
        clientConnectionBuilder.setPort(port);
        for (int retryCount = 0; running && retryCount < MAX_RETRY; retryCount++) {
            try {
                connection = clientConnectionBuilder.build();
                //区分监听数据
                switch (port){
                    case 2404:
                        listener2404 = new J60870ClientListener2404();
                        connection.startDataTransfer(listener2404);
                        break;
                    case 2405:
                        listener2405 = new J60870ClientListener2405();
                        connection.startDataTransfer(listener2405);
                        break;
                    case 2406:
                        listener2406 = new J60870ClientListener2406();
                        connection.startDataTransfer(listener2406);
                        break;
                    case 2407:
                        listener2407 = new J60870ClientListener2407();
                        connection.startDataTransfer(listener2407);
                        break;
                    case 2408:
                        listener2408 = new J60870ClientListener2408();
                        connection.startDataTransfer(listener2408);
                        break;
                }
                log.info("连接到端口 {} 成功!", port);
                return true; // 连接成功
            } catch (IOException e) {
                log.error("连接到端口 {} 异常: {}", port, e.getMessage());
                if (!retryWithBackoff(retryCount, port)) {
                    // 如果重试策略决定停止重试,则返回false
                    return false;
                }
            }
        }
        return false; // 所有重试均失败
    }

    private boolean retryWithBackoff(int retryCount, Integer port) {
        long backoff = calculateBackoff(retryCount);
        if (backoff > MAX_BACKOFF) {
            backoff = MAX_BACKOFF; // 限制最大重试间隔
        }
        log.info("端口 {} 将在 {} 秒后重试连接...", port, TimeUnit.MILLISECONDS.toSeconds(backoff));
        try {
            Thread.sleep(backoff);
        } catch (InterruptedException ex) {
            log.error("连接到端口 {} 的重试线程被中断", port, ex);
            Thread.currentThread().interrupt(); // 保留中断状态
            return false; // 停止重试
        }
        return true; // 继续重试
    }

    private long calculateBackoff(int retryCount) {
        return Math.min((long) Math.pow(2, retryCount) * 1000, MAX_BACKOFF); // 指数退避,限制最大值
    }

    //关闭连接
    public void disconnect() {
        running = false;
        try {
            if (connection != null) {
                connection.close();
                log.info("关闭104连接成功");
            }
        } catch (Exception e) {
            log.error("关闭连接时发生异常: {}", e.getMessage());
        }
    }

    @Override
    public void run() {

    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值