123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- package com.ruoyi.sim.service.impl;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.sim.config.SimConfig;
- import com.ruoyi.sim.config.SimDebugConfig;
- import com.ruoyi.sim.domain.Seat;
- import com.ruoyi.sim.domain.vo.SimSocketParamVo;
- import com.ruoyi.sim.domain.vo.SocketWrapCacheVo;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.core.parameters.P;
- import org.springframework.stereotype.Service;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.util.HashMap;
- import java.util.List;
- import java.util.concurrent.atomic.AtomicInteger;
- import static com.ruoyi.sim.constant.CommConst.SOCKET_TIME_OUT;
- /**
- * 1.所有Socket常开。
- * todo: connectedTimeMillis 时间。
- * <p>
- * 创建Socket重试,用failed开始方法去操作。
- */
- @Service
- public class SocketService {
- private static final Logger l = LoggerFactory.getLogger(SocketService.class);
- /**
- * 硬件孙总北京办公室,测试远程地址
- * <p>
- * 孙总办公室域名
- * nas.yichiot.com
- */
- public static final String IP_TEST = "221.218.215.73";
- public static final int PORT_TEST = 8899;
- private static final int LOCAL_PORT = 9000;
- private static final int INIT_SIZE = 32;
- /**
- * 6 hours
- * 1000L * 60 * 60 * 6
- * 1000L * 60 * 5
- */
- private static final long TIMEOUT_LIMIT = 1000L * 60 * 60 * 6;
- public static final int SOCKET_CONNECT_RETRY_COUNT_LIMIT = 4;
- /**
- * key: ip:port
- * value:
- */
- private static HashMap<String, SocketWrapCacheVo> cachedMap = new HashMap<>(INIT_SIZE);
- /**
- * 每个Socket都有。
- * 重试次数。
- * default 0.
- */
- private static HashMap<String, AtomicInteger> failedMap = new HashMap<>(INIT_SIZE);
- @Autowired
- private SimConfig config;
- @Autowired
- private SeatService seatService;
- /**
- * @param sspv
- * @return true:socket ok!
- */
- public boolean isOk(final SimSocketParamVo sspv) {
- final String key = sspv.toKey();
- if (cachedMap.containsKey(key) && cachedMap.get(key) != null) {
- Socket s = cachedMap.get(key).getSocket();
- if (s != null) {
- return (s.isConnected() && s.isBound() && !s.isClosed());
- }
- }
- return false;
- }
- public boolean isNotOk(final SimSocketParamVo sspv) {
- return !isOk(sspv);
- }
- /**
- * 暂时不考虑超时周期。
- * todo:
- *
- * @param ssv
- * @return
- */
- public boolean isTimeout(SimSocketParamVo ssv) {
- if (cachedMap.containsKey(ssv.toKey())) {
- Long cached = cachedMap.get(ssv.toKey()).getOkTimeMillis();
- if (cached == null || cached == 0L) {
- return true;
- }
- return System.currentTimeMillis() - cached <= TIMEOUT_LIMIT;
- }
- return true;
- }
- /**
- * @param sspv
- * @param force 是否强制使用新连接的Socket
- * @return
- */
- public AjaxResult openOne(final SimSocketParamVo sspv, final boolean force) {
- // check.
- if (!config.isCommGlobal()) {
- l.warn("isCommGlobal == {} [模拟器通信被禁用!]", config.isCommGlobal());
- return AjaxResult.error("模拟器通信被禁用!");
- }
- //
- try {
- if (isNotOk(sspv) || force) {
- final String key = sspv.toKey();
- l.info("openSocket cachedSocket is not ok!try new socket ip = {}:{}!forceNew = {}", sspv.getIp(), sspv.getPort(), force);
- closeOne(sspv, false);
- // 不指定本地端口实现。
- Socket s = new Socket(sspv.getIp(), sspv.getPort());
- // todo: LOCAL_PORT
- // Socket s = new Socket(sspv.getIp(), sspv.getPort(), InetAddress.getLocalHost(), SimDebugConfig.TCP_LOCAL_PORT);
- s.setSoTimeout(SOCKET_TIME_OUT);
- SocketWrapCacheVo value = new SocketWrapCacheVo(sspv.getIp(), sspv.getPort(), s, System.currentTimeMillis());
- // 新建Socket需要挂起 2s后再发指令。
- value.setPreviousSendSleep(2000L);
- cachedMap.put(key, value);
- // socket failed count reset.
- failedReset0(sspv);
- } else {
- l.info("openSocket cachedSocket cache ok!cached socket ip = {}:{}!forceNew = {}", sspv.getIp(), sspv.getPort(), force);
- }
- Seat seat = seatService.uniqueByRs485IpAndPort(sspv.getIp(), sspv.getPort());
- seat.setSeatRs485SocketState(Seat.SocketState.ONLINE);
- seatService.updateSeat(seat);
- return AjaxResult.success("Socket[" + sspv.getIp() + ":" + sspv.getPort() + "],创建成功!");
- } catch (IOException e) {
- l.error("IOException = {}", sspv);
- if (failedIsReachedMax(sspv, SOCKET_CONNECT_RETRY_COUNT_LIMIT)) {
- return AjaxResult.error("Socket[" + sspv.getIp() + ":" + sspv.getPort() + "],重试[" + failedGet(sspv) + "]次,创建失败!");
- } else {
- failedPlus1(sspv);
- AjaxResult ar = openOne(sspv, force);
- if (ar.isSuccess()) {
- return ar;
- } else {
- return AjaxResult.error("Socket[" + sspv.getIp() + ":" + sspv.getPort() + "],进行重试,创建失败!");
- }
- }
- }
- }
- public AjaxResult tryOpenOne(final SimSocketParamVo sspv) {
- if (!config.isCommGlobal()) {
- l.warn("isCommGlobal == {} [模拟器通信被禁用!]", config.isCommGlobal());
- return AjaxResult.error("模拟器通信被禁用!");
- }
- return openOne(sspv, false);
- }
- /**
- * todo:部分返回Aj结果。
- *
- * @return
- */
- public AjaxResult tryOpenAll() {
- if (!config.isCommGlobal()) {
- l.warn("isCommGlobal == {} [模拟器通信被禁用!]", config.isCommGlobal());
- return AjaxResult.error("模拟器通信被禁用!");
- }
- List<Seat> allSeat = seatService.listAllEnable();
- for (Seat s : allSeat) {
- AjaxResult ar = openOne(s.toSimSocketParamVo(), false);
- l.debug("AjaxResult = {}", ar);
- }
- return AjaxResult.success("所有Socket,创建成功!");
- }
- public AjaxResult closeOne(final SimSocketParamVo sspv, boolean failedReset) {
- if (!config.isCommGlobal()) {
- l.warn("isCommGlobal == {} [模拟器通信被禁用!]", config.isCommGlobal());
- return AjaxResult.error("模拟器通信被禁用!");
- }
- final String key = sspv.toKey();
- try {
- if (cachedMap.containsKey(key)) {
- Socket s = cachedMap.get(key).getSocket();
- s.getInputStream().close();
- s.getOutputStream().close();
- s.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (failedReset) {
- // failed count reset.
- failedReset0(sspv);
- }
- cachedMap.remove(key);
- return AjaxResult.success("关闭Socket成功!");
- }
- }
- public AjaxResult closeAll() {
- if (!config.isCommGlobal()) {
- l.warn("isCommGlobal == {} [模拟器通信被禁用!]", config.isCommGlobal());
- return AjaxResult.error("模拟器通信被禁用!");
- }
- final String msgOk = "关闭所有Socket成功!";
- List<Seat> allSeat = seatService.listAllEnable();
- for (Seat s : allSeat) {
- closeOne(new SimSocketParamVo(s.getSeatRs485Ip(), s.getSeatRs485Port()), true);
- }
- return AjaxResult.success(msgOk);
- }
- /**
- * @param seat
- * @return todo:null
- */
- public SocketWrapCacheVo get(final Seat seat) {
- if (seat == null) {
- throw new IllegalArgumentException("seat为空。");
- }
- return get(new SimSocketParamVo(seat.getSeatRs485Ip(), seat.getSeatRs485Port()));
- }
- /**
- * @param sspv
- * @return
- */
- public SocketWrapCacheVo get(final SimSocketParamVo sspv) {
- if (isNotOk(sspv)) {
- AjaxResult ar = openOne(sspv, true);
- if (ar.isError()) {
- // todo: isError
- }
- }
- return cachedMap.get(sspv.toKey());
- }
- /**
- * 初始化。todo:
- */
- public void clear(final SimSocketParamVo sspv) {
- }
- private static final int SOCKET_FAILED_COUNT_0 = 0;
- private static final int SOCKET_FAILED_COUNT_ADD_1 = 1;
- /**
- * @param sspv
- * @param limit include limit
- * @return
- */
- public boolean failedIsReachedMax(final SimSocketParamVo sspv, final int limit) {
- final String key = sspv.toKey();
- return (failedMap.containsKey(key) && failedMap.get(key).get() >= limit);
- }
- public int failedPlus1(final SimSocketParamVo sspv) {
- final String key = sspv.toKey();
- if (!failedMap.containsKey(key)) {
- failedMap.put(key, new AtomicInteger(SOCKET_FAILED_COUNT_ADD_1));
- } else {
- failedMap.get(key).addAndGet(SOCKET_FAILED_COUNT_ADD_1);
- }
- return failedMap.get(key).get();
- }
- public int failedGet(final SimSocketParamVo sspv) {
- final String key = sspv.toKey();
- if (failedMap.containsKey(key)) {
- return failedMap.get(key).get();
- } else {
- return SOCKET_FAILED_COUNT_0;
- }
- }
- public void failedReset0(final SimSocketParamVo sspv) {
- final String key = sspv.toKey();
- if (failedMap.containsKey(key)) {
- failedMap.get(key).set(SOCKET_FAILED_COUNT_0);
- } else {
- l.debug("not containsKey SimSocketParamVo sspv:" + sspv);
- }
- }
- }
|