我正在开发一个JavaFX项目,我使用socket(java.net.Socket)API从连接到网络的设备获取数据。我面临两个主要问题。第一个问题是我无法终止任务。 if中的一个FetchTask块中的代码永远不会被执行。
if(Thread.currentThread().isInterrupted()){
System.out.println("i am breaking out");
break;
}
第二个问题是我无法关闭套接字。如果我首先关闭BufferReadeader然后关闭套接字,UI会冻结,但是如果我选择先关闭套接字然后关闭bufferReader,那么我会得到以下异常。
java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at connector.FetchTask.call(FetchTask.java:52)
at connector.FetchTask.call(FetchTask.java:14)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:748)
这是我的完整控制器代码 - >
public class ControllerDbase implements Initializable{
@FXML
private TableView dataTable;
@FXML
private TableColumn dataTable_Column;
@FXML
private ToggleButton connectToggle;
private Socket socket = null;
private BufferedReader inputBuffer = null;
FetchTask fetchTask;
private static ObservableList<SqlData> data;
Connection con ;
public static volatile boolean closesignal = false;
public void connectAction(ActionEvent actionEvent) {
if (connectToggle.isSelected()){
try {
//socket = new Socket("192.168.1.36",80);
System.out.println("Connecting to : " + Selected_IP.ip_Hold);
socket = new Socket(Selected_IP.ip_Hold,80);
inputBuffer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//thread.start();
fetchTask = new FetchTask(con,inputBuffer);
new Thread( fetchTask).start();
} catch (IOException e) {
e.printStackTrace();
}
}else {
try {
fetchTask.cancel();
socket.close();
inputBuffer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void ephantAction(ActionEvent actionEvent) throws IOException {
try {
socket.getOutputStream().write('d');
} catch (IOException e) {
e.printStackTrace();
}
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("progressbar.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle("ABC");
stage.setScene(new Scene(root1));
stage.show();
}
public void printAction(ActionEvent actionEvent) {
//System.out.println("hello i am printing");
try {
printResult(con);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
TableColumn firstNameCol = new TableColumn("Dolphin");
firstNameCol.setCellValueFactory(new PropertyValueFactory<SqlData,String>("firstName"));
data = FXCollections.observableArrayList(
//new connector.SqlData("dummy value")
);
dataTable.setItems(data);
dataTable.getColumns().addAll(firstNameCol);
try {
con = getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
private static Connection getConnection() throws SQLException {
Connection con = null;
String url = "jdbc:sqlite:wolf.db";
// create a connection to the database
con = DriverManager.getConnection(url);
System.out.println("Connection to SQLite has been established.");
return con;
}
private static void printResult(Connection con) throws SQLException {
//reading records
Statement st = con.createStatement();;
System.out.println("Reading records:");
ResultSet rs=st.executeQuery("select * from foobar");
while(rs.next()){
System.out.println(rs.getString("indata"));
data.add(new SqlData(rs.getString("indata")));
}
st.close();
rs.close();
}
private static void storeInt(Connection con, int storedata) throws SQLException {
String sql = "insert into foobar(indata) values (?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setInt(1, storedata);
pstmt.executeUpdate();
}
}
这是FetchTask代码 - &gt;
public class FetchTask extends Task<Void> {
public boolean exitFlag = false;
private BufferedReader inputBuffer = null;
private Connection connection;
FetchTask(Connection connect, BufferedReader inputBuffer){
this.connection = connect;
this.inputBuffer = inputBuffer;
}
private void storeInt(Connection con, int storedata) throws SQLException {
String sql = "insert into foobar(indata) values (?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setInt(1, storedata);
pstmt.executeUpdate();
}
@Override
protected Void call() throws Exception {
while (!isCancelled()){
if(Thread.currentThread().isInterrupted()){
System.out.println("i am breaking out");
break;
}
String inMsg = null;
try {
inMsg = inputBuffer.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if (!inMsg.isEmpty()) {
System.out.println(inMsg);
try {
storeInt(connection, Integer.parseInt(inMsg));
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("exiting thread");
return null;
}
}
所以我想知道当取消选择切换按钮时如何终止获取数据任务和套接字。
答案 0 :(得分:0)
请注意,您无法interrupt()
对Socket
进行阻止性阅读。
中断阻塞读取的标准方法确实是关闭套接字。
因此,您可以实施取消操作,例如
@Override
protected void cancelled() {
try {
socket.close();
} catch( IOException e ) {
// Never mind.
}
}
并且在protected Void call()
中,如果任务已被取消,您可以捕获并忽略任何(IO-)异常。
try {
...
} catch ( IOException e ) {
if ( this.isCancelled() ) {
// May ignore the exception. We're terminating anyway.
} else {
throw e; // Not cancelled -> Need to propagate the exception.
}
}