我已經編寫了一個程序,它使用多點傳送來發現本地網絡上的對等方並允許它們之間的文件傳輸。它的工作原理,除了一些獲取文件/初始化傳輸線程的過程非常緩慢。它掛起約10-15秒,然後開始傳輸,並正常完成:在執行SwingWorker之前掛起Java文件傳輸程序
Transfer.java
我的JFrame GUI類。這是爲了方便Netbeans完成的,因此任何生成的代碼都不會在這裏發佈。
package transfer; import java.beans.PropertyChangeEvent; import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFileChooser; import static javax.swing.JFileChooser.FILES_AND_DIRECTORIES; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class Transfer extends javax.swing.JFrame { private final FileDrop fileDrop; private Client client; private final Server server; private final ClientMulticast clientMulticast; private final ServerMulticast serverMulticast; public Transfer() throws IOException { initComponents(); this.setTitle("Transfer"); peerBox.setEditable(false); peerBox.removeAllItems(); fileDrop = new FileDrop(backgroundPanel, (java.io.File[] files) -> { System.out.println(files[0].isDirectory()); if (peerBox.getSelectedIndex() != -1) { sendLabel.setText("Hello"); try { client = new Client(sendLabel, files, (Peer) peerBox.getSelectedItem()); //Client property change listener - listens for updates to progress bar client.addPropertyChangeListener((PropertyChangeEvent evt1) -> { if (null != evt1.getPropertyName()) switch (evt1.getPropertyName()) { case "progress": sendProgressBar.setValue((Integer) evt1.getNewValue()); break; } }); client.execute(); } catch (Exception ex) { System.out.println("Unable to send! IOException in FileDrop call."); ex.printStackTrace(System.out); } } else { sendLabel.setText("Host not found"); } }); sendProgressBar.setMaximum(100); sendProgressBar.setMinimum(0); receiveProgressBar.setMaximum(100); receiveProgressBar.setMinimum(0); server = new Server(receiveLabel); //Server property change listener - listens for updates to progress bar server.addPropertyChangeListener((PropertyChangeEvent evt1) -> { if ("progress".equals(evt1.getPropertyName())) { receiveProgressBar.setValue((Integer) evt1.getNewValue()); } }); server.execute(); serverMulticast = new ServerMulticast(); serverMulticast.execute(); clientMulticast = new ClientMulticast(peerBox); clientMulticast.execute(); } ...GENERATED CODE... private void openButtonActionPerformed(java.awt.event.ActionEvent evt) { Transfer guiObject = this; SwingWorker openFile = new SwingWorker<Void, String>() { @Override protected Void doInBackground() throws Exception { openButton.setEnabled(false); fileChooser.setFileSelectionMode(FILES_AND_DIRECTORIES); int returnVal = fileChooser.showOpenDialog(guiObject); if (returnVal == JFileChooser.APPROVE_OPTION && peerBox.getSelectedIndex() != -1) { File[] fileArray = fileChooser.getSelectedFiles(); client = new Client(sendLabel, fileArray, (Peer) peerBox.getSelectedItem()); //Client property change listener - listens for updates to progress bar client.addPropertyChangeListener((PropertyChangeEvent evt1) -> { if ("progress".equals(evt1.getPropertyName())) { sendProgressBar.setValue((Integer) evt1.getNewValue()); } }); client.execute(); //block this swingworker until client worker is done sending while(!client.isDone()) { } } openButton.setEnabled(true); return null; } }; openFile.execute(); } /** * @param args the command line arguments * @throws java.lang.ClassNotFoundException * @throws java.lang.InstantiationException * @throws java.lang.IllegalAccessException * @throws javax.swing.UnsupportedLookAndFeelException */ public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException { System.setProperty("apple.laf.useScreenMenuBar", "true"); System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Transfer"); UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { try { new Transfer().setVisible(true); } catch (IOException ex) { Logger.getLogger(Transfer.class.getName()).log(Level.SEVERE, null, ex); } }); } // Variables declaration - do not modify private javax.swing.JPanel backgroundPanel; private javax.swing.JFileChooser fileChooser; private javax.swing.JButton openButton; private javax.swing.JComboBox<Peer> peerBox; private javax.swing.JLabel receiveHeaderLabel; private javax.swing.JLabel receiveLabel; private javax.swing.JPanel receivePanel; private javax.swing.JProgressBar receiveProgressBar; private javax.swing.JLabel sendHeaderLabel; private javax.swing.JLabel sendLabel; private javax.swing.JPanel sendPanel; private javax.swing.JProgressBar sendProgressBar; // End of variables declaration }
ClientMutlicast.java
發送多播數據包和接收響應 - 相應地修改GUI。這門課是錯誤的地方。
package transfer; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import javax.swing.JComboBox; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class ClientMulticast extends SwingWorker<Void, Peer> { private boolean peerPreviouslyFound; private byte[] sendData, receiveData; private final DatagramSocket mSocket; private DatagramPacket receivePacket; private final JComboBox<Peer> peerBox; private Peer peer; private ArrayList<Peer> peerList; public ClientMulticast(JComboBox<Peer> peerBox) throws SocketException { peerList = new ArrayList<>(); this.peerBox = peerBox; mSocket = new DatagramSocket(); mSocket.setBroadcast(true); mSocket.setSoTimeout(300); sendData = "CLIENT_MSG".getBytes(); } @Override protected Void doInBackground() throws IOException, InterruptedException, InvocationTargetException { while (true) { try { receiveData = new byte[1024]; receivePacket = new DatagramPacket(receiveData, receiveData.length); peerPreviouslyFound = false; //send broadcast message mSocket.send(new DatagramPacket(sendData, sendData.length, InetAddress.getByName("239.255.255.255"), 8888)); //receive response mSocket.receive(receivePacket); //don't have to worry about responses from local host because //server rejects multicast packets from local host peer = new Peer(receivePacket.getAddress(), receivePacket.getPort(), System.currentTimeMillis()); for (Peer peerList1 : peerList) { if (peerList1.getIPAddress().equals(peer.getIPAddress())) { peerList1.setTimestamp(System.currentTimeMillis()); peerPreviouslyFound = true; break; } } //add to peer list only if reponse is valid, not from local host, and not previously received from this host if ("SERVER_RESPONSE".equalsIgnoreCase(new String(receivePacket.getData()).trim()) && !peerPreviouslyFound) { //publish(peer); peerBox.addItem(peer); peerList.add(peer); } for (int i = 0; i < peerList.size(); i++) { //if peer is greater than 5 seconds old, remove from list if (peerList.get(i).getTimestamp() + 5000 < System.currentTimeMillis()) { peerBox.removeItemAt(i); peerList.remove(i); } } } catch (SocketTimeoutException ex) { for (int i = 0; i < peerList.size(); i++) { //if peer is greater than 5 seconds old, remove from list if (peerList.get(i).getTimestamp() + 5000 < System.currentTimeMillis()) { final int j = i; SwingUtilities.invokeAndWait(() -> { peerBox.removeItemAt(j); peerList.remove(j); }); } } } TimeUnit.MILLISECONDS.sleep(500); }//end while } @Override protected void process(List<Peer> p) { peerBox.addItem(p.get(p.size() - 1)); peerList.add(p.get(p.size() - 1)); } }
我敢肯定,當UI構造內的FileDrop對象嘗試使用client.execute(執行客戶的SwingWorker)的問題是,有一個大的延遲。我可以調試它,但它不顯示任何問題。另外,我知道這個問題不能在Client()中調用socket.connect(),因爲在socket.connect()之前的print語句不會打印,直到程序從掛起的任何地方恢復。有任何想法嗎?我完全失去了。
- 編輯:上面的所有代碼都按需要工作,此處提到的錯誤已得到解決。如果有人想要完整的源代碼,我會很樂意分享它。
在SwingWorker中使用'ProcessBuilder'的相關示例顯示爲[此處](http://stackoverflow.com/a/20603012/230513)。 – trashgod
你能詳細說一下嗎?這個例子正在做同樣的事情,只是以不同的方式。我的SwingWorkers使用屬性更改偵聽器來更新進度條和process()方法,以安排EDT上的gui更新。他們正在使用後臺任務(從我能理解的方面)。你是說我錯誤地更新了GUI? – Timmah339
這個詞_hangs_總是讓我懷疑阻止了EDT;但是,乍一看,我的工作人員看不到違規行爲;我的意思是建議一個完整的工作示例供參考。 – trashgod