0

Java を使用して単純なソケット サーバーを作成しています。一度に 1 つのクライアントに接続できます。複数のクライアントを処理するためにスレッドを実装しようとしました。Server コンストラクターで、ServerSocket を処理するスレッドを作成し、新しいクライアントをリッスンし続ける必要があります。ソケットが接続されたら、クライアントのソケットを処理する別のスレッドを作成しようとしました。しかし、まだ複数のクライアントを接続できません。接続しようとする 2 番目のクライアントは IO ストリームを取得しません。

public class Server extends JFrame {

private JTextField enterField;
private JTextArea displayArea;
private ObjectOutputStream output;
private ObjectInputStream input;

private ServerSocket server;
private Socket connection;
private int counter = 1;

public Server() {
    super("Server");
    enterField = new JTextField();
    enterField.setEditable(false);
    enterField.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent event) {
            sendData(event.getActionCommand());
            enterField.setText("");

        }
    });

    add(enterField, BorderLayout.NORTH);
    displayArea = new JTextArea();
    add(new JScrollPane(displayArea));
    setSize(300, 150);
    setLocation(500, 500);
    setVisible(true);

    new Thread(new Runnable() {
        public void run() {
            try {
                server = new ServerSocket(50499, 100);
                displayMessage("Listening on Port: "
                        + server.getLocalPort() + "\n");
                for (;;) {
                    Socket nextClient = server.accept();
                    displayMessage("Client Connected");
                    new ClientThread(nextClient).start();
                    nextClient = null;
                }
            } catch (IOException exception) {
                exception.printStackTrace();
            }
        }
    }).start();
}

private void closeConnection() {
    displayMessage("\nTerminating connection\n");
    setTextFieldEditable(false);
    try {
        output.close();
        input.close();
        connection.close();
    } catch (IOException ioException) {
        ioException.printStackTrace();
    }
}

private void displayMessage(final String string) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            displayArea.append(string);
        }
    });
}

private void setTextFieldEditable(final boolean editable) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            enterField.setEditable(editable);

        }

    });

}

private void sendData(String message) {
    try {
        output.writeObject("SERVER>>> " + message);
        output.flush();
        displayMessage("\nSERVER>>> " + message);
    } catch (IOException ioException) {
        displayArea.append("\nError Writing Object");
    }
}

private class ClientThread extends Thread {

    public ClientThread(Socket socket) throws IOException {
        try {
            connection = socket;
            output = new ObjectOutputStream(socket.getOutputStream());
            output.flush();
            input = new ObjectInputStream(socket.getInputStream());
            displayMessage("Got I/O Stream\n");
            displayMessage("Connection " + counter + " received from: "
                    + 
                            connection.getInetAddress().getHostName());
            counter++;
            String message = "Connection Sucessful";
            sendData(message);
            setTextFieldEditable(true);
            do {

                message = (String) input.readObject();
                displayMessage("\n" + message);
            } while (!message.endsWith(">>> TERMINATE"));

        } catch (ClassNotFoundException classNotFoundException) {
            displayMessage("\nUnknown object type recieved");

        } finally {
            closeConnection();
        }

    }
  }
}
4

2 に答える 2

2

ClientThreadコンストラクター内で接続を行っています。したがって、コマンドnew ClientThread(...)を送信するまで は決して戻りません。メソッドTERMINATE内にロジックを配置します。run()

private class ClientThread extends Thread {
  private Socket socket;

  // The queue, thread-safe for good measure
  private Queue<String> queue = new ConcurrentLinkedQueue<String>();

  public ClientThread(Socket socket) throws IOException {
    this.socket = socket;
  }

  public void send(String message) {
    if (message != null) {
      this.sendQueue.add(message);
    }
  }

  public void run() {
    try {
      connection = socket;
      output = new ObjectOutputStream(socket.getOutputStream());
      output.flush();
      input = new ObjectInputStream(socket.getInputStream());
      displayMessage("Got I/O Stream\n");
      displayMessage("Connection " + counter + " received from: " 
          + connection.getInetAddress().getHostName());
      counter++;
      String message = "Connection Sucessful";
      sendData(message);
      setTextFieldEditable(true);
      do {
        // Purge the queue and send all messages.
        while ((String msg = queue.poll()) != null) {
          sendData(msg);
        }
        message = (String) input.readObject();
        displayMessage("\n" + message);
      } while (!message.endsWith(">>> TERMINATE"));
    } catch (ClassNotFoundException classNotFoundException) {
      displayMessage("\nUnknown object type recieved");
    } finally {
      closeConnection();
    }
  }
}

通常、他のスレッドから接続にメッセージを送信します。

ClientThread client = new ClientThread(newClient);
client.start();
client.send("Hi there");

個人的には、 NettyMinaなどのノンブロッキング (NIO) ネットワーク ライブラリを使用して、この種のものを実装していたでしょう。それらを使用するにはいくつかの学習が必要ですが、それだけの価値があると思います。ノンブロッキングとは、接続ごとに個別のスレッドを専用にするのではなく、ソケットで何かを受信したときに通知されることを意味します。

于 2013-05-25T15:38:59.737 に答える
0

クラスのrunメソッドの実装を提供していません。Thread

ClientThread の処理ロジックをrunメソッド内に入れる

コードをモジュール化して管理しやすくするには、ClientThreadクラスをパブリックにして、それらのスレッド間で必要なリソースのみを共有します。

public class ClientThread extends Thread {  //make class public
  private Socket socket;
// define all other references 
ObjectOutputStream output = null;
//...

  public ClientThread(Socket socket) throws IOException {
    this.socket = socket;
  }

  public void run() {
    try {
      connection = socket;
        output = new ObjectOutputStream(socket.getOutputStream());
        output.flush();
        input = new ObjectInputStream(socket.getInputStream());
        displayMessage("Got I/O Stream\n");
        displayMessage("Connection " + counter + " received from: "
                + 
                        connection.getInetAddress().getHostName());
        counter++;
        String message = "Connection Sucessful";
        sendData(message);
        setTextFieldEditable(true);
        do {

            message = (String) input.readObject();
            displayMessage("\n" + message);
        } while (!message.endsWith(">>> TERMINATE"));

    } catch (ClassNotFoundException classNotFoundException) {
        displayMessage("\nUnknown object type recieved");

    } finally {
        closeConnection();
    }

}
}}
于 2013-05-25T15:37:48.093 に答える