2012-05-13 5 views
2

私は知っている、私は知っている、これまでに百万の質問と答えはどこでも。それに関する実際の詳細な記事のトン、いくつかの種類の例。私は過去数時間、それについて読んで過ごしましたが、そのトリックをやっていません。なぜ私のコードはまだ動作していないため、私は明らかに何をする必要があるか分からないので、私はこれを求めている理由です。私はSwingがEDTとどのように動作するのかを知り、ServerSocketのaccept()メソッドを使うつもりなら、Swingの新しいスレッドを開始する必要があります(私は思っていますか?)。私のコードをそのまま実行すると、ウィンドウが開き、フリーズします。 私の質問は、誰かが私のコードを見て、私が間違っていることを教えてくれるのだろうか? (それは私がように感じているものですので:P)ここJava - スレッド、スイング、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"){ 

    } 
} 

} 

--edit --- 新しい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のSocketから読んでいます。これはブロックすることを意味します。 invokeLaterを呼び出すと、RunnableがEDT上でのみ実行されます。あなたはEDTの2つの呼び出しを積み重ねています。そのうちの1つはソケットです。

SwingWorkerでソケットを移動すると、Sockerの値が徐々にGUIに戻ります。

+0

さて、私はそれをやった。これは現在フリーズせずに動作しますが、何らかの理由でaccept()がまだ実行されていません。私は自分の質問を編集し、SwingWorkerを使って変更を加えました。 – cgasser

+0

@ Zexanima SwingWorkerでexecute()の代わりにrun()を呼び出しています。これは唯一の問題ではありません。あなたのMain.run()の内部にスレッドを作成しないでください。SwingWorkerがそのスレッドを作成します。最後に、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

@Gray、そうですね。どのスレッドが最もアクションを起こしても、「メインスレッド」と呼びます。私はそれを編集します。 – zneak

+0

@Gray、wait、 "main thread"はどこに書きましたか? – zneak