Java – Threads,Swing和ServerSocket

我知道,我知道,到处都有一百万个问题和答案。 关于它的大量详细文章,几种类型的例子。 过去几个小时我一直在阅读它,但这并没有成功。 我问这个的原因是因为我仍然不明白我需要做什么显然是因为我的代码仍然无效。 我知道Swing如何与EDT一起工作,如果我要使用ServerSocket的accept()方法,我将需要为Swing启动一个新线程(我想?)。 当我运行我的代码时,窗口就会打开并冻结。 我的问题是,有人可以看看我的代码,告诉我我做错了什么,并向我解释,就像我只有半个脑子一样? (因为那就是我的感受。:P)

以下是我已经读过的一些地方:

  • 来自SO的这个问题。
  • 这个网站。
  • 当然还有Oracle对swing和thread的解释。
  • 以及其他一些随机网站。

Main.class

package com.sever.core; import java.io.IOException; import java.net.Socket; import java.util.Scanner; import javax.swing.SwingUtilities; public class Main { private SocketManager network; public static void main(String[] args){ SwingUtilities.invokeLater(new Runnable(){ @Override public void run() { Window window = new Window(); window.setVisible(true); } }); SwingUtilities.invokeLater(new Runnable(){ @Override public void run() { Main main = new Main(); main.run(); } }); } public void run(){ network = new SocketManager(25595); while(true){ try { network.setSocket(network.getServerSocket().accept()); AddUser(network.getSocket()); Thread x = new Thread(network); x.start(); } catch (Exception e) { System.out.println("Failed to connect."); } } } public void AddUser(Socket s){ try { Scanner input = new Scanner(s.getInputStream()); network.addUser(input.nextLine()); } catch (Exception e) { } } } 

Window.class

 package com.sever.core; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.*; public class Window extends JFrame{ private int screenWidth = 800; private int screenHeight = 600; private Thread thread; private JPanel window = new JPanel(); private JTextArea consle = new JTextArea("Server started...."); private JTextField input = new JTextField(); private JScrollPane consleinput = new JScrollPane(consle); public Window(){ this.setName("NAMEHERE - Server Software"); setResizable(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(screenWidth,screenHeight); window.setBackground(Color.DARK_GRAY); window.setLayout(new BoxLayout(window, BoxLayout.Y_AXIS)); consleSetup(); addComponets(); } private void addComponets(){ add(window); window.add(consleinput); window.add(input); } private void consleSetup(){ consle.setEditable(false); consle.setLineWrap(true); consle.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); consleinput.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); input.setMaximumSize(new Dimension(Integer.MAX_VALUE,input.getPreferredSize().height)); } private void addListeners(){ input.addActionListener(new ActLis()); input.setActionCommand("input"); } } 

SocketManager.class

 package com.sever.core; import java.io.*; import java.net.*; import java.util.ArrayList; public class SocketManager implements Runnable{ private Socket sock; private ServerSocket sersoc; private PrintWriter output; private BufferedReader input; private Thread thread; public ArrayList currentConnections = new ArrayList(); public ArrayList currentUsers = new ArrayList(); public SocketManager(String ip, int port){ try{ sock = new Socket(ip,port); PrintWriter output = new PrintWriter(sock.getOutputStream()); BufferedReader input = new BufferedReader( new InputStreamReader(sock.getInputStream())); System.out.println("Server: socket started."); }catch(Exception e){ System.out.println("Server: Socket failed to connect.\n"); } } public SocketManager(int port){ try { sersoc = new ServerSocket(port); } catch (IOException e) { System.out.println("Server: Socket failed to connect.\n"); } } public SocketManager(Socket socket){ this.sock = socket; try{ output = new PrintWriter(sock.getOutputStream()); input = new BufferedReader( new InputStreamReader(sock.getInputStream())); }catch(Exception e){ } } public synchronized void checkConnetion(){ if(!sock.isConnected()){ for(int x = 0; x <= currentConnections.size(); x++){ if(currentConnections.get(x) == sock){ currentConnections.remove(x); System.out.println("Server: Disconnecting from: " + currentConnections.get(x) + "\n"); } } } } public synchronized Socket getSocket(){ return sock; } public synchronized ServerSocket getServerSocket(){ return sersoc; } public synchronized void setSocket(Socket s){ System.out.println("Setting socket to: " + s.getInetAddress()); sock = s; } public synchronized void addSocket(Socket s){ currentConnections.add(s); } public synchronized void addUser(String u){ currentUsers.add(u); } public synchronized ArrayList getConnections(){ return currentConnections; } public synchronized ArrayList getUsers(){ return currentUsers; } public synchronized void send(String data){ try{ output.println(data); }catch(Exception e){ } } public synchronized void close(){ try{ sock.close(); }catch(Exception e){ } output = null; input = null; System.gc(); } public synchronized boolean isConnected(){ return (sock == null) ? false : (sock.isConnected() && !sock.isClosed()); } @Override public void run() { System.out.println("Is runing."); while(true){ try { checkConnetion(); if(input.readLine().isEmpty()){ return; } output.println("Server: Recived your message."); } catch (Exception e) { } finally{ try { sock.close(); } catch (Exception e) { } } } } } 

ActLis.class

 package com.sever.core; import java.awt.event.*; import javax.swing.*; public class ActLis implements ActionListener{ private JTextField actionField; public ActLis(){ } public ActLis(JTextField t){ actionField = t; } @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub String cmd = e.getActionCommand(); if(cmd == "input"){ } } } 

–EDIT —带有SwingWorker的新Main.class

 package com.sever.core; import java.io.IOException; import java.net.Socket; import java.util.Scanner; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class Main { private SocketManager network; public static void main(String[] args){ SwingUtilities.invokeLater(new Runnable(){ @Override public void run() { Window window = new Window(); window.setVisible(true); } }); SwingWorker server = new SwingWorker(){ @Override protected Object doInBackground() throws Exception { Main main = new Main(); main.run(); return null; } }; server.run(); } public void run(){ network = new SocketManager(25595); while(true){ try { network.setSocket(network.getServerSocket().accept()); AddUser(network.getSocket()); Thread x = new Thread(network); x.start(); } catch (Exception e) { System.out.println("Failed to connect."); } } } public void AddUser(Socket s){ try { Scanner input = new Scanner(s.getInputStream()); network.addUser(input.nextLine()); } catch (Exception e) { } } } 

您正在阅读EDT上的Socket。 这意味着你阻止了它。 调用invokeLater只会导致您的Runnable在EDT上执行。 你在EDT打了两个电话,其中一个是你的sockets。

考虑在SwingWorker中移动套接字, SwingWorker将Socker的值逐步返回到GUI。

套接字操作阻止。 例如,如果您调用accept ,则在实际连接到您的程序之前,调用将不会返回,从而有效地阻止正在运行的线程。 这就是他们建议让网络在辅助线程上运行的原因。

在您的情况下,您确实创建了一个线程,但是您没有从中调用accept

 while(true) { try { // this is called on the EDT--beware! network.setSocket(network.getServerSocket().accept()); AddUser(network.getSocket()); // ... and then, everything called from x will be on the secondary thread Thread x = new Thread(network); x.start(); } catch (Exception e) { System.out.println("Failed to connect."); } } 

这就是冻结的原因。 如果您不想阻止UI,则必须从辅助线程完成对accept的调用。