当有两个以上的线程在运行时,如何让两个线程只相互响应-Java

时间:2017-05-19 09:21:58

标签: java multithreading sockets

我正在做一个我需要创建一个java服务器和一些客户端的项目,以便客户端可以在服务器上播放tic-tac-toe。客户端和服务器将在同一个网络中,所以IP不会有任何问题,它们总是一样的。现在针对这个问题,只有两个玩家一起玩一个匹配,但是会有多个匹配运行,所以服务器应该处理它。我遇到的问题是我在服务器上使用线程来交换客户端之间的移动,我不知道如何使一个线程只与另一个线程通信,而不通知或与其他线程交互它目前没有参加比赛。 有没有办法从其他线程中隔离两个线程? 我无法上传任何代码,因为我甚至不知道从哪里开始。

感谢。

4 个答案:

答案 0 :(得分:1)

由于您处于专用网络并使用套接字,因此您可以使用每个客户端的地址进行识别,您可以将一个对象作为同步对象分配给两个客户端,以便进行线程间通信。

答案 1 :(得分:0)

此问题与聊天应用类似。尝试查看任何基于xmpp的应用程序服务器(openfire)

答案 2 :(得分:0)

如果您的整个游戏都在一个套接字上进行,那么您就没有问题。当您的服务器套接字接受时,创建一个线程,并让该线程处理该套接字。没有其他线程甚至在范围内有该套接字。

如果你希望每个游戏都在一个单独的套接字连接上移动,而一个寿命较长的线程维持游戏状态,那就更复杂了。

可能最简单的解决方案是每个服务器线程都有自己的服务器套接字,使用动态分配的端口。服务器将有一个众所周知的端口,在该端口上将协商一个新会话:

  client                             server

  connect (well known port) -------> accept (well known port)
  request new game          -------> create new server socket (dynamic port)
                                     launch thread to listen on dynamic port
  receive dynamic port num  <------- respond with dynamic port num
  connect (dynamic port)    -------> (in thread) accept, handle game
  play game on this socket  -------> ...

有一些细节需要解决,比如是否保持第一个套接字打开,或者在协商后关闭它。

这是一个相当完善的模式(例如,它类似于FTP)。对于以这种方式工作的协议,防火墙可能会出现问题。

另一个选择是继续将所有请求发送到同一个端口,由单个ServerSocket处理,并将请求发送到相应的线程。要做到这一点,你需要一个会话ID,这将是每个请求的一部分。

执行此操作的一种方法是为每个游戏线程创建一个队列。每个线程从队列中读取命令。调度程序将请求放在适当的队列上。

创建新游戏主题时:

  // in the dispatcher
  Queue<Request> queue = new LinkedBlockingQueue<>();
  String sessionId = generateSessionId(); // UUID, whatever
  gamequeues.put(sessionid, queue); // gameQueues is a Map<String,Queue<Request>>
  Game game = new Game(queue, sessionId);
  new Thread(game).start();

当您收到游戏活动请求时:

  // also in the dispatcher
  String sessionId = request.getSessionId(); // HTTP header, something from payload, whatever
  queue.add(request);

  // In the thread
  while(game.isActive()) {
      Request request = queue.take();
      handle(request);
  }

虽然我已经展示了使用JDK中的Queue类的简单实现,但是诸如各种JMS实现(例如ActiveMQ),Kafka,Redis之类的队列实现为您提供了更强大的抽象功能。例如,所有这些都允许您定义单个队列,但是消费者只能获取与标题匹配的消息(例如会话ID)。

在所有这些示例中,如果担心安全问题,则需要防止会话密钥窃取。

答案 3 :(得分:0)

两个线程在你正在使用的公共锁上相互通信。如果两个线程需要相互通信,那么在它们之间使用一个公共锁。