Java-在客户端识别从服务器发送到一个或发送到所有消息

Java-在客户端识别从服务器发送到一个或发送到所有消息,java,multithreading,sockets,Java,Multithreading,Sockets,我正在开发一个服务器/客户端应用程序,该应用程序允许多个客户端在任何给定时间连接到服务器。 对于每个客户机,服务器设置一个ClientHandler对象,该对象具有连接到此套接字的客户机的输入和输出流。通过此连接,客户端可以在程序运行的任何时间点向服务器自由发送大量消息,服务器将根据消息做出响应 我需要实现的是一种机制,它在某些时候向当前连接的所有客户端发送消息。我通过将所有输出流存储到客户机的ArrayList中来实现这一点,该列表将允许向所有客户机发送相同的消息 我正在挣扎的是: 当接收到客

我正在开发一个服务器/客户端应用程序,该应用程序允许多个客户端在任何给定时间连接到服务器。 对于每个客户机,服务器设置一个
ClientHandler
对象,该对象具有连接到此套接字的客户机的输入和输出流。通过此连接,客户端可以在程序运行的任何时间点向服务器自由发送大量消息,服务器将根据消息做出响应

我需要实现的是一种机制,它在某些时候向当前连接的所有客户端发送消息。我通过将所有输出流存储到客户机的
ArrayList
中来实现这一点,该列表将允许向所有客户机发送相同的消息

我正在挣扎的是:

当接收到客户机特有的消息时,客户机GUI会相应地更新(只能发送选定数量的消息,因此只有选定数量的可能响应来自服务器,由客户端if语句处理)。但是,当客户端收到发送给所有客户端的消息时,我希望客户端以完全不同的方式更新GUI

考虑到两种形式的输入都来自同一个输入流,我可以看出这很困难,我预计我必须声明使用
PrintWriter
导致输出的任何方法都必须进行
同步。但是,在使用相同的
PrintWriter
时,是否有办法处理不同的输入?这是否必须使用进一步的
if
语句来完成,或者是否可以在客户端使用一个单独的
线程来处理发送到所有客户端的消息

谢谢你的建议,如果你认为你能帮上忙的话,请随意索取我现有代码的一部分


标记

首先,您的服务器和客户端之间缺乏协议

显然,服务器可以发送两种类型的消息“响应”和“广播”。 一种相当简单的方法是标记消息:例如,如果消息是对请求的响应,则在mesages前面加上“R”,如果消息是无人参与的广播消息,则在mesages前面加上“B”。(这完全取决于服务器和客户端之间的通信方式。)

您的客户机是否需要不同的线程来处理消息则完全不同。如果客户端中的处理活动会阻止套接字的及时读取,则使用不同的线程非常有用。然后,您可能会考虑正在进行通信的I/O线程,并将消息发送到不同的“处理程序”(可以是其他线程)进行处理。(此I/O线程还可以删除标记,这样现有的处理代码就不需要了解服务器的底层协议。)

类似的推理可能适用于服务器端。根据交互和请求处理的动态,您可能会使用多个线程。然后,您应该有一个与客户机和其他执行工作(生成响应或广播消息)的人进行I/O的人

现在,如果继续将客户端套接字添加到while循环中的arraylist中,您将拥有一个与服务器积极连接的客户端列表,如:

接受后:

  clients = new ArrayList<DataOutputStream>();
  Socket socket = ss.accept();
  os = new DataOutputStream(socket.getOutputStream());
  clients.add(os);
clients=newarraylist();
套接字=ss.accept();
os=新的DataOutputStream(socket.getOutputStream());
clients.add(os);

现在,由于客户机阵列列表中包含了所有客户机,您可以在其中循环,或者使用某种协议定义读取后应发送数据的客户机。

我在这里有点困惑。您谈论服务器端(向所有客户端发送消息),然后谈论客户端(更新GUI),然后突然引入属于服务器或客户端的线程?看起来你有不同的问题,但你把它们混在一起了。对于消息部分,您显然需要在协议中以某种方式标记广播消息,而这与线程同步无关。为此,当您说“以某种方式标记广播消息”时,您的意思是在消息内容之前发送布尔值,这可以在客户端检测到吗@SergeyTachenovI不知道你协议的细节就不能说。这是你可以自由重新设计的东西吗?它使用什么格式?它可以扩展或重新设计吗?例如,如果它使用XML消息,那么只需向作业添加一个“broadcast='true'”属性就可以了。“在内容之前发送一个布尔值”听起来也很相似,尽管对于一个定义良好的协议来说太幼稚了。谢谢。我一直在研究它,有人告诉我,我确实需要客户端上的两个线程。一个用于个人信息,一个用于“广播”。我假设广播消息的标记仍然可以以这种方式工作,只要在检测到广播消息时另一个客户端线程调用
wait()
@SergeyTachenov一条流上的两个线程没有任何意义。但是,您可以有三个流:一个接收所有消息并将它们放入两个
阻塞队列
中,另两个线程从各自的队列中读取(这样您就不必使用低级
等待()
,这很难看)。但你们仍然需要一些方法来区分这些信息。嗨,你们提出了一个非常有趣的观点,我觉得这就是我可能一直在寻找的。您提到“将消息发送到不同的处理程序”,这在我的情况下是可行的。我一直在寻找将消息传递给另一个线程的方法,但一直找不到任何合适的方法。在我当前的版本中,我已经决定让两个线程共享相同的
扫描器
对象,但我一点也不喜欢这样。你能加一个e吗
  clients = new ArrayList<DataOutputStream>();
  Socket socket = ss.accept();
  os = new DataOutputStream(socket.getOutputStream());
  clients.add(os);