2012-05-13 46 views
2

我知道我知道,在這個無處不在的地方已經有100萬個問題和答案。關於它的非常詳細的文章,幾種類型的例子。我花了幾個小時閱讀了這篇文章,但那不是訣竅。我問這個問題的原因是因爲我仍然不明白我需要做什麼,顯然是因爲我的代碼還沒有工作。我得到Swing如何與EDT協同工作的想法,如果我要使用ServerSocket的accept()方法,那麼我需要爲Swing啓動一個新線程(我認爲?)。當我運行我的代碼時,窗口剛剛打開並凍結。 我的問題是有人看我的代碼,告訴我我做錯了什麼,並解釋給我,就像我只有一半的大腦? (因爲這是我的感覺就像:P)Java - 線程,Swing和ServerSocket

這裏有一些地方我讀過不已:

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<Socket> currentConnections = new ArrayList<Socket>(); 
public ArrayList<String> currentUsers = new ArrayList<String>(); 


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<Socket> getConnections(){ 
    return currentConnections; 
} 

public synchronized ArrayList<String> 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"){ 

    } 
} 

} 

- 編輯 - 新Main.class用的SwingWorker

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) { 

    } 
} 
} 
+2

由於您使用了invokeLater,因此您的套接字在EDT上運行。你應該使用SwingWorker來執行Main.run()。 –

+0

@GuillaumePolet好的,謝謝。我讀過那篇文章,但是當我這樣做時,我不確定那是否是我想要的。我會試一試並回報。 – cgasser

回答

7

您正在閱讀您在EDT上的套接字。這意味着你阻止它。調用invokeLater只會導致您的Runnable在EDT上執行。你正在EDT上打兩個電話,其中一個是你的插座。

考慮在SwingWorker中移動套接字,該套接字將逐步將您的Socker的值返回給GUI。

+0

好的,我已經完成了。它現在沒有凍結,但現在由於某種原因,accept()仍然沒有運行。我編輯了我的問題,並用底部的SwingWorker添加了我的更改。 – cgasser

+0

@Zexanima你在你的SwingWorker上調用run()而不是execute()。 Bu不是唯一的問題,不要在你的Main.run()中創建一個Thread,SwingWorker會爲你創建該Thread。最後,不要返回null,而是返回來自Socket的輸入。此外,添加SwingWorker 的缺失類型,這將更清潔。 –

+0

好吧,我會那樣做的。爲什麼我會返回我的套接字的輸入?我不打算使用它的回報(據我所知)。那麼只是讓我的代碼更清潔? – cgasser

2

插座操作區塊。例如,如果您撥打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

+3

他在'SwingUtilities.invokeLater()'裏面調用'accept'嗎?這不是在「主線程」中,而是在AWT調度程序線程中。他的程序「凍結」,因爲他阻止AWT調度程序線程與accept一起運行。 – Gray

+0

@格雷,沒錯,我猜。我稱之爲「主線程」,無論哪個線程獲得最大的動作。我會編輯它。 – zneak

+0

@格雷,等等,我甚至在哪寫「主線程」? – zneak