0

我正在使用 Java 创建一个简单的套接字服务器。我一次可以连接一个客户端,我尝试实现线程来处理多个客户端。在我的服务器构造函数中,我创建了一个处理 ServerSocket 的线程,并且应该继续监听新客户端。连接套接字后,我尝试创建另一个线程来处理客户端套接字。但我仍然无法连接多个客户端。我尝试连接的第二个客户端不会获得 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

您没有为Class提供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 回答