【问题标题】:Server to send messages to clients服务器向客户端发送消息
【发布时间】:2015-01-05 21:36:57
【问题描述】:

我对 Java 比较陌生,在创建多客户端/服务器聊天时遇到问题。

我需要实现服务器,以便它可以从一个或多个客户端接收多条消息,并将所有这些消息发送给所有客户端。因此,假设有两个客户端,client1 将消息“hi”发送到服务器。服务器会将该消息发送到客户端 1 和客户端 2(它会发回到所有可能连接到服务器的客户端)。

另外,我如何将客户的用户名与他们的消息相关联?如果 client1 发送“hi”,我希望 Client1 和 Client2 中的 TextAreas 显示消息说“client1:hi”。

这些实现是在 JavaFX 中完成的。

服务器代码:

package server;

import java.io.*;
import java.net.*;
import java.util.*;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextArea;

public class ServerFormController implements Initializable{
    @FXML
    public TextArea svrLog;
    private int clientNo = 0;

    ArrayList<HandleAClient> clients = new ArrayList<>();

   //@Override
  // public void run()
  // {

  // }

  @Override
  public void initialize(URL url, ResourceBundle rb) {
    new Thread( () ->
    {
        try{

            ServerSocket serverSocket = new ServerSocket(8000);
            svrLog.appendText("Server started at " + new Date() + '\n');

            while (true)
            {
                Socket socket = serverSocket.accept();
                svrLog.appendText("Worked \n");

                clientNo++;

                //svrLog.appendText("Starting thread for client " + clientNo + "at"
               // + new Date() + '\n');

               // InetAddress inetAddress = socket.getInetAddress();
                //svrLog.appendText("Client " + clientNo + "'s host name is "
                //+ inetAddress.getHostName() + "\n");
              // svrLog.appendText("Client " + clientNo + "'s IP Address is "
               // + inetAddress.getHostAddress() + "\n");

                new Thread(new HandleAClient(socket)).start();
            }

        } catch (IOException ex) {
            svrLog.appendText("Couldn't create ServerSocket! \n");
        }
    }).start();
   }

   /** Creates individual client socket*/
   class HandleAClient implements Runnable {
      private Socket socket;
      DataInputStream inputFromClient = null;
      DataOutputStream outputToClient = null;
      //ServerFormController svr;

      public HandleAClient(Socket socket)
      {
          this.socket = socket;
      }

      public void run()
      {
          try{
              inputFromClient = new DataInputStream(socket.getInputStream());
              outputToClient = new DataOutputStream(socket.getOutputStream());

              while (true)
              {
                  String msg = inputFromClient.readUTF();
                 // for(int i = 0; i < clients.size(); i++) // probably because object in client contain null datastreams
                 //   clients.get(i).outputToClient.writeUTF(msg); // nope.
                  outputToClient.writeUTF(msg);
                  svrLog.appendText(msg);
                  svrLog.appendText("New message received from client. Sent to all clients.");

              }
          } catch (IOException ex) {
              svrLog.appendText("Could not create data stream with client! \n");
          }
      }
  }
 }

客户端代码:

package handlerclient;

import java.io.*;
import java.net.*;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class HandlerClientFormController implements Initializable {
    @FXML
    private TextField ipAdrText; // TextField to get the IP Address
    @FXML
    private TextField usernameText; // TextField to get the user's chat name
    @FXML
    private Button clientConnectBtn;  // Tries to connect to server
    @FXML
    private TextArea msgLogTxtArea; // Displays all the messages between the clients
    @FXML
    private TextArea msgSendTxtArea; // TextArea to get the message from the client
    @FXML
    private Button clientSendBtn;  // Sends the message from the client to the server

    DataOutputStream toServer = null;
    DataInputStream fromServer = null;

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    

    @FXML
    private void onConnectBtnClick(ActionEvent event) {
    try{
        Socket socket = new Socket(ipAdrText.getText(), 8000);
        fromServer = new DataInputStream(socket.getInputStream());
        toServer = new DataOutputStream(socket.getOutputStream());
    }
    catch (IOException ex)
    {
        msgLogTxtArea.appendText("Could not connect to server!");
    }
}

    @FXML
    private void onSendBtnClick(ActionEvent event) {
       try{
            toServer.writeUTF(msgSendTxtArea.getText());
            toServer.flush();

            String newmsg = fromServer.readUTF();

            msgLogTxtArea.appendText(newmsg + '\n');
        }
        catch (IOException ex)
        {
            msgLogTxtArea.appendText("Could not send/receive message! \n");
        }
    }

}

【问题讨论】:

    标签: java multithreading javafx client-server javafx-2


    【解决方案1】:

    例如,它可以通过扩展 HandleAClient 的构造函数来完成。
    想法 - 保存在客户端处理程序客户端的信息。
    在创建 HandleAClient 的实例时,在您的 ServerFormController 中,我们有关于客户端编号的信息。 我们可以将它作为构造函数的附加参数提供给 HandleAClient,因此当客户端处理程序接收到来自客户端的消息时,它将能够使用具体客户端的名称制作“个性化”消息。

    【讨论】:

    • 您是否知道在 ServerFormController 中需要什么才能将消息发送到所有客户端?就像我在问题中提到的那样,“我需要将服务器实现到它可以从一个或多个客户端接收多条消息的位置,并将所有这些消息发送给所有客户端。所以,假设有两个客户端和 client1 发送消息“hi”到服务器。服务器将该消息发送到 client1 和 client2(它会发送回连接到服务器的所有可能的客户端)。另外,感谢您的回复。这很有帮助。
    • 我认为你最初的想法很接近这样做 - 关于注释代码 // for(int i = 0; i
    • 哇。刚刚意识到我从来没有向客户添加任何东西,所以难怪那部分从来没有奏效。哎呀。感谢您的帮助!
    • 附注在该概念中,客户端集合应该是多线程安全的。 stackoverflow.com/questions/2444005/… 中的 java.util.concurrent 或 Collections.synchronizedList() 可以帮助解决这个问题
    猜你喜欢
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2017-07-30
    • 1970-01-01
    相关资源
    最近更新 更多