我编写了一个程序,该程序使用多播来发现本地网络上的对等方并允许它们之间的文件传输。它工作,除了一些获取文件/初始化传输线程的过程非常慢。它会挂起大约10-15秒,然后开始传输并正常完成:
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时,存在很大的延迟。我可以调试它,但它没有显示任何问题。此外,我知道问题不在于我在socket()中的socket.connect()调用,因为在socket.connect()之前的print语句不会打印,直到程序从任何地方恢复#39;悬挂。有任何想法吗?我完全迷失了。
- 编辑:上面的所有代码都按预期工作,此处提到的错误已经解决。如果有人想要完整的消息来源,我很乐意分享它。
答案 0 :(得分:0)
我将名为peerBox
的组合框传递给我的ClientMuticast
课程。我直接修改了这个结构,将对等体存储在其中。这阻止了接口线程,因为ClientMulticast
类不断访问/更改组合框
我更改了代码以使用组合框仅向gui显示值并存储发现的对等项。在每次调用ClientMulticast
构造函数时,使用数组列表复制组合框中的所有值。如果发现了对等方,则会通过publish()
类中的process()
和ClientMulticast
方法更新组合框。放置在process()
内的任何代码都将安排在EDT上执行。