多线程 Java 服务器设置

发布于 2024-10-30 23:18:47 字数 1011 浏览 0 评论 0原文

我正在尝试编写一个支持网络多人游戏的游戏服务器。

我试图实现的是一个服务器,它循环监听连接并为每个客户端设置一个线程。它应该执行此操作,直到游戏主机单击开始游戏,然后它应该继续游戏逻辑、发送数据等。

为了实现此目的,我在此线程的 run 方法中使用此代码来循环并侦听连接。

try {
  while (gameStarted == false) {
      System.out.print(gameStarted);

      clientSocket = ss.accept();
      ClientThreadOnServer runClient = new ClientThreadOnServer(clientSocket);
      clientThreads.add(runClient);
      window.updateText();
  }
  System.out.println("end");

然后,在我的服务器中,我放置了一个可运行的内部类,该类会弹出一个带有计数器和开始按钮的 JFrame,其想法是,当用户单击框架中的开始游戏时,布尔值 gameStarted 会被翻转,如下所示:

public void actionPerformed(ActionEvent e) {
  if (e.getActionCommand().equals("start")) {
    synchronized (this) {
      System.out.println("click");
      gameStarted = true;
    }
  }
}

但是它没有工作!当您单击开始时,会检测到并按下按钮,因此布尔值可能会更改,但服务器不会退出 while 循环并继续。我想我知道为什么,循环位于 ss.accept();并且没有像我希望的那样测试布尔条件。

我不确定我是否以正确的方式处理这个问题,尤其是服务器上的客户端线程列表,我希望用它来控制数据的发送。如果我以完全错误的方式这样做,请让我知道应该如何完成,或者如果我没有疯,我该如何让我的代码工作?

I am trying to write a game server that supports multiplayer over a network.

What I am attempting to achieve is a server that listens in a loop for connections and sets up a thread for each client. it should do this until the host of the game clicks start game, upon which it should continue with the game logic, sending data etc.

To achieve this I use this code in the run method of this thread to loop and listen for connections.

try {
  while (gameStarted == false) {
      System.out.print(gameStarted);

      clientSocket = ss.accept();
      ClientThreadOnServer runClient = new ClientThreadOnServer(clientSocket);
      clientThreads.add(runClient);
      window.updateText();
  }
  System.out.println("end");

Within my server I then placed an runnable inner class that pops up a JFrame with a counter and a start button, with the idea being the boolean gameStarted gets flipped when the user clicks start game in the frame, like so:

public void actionPerformed(ActionEvent e) {
  if (e.getActionCommand().equals("start")) {
    synchronized (this) {
      System.out.println("click");
      gameStarted = true;
    }
  }
}

however it doesn't work! When you click start the button is detected and pressed so presumably the boolean is changed, but the server doesn't exit the while loop and continue on. I think I know why, the loop is sitting on ss.accept(); and not testing the boolean condition as I had hoped.

I'm not really sure if I am even going about this in the right way, especially the list of client threads on the server which I hope to then use to control the sending of data. If I am doing this in a totally wrong way please let me know how it should be done, or if I am not crazy, how do I make my code work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

酒绊 2024-11-06 23:18:47

accept() -
监听连接
建立到这个套接字并接受
它。该方法会阻塞,直到
连接已建立。

这意味着循环只会在客户端连接后立即检查游戏状态。您可以使用 setTimeout() 指定在抛出 SocketTimeoutException 表示客户端未连接之前,accept 调用可以阻塞多长时间。您可以在循环中使用它来使 accept() 不会永远阻塞,并允许您再次检查 gameStarted

注:
您并未在 gameStarted 上完全同步,只是在写入时完全同步。这意味着存在竞争条件,您可能会在单击开始后尝试接受其他客户端。解决此问题的最简单方法是使用以下方法。您不想将整个循环放入同步块中,因为这样开始按钮将永远无法进入其同步块,因为循环保持锁定。

private synchronized boolean isGameStarted() {
  return gameStarted;
}

...
try {
  while (!isGameStarted()) {
...

accept() -
Listens for a connection
to be made to this socket and accepts
it. The method blocks until a
connection is made.

This means that the loop will only check the game state right after a client has connected. You can use setTimeout() to specify the how long an accept call can block for before throwing a SocketTimeoutException to signify that a client did not connect. You can use that in your loop to cause accept() to not block forever and allow you to check gameStarted again.

Note:
You are not fully synchronizing on gameStarted, just on the write. This means there is a race condition and you might attempt to accept an additional client after start is clicked. The easiest way to fix this is with the following. You don't want to put the entire loop in a synchronized block because then the start button would never be able to enter it's synchronized block because the loop is holding the lock.

private synchronized boolean isGameStarted() {
  return gameStarted;
}

...
try {
  while (!isGameStarted()) {
...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文