我是Java的新手,在创建多客户端/服务器聊天时遇到问题。
我需要将服务器实现为可以从一个或多个客户端接收多个消息的服务器,并将所有这些消息发送给所有客户端。因此,假设有两个客户端,并且client1将消息“ hi”发送到服务器。服务器将把该消息发送到client1和client2(它将发送回所有连接到服务器的可能客户端)。
另外,如何将客户的用户名与他们的消息相关联?如果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");
}
}
}
例如,可以通过扩展HandleAClient的构造函数来完成。
想法-保存在客户端处理程序中的客户端信息。
在创建HandleAClient实例时,在ServerFormController中,我们具有有关客户端编号的信息。我们可以将其作为构造函数的附加参数提供给HandleAClient,因此当客户端处理程序接收到来自客户端的消息时,它将能够使用具体客户端的名称制作“个性化”消息。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句