1

我正在使用 JSSC 串行端口包在我的应用程序和连接到串行端口的设备之间交换数据。我做了一个简单的应用程序,它可以向设备发送识别消息并打印响应。我希望它能够抵抗连接错误(例如在通信期间拔下电缆后)。

操作顺序 Init -> Open -> IDN -> Close 完美运行。打开端口后拔下电缆时,我无法发送消息(对我来说似乎合乎逻辑)并关闭端口(不再需要关闭任何东西,所以我也明白这一点)。

一开始我很惊讶在再次插入电缆后我无法关闭端口,但我发现在每次连接设备后,操作系统都会给它一个不同的编号,JSSC 库使用它来处理端口。幸运的是,事实证明,在重新连接后简单地打开端口就可以解决所有问题,因为应用程序可以再次发送消息。

不幸的是,当端口打开时有更多尝试断开/连接电缆时,问题就开始了。每次尝试后,应用程序的运行速度越来越慢,最终以无法再发送消息的状态结束。另一件事是,在这种状态下,所有串行端口(不仅是我尝试与之通信的那个)都被阻止,我什至无法通过类似终端的应用程序访问它们。

所以问题是:

如何使应用程序能够抵抗连接中断而不阻塞端口和失去性能?

我想这可能与某种资源、内存管理等有关,但我对这些东西的了解不足以自己解决问题。

沟通的实施:

import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;

class Connection implements SerialPortEventListener {
  private static final int SERIAL_PORT_BAUD_RATE = 9600;
  private static final int SERIAL_PORT_DATA_BITS_NUMBER = 8;
  private static final int SERIAL_PORT_STOP_BITS_NUMBER = 1;
  private static final int SERIAL_PORT_PARITY = 0;

  private SerialPort serialPort;
  private String portName;

  public Connection(String portName) {
    this.portName = portName;
  }

  public void open() throws SerialPortException {
    serialPort = new SerialPort(portName);
    serialPort.openPort();
    serialPort.setParams(SERIAL_PORT_BAUD_RATE,
            SERIAL_PORT_DATA_BITS_NUMBER,
            SERIAL_PORT_STOP_BITS_NUMBER,
            SERIAL_PORT_PARITY);
    serialPort.addEventListener(this);
  }

  public void close() throws SerialPortException {
    if (serialPort != null) {
      serialPort.closePort();
    }
  }

  public void simpleMessage() throws SerialPortException {
    if (serialPort != null) {
      serialPort.writeString("IDN");
    }
  }

  @Override
  public void serialEvent(SerialPortEvent serialPortEvent) {
    if (serialPortEvent.getEventType() == SerialPortEvent.RXCHAR) {
      try {
        System.out.println(serialPort.readString());
      } catch (SerialPortException e) {
        System.out.println("Error while reading a string.");
      }
    }
  }
}

主类:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.IOException;

public class MainApplication extends Application{
  public static void main(String [] args) {
    Application.launch();
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
    Pane rootPane = null;
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(MainApplication.class.getResource("front.fxml"));

    try{
      rootPane = loader.load();
    } catch (IOException exception) {
      exception.printStackTrace();
    }

    Scene scene = new Scene(rootPane);
    primaryStage.setScene(scene);
    primaryStage.show();
    primaryStage.setOnCloseRequest(event -> {
      Platform.exit();
      System.exit(0);
    });
  }
}

FXML 代码:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<StackPane fx:id="rootPane"
           xmlns="http://javafx.com/javafx/8.0.60"
           xmlns:fx="http://javafx.com/fxml/1"
           fx:controller="FrontController">
    <VBox>
        <Button text="Init" onAction="#init"/>
        <Button text="Open" onAction="#openPort"/>
        <Button text="Close" onAction="#closePort"/>
        <Button text="IDN" onAction="#idn"/>
        <Button text="Get Ports" onAction="#getPorts"/>
        <Button text="Is opened?" onAction="#isPortOpen"/>
    </VBox>
</StackPane>

控制器:

import javafx.fxml.FXML;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.util.Arrays;

public class FrontController {

  private Connection connection;

  @FXML
  private void init() {
    String portName = "COM4";
    connection = new Connection(portName);
  }

  @FXML
  private void openPort() {
    try {
      connection.open();
    } catch (SerialPortException e) {
      e.printStackTrace();
    }
  }

  @FXML
  private void closePort() {
    try {
      connection.close();
    } catch (SerialPortException e) {
      e.printStackTrace();
    }
  }

  @FXML
  private void idn() {
    try {
      connection.idnMessage();
    } catch (SerialPortException e) {
      e.printStackTrace();
    }
  }

  @FXML
  private void getPorts() {
    System.out.println(Arrays.toString(SerialPortList.getPortNames()));
  }

  @FXML
  private void isPortOpen() {
    System.out.println(connection.getSerialPort().isOpened());
  }
}
4

1 回答 1

0

基本上在不关闭的情况下拔出设备(实际上大多数情况下在 Windows 操作系统中)会使操作系统处于不一致的状态。移除设备后,您需要进行清理。请注意,即使设备已被移除,关闭端口也非常重要。我们可以留下close的返回值。这向操作系统提示应用程序对设备也不感兴趣,因此操作系统可以自由释放我们也想要的资源。所以简而言之,我们需要创建一个线程来监控我们的设备是否连接到系统。

于 2017-12-04T06:37:07.333 回答