【问题标题】:Java - creating separate thread for sending objects over the InternetJava - 创建用于通过 Internet 发送对象的单独线程
【发布时间】:2012-05-30 12:11:29
【问题描述】:

我正在学习用 Java 编写用于事件驱动编程的 Battleships 游戏。游戏应该是网络游戏,我打算在一个应用程序中制作客户端和服务器。

这是代表我的应用程序结构的图像: class diagram http://dl.dropbox.com/u/41993645/mvc.jpeg

直截了当-我想编写将作为单独线程运行并负责远程视图-控制器通信的服务器类。因此,Server 类将负责:

  • 无限循环从套接字读取对象,如果有的话, 将它们放入控制器的 BlockingQueue 中。
  • 提供诸如“sendActionEventToView()”之类的方法,这将允许 Controller 以另一种方式传递对象 - 从 Controller 到远程 View。

不幸的是,当运行服务器线程时,整个应用程序停止响应。如果有人能告诉我我做错了什么,我将不胜感激。我认为这是服务器代码的问题部分:

/** Main Server method - responsible for reading objects
 *  and putting them in the queue if any arrived */
public void run() {
  GameEvent event;
  while(true) {
    try {
      event = (GameEvent)objectStream.readObject();
      if(event != null) eventQueue.put(event);
    } catch(ClassNotFoundException e) {
      e.printStackTrace();
    } catch(IOException e1) {
      e1.printStackTrace();
    } catch(InterruptedException e2) {
      e2.printStackTrace(); 
    }
  }
}

我认为线程挂在“readingObject()”上 - 如果流中没有任何对象,我如何强制它将处理器时间分配给另一个线程?

服务器的其余部分:https://github.com/mc-suchecki/Battleships/blob/master/controller/Server.java 应用程序的其余部分:https://github.com/mc-suchecki/Battleships

非常感谢您,如果有任何不清楚的地方,请发表评论。对不起我的英语。

【问题讨论】:

  • 在大多数人回答之前,您将不得不发布一些简洁的代码示例。我建议您添加更多println 调试或使用调试器来找出您的问题。
  • 谢谢,我已经发布了有问题的代码。我试过调试,但我的知识让我只是找到问题,但不幸的是没有解决它。
  • 您是在每个客户端启动一个线程,还是一次从一个客户端连接读取?
  • 好吧,我应该写的。游戏应该是 p2p - 开始时玩家选择是要托管游戏还是连接到另一台服务器。每台服务器只允许一个客户端。见 createServer() 和 connectToServer() 代码:github.com/mc-suchecki/Battleships/blob/master/view/View.java

标签: java multithreading sockets event-handling connection


【解决方案1】:

普通的 java 流是阻塞的。这意味着您通常希望每个套接字连接使用 2 个线程(假设双向通信)。对于每个套接字连接,一个线程专用于每个流(输入/输出)。

【讨论】:

  • 好的,我知道 - 我只尝试过单向通信。准确地说-服务器中只有一个套接字,客户端中只有一个套接字-应用程序应该是p2p。
【解决方案2】:

如果你的代码 public void run();使用 Thread 的 start 方法启动,readObject 只能阻塞该线程。

【讨论】:

  • 我在写服务器代码的时候也是这么想的,但是应用还是因为某种原因挂掉了。
【解决方案3】:

如果你真的在使用多个线程,那么当一个线程被阻塞时,其他线程就会运行。没有必要“强制”处理器给其他线程时间。

查看您的代码,您的视图会直接调用 Controller 的 run 方法,而不是将其交给另一个线程运行: https://github.com/mc-suchecki/Battleships/blob/75e6cf69d081c05845f4171bf42ce096ed5247a7/view/View.java#L48 这将导致 Controller's 代码在调用 createServer 的同一线程中运行。

在您的要点中,您已经将您的 Controller 提交到 Controller's 构造函数中的新线程 (https://gist.github.com/2835863#L46)。我假设您可以在视图中删除对“controller.run()”的调用。

【讨论】:

  • 谢谢,没错,controller.run() 是不需要的,但是问题还是存在的。
【解决方案4】:

确保您的 run 方法本身有一个线程。我怀疑您在一个线程上做了很多事情;您所有的线程实际上都是一个线程,它们都在套接字上等待。当他们(单数)读到一些东西时,他们只是回去再次等待套接字。

使用您的 IDE 确保您拥有所需的所有线程。使用您的调试器。挂起时暂停程序并检查所有线程。确保你至少有两个。 (如果你不这样做,那就是问题所在。)一个线程应该挂在读取的套接字上。检查其他人(如果存在)在哪里挂起并修复代码,以免他们不这样做。

【讨论】:

    【解决方案5】:

    我刚刚发现了问题——它在构造函数中:

    /** Server class constructor */
    public Server(BlockingQueue<GameEvent> queue) {
      eventQueue = queue;
      try {
        serverSocket = new ServerSocket(Constants.PORT_NUMBER);
        socket = serverSocket.accept();  
        inputStream = socket.getInputStream();  
        objectStream = new ObjectInputStream(inputStream);  
      } catch(IOException e) {
        e.printStackTrace();
      }  
      Thread thread = new Thread(this);
      thread.start();
    }
    

    线与socket = serverSocket.accept() 挂起应用程序之前 创建单独的线程。我不知道为什么,但是我在run() 方法中寻找了一个问题,并且是错误的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      • 2015-05-06
      • 2012-03-25
      • 2015-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多