我目前正在进行小型聊天,目前我在如何从一个客户端获取某些数据并将其分发给其他客户端时遇到了一些困难。
到目前为止,这是我的服务器:
public static void main(String[] args) {
try
{
@SuppressWarnings("resource")
ServerSocket server = new ServerSocket(8000);
Hashtable<String, Client> connectedClients = new Hashtable<String, Client>();
while (true)
{
Socket s = server.accept();
System.out.println("Client connected from " + s.getLocalAddress().getHostName());
Client chat = new Client(s);
Thread t = new Thread(chat);
t.start();
}
}
catch (Exception e)
{
System.out.println("An error occured.");
e.printStackTrace();
}
}
这是类Client:
public void run()
{
try
{
@SuppressWarnings("resource")
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream());
String newLine = null;
while (true)
{
newLine = in.nextLine();
if(clientName==null){
clientName = newLine;
}
else{
out.println(clientName+": "+newLine);
out.flush();
}
}
}
catch (Exception e)
{
System.out.println(clientName+" disconnected.");
}
}
(请注意,我只添加了非常重要的段落)。如您所见,我正在为每个客户端创建一个新线程,它将第一个发送的字符串作为用户名。这是由我的GUI处理,通过禁用所有消息字段,直到设置了用户名,这样就可以了。
但是,正如您可能已经注意到的那样,有一个未使用的Hashtable应该填充String和Client。正如您可能已经猜到的那样,这将是用户名和客户端实例。
现在的问题是,如何将Thread类中的数据传递给调用Server类。
我提出了2个想法:1)使线程可观察并将所需的方法添加到我的Server类。一旦设置了名称,它就会通知我的Server类,将String和通知类添加到我的Hashtable,然后在其他客户端中分发。
2)向我的服务器添加一个静态方法,它也做同样的事情。
然而,我觉得我在这里想得太远了。我很确定有更简单的方法,但我无法弄明白。
任何人都可以帮我解决这个问题吗?
答案 0 :(得分:1)
您需要将集合封装在对象中,然后使用执行该集合所需操作所需的方法将该对象传递给每个客户端。
例如:
class ClientManager {
private Hashtable<String, Client> clientMap = new Hashtable<>();
public void sendGlobalMessage(String message) {
for(Client client : clientMap.values()) {
if(client != null) {
client.sendMessage(message);
}
}
}
}
您现在可以将此传递给每个客户端。您的Client
课程应该如下所示,接受ClientManager
并提供sendMessage
方法:
class Client {
private ClientManager manager;
private Socket socket;
private DataOutputStream out;
public Client(ClientManager manager, Socket socket) {
this.manager = manager;
this.socket = socket;
}
public void run() {
try {
out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream());
clientManager.sendGlobalMessage("hey!");
}catch(IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String message) throws IOException {
out.writeUTF(message);
}
}
当Server
接受连接时,它会创建一个Client
对象。这是你应该通过的时候:
class Server {
public static void main(String[] args) {
try(ServerSocket ss = new ServerSocket(...)) {
ChatManager manager = new ChatManager();
while(true) {
Client client = new Client(manager, ss.accept());
new Thread(client).start();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
答案 1 :(得分:0)
您可以将Server
对象(如果它不在main
中)传递给Client
的每个实例,并使用该引用来维护Hashtable
。
如果您没有创建Server
对象,那么您将需要使用第二个选项(实际上并不是那么开箱即用)。只需将connectedClients
成为static
类的Server
成员,然后添加另一个静态方法来维护它。
您可能需要考虑制作该方法synchronized
(除非这是您使用Hashtable
而不是HashMap
进行同步的原因。)< / p>