【问题标题】:Muitiplexed socket communication in JavaJava中的多路套接字通信
【发布时间】:2014-06-06 20:03:45
【问题描述】:

我正在编写一个服务器程序,它可以接受来自多个(但固定)数量的客户端的通信。我想让程序保持单线程。为此,我使用非阻塞套接字来迭代每个客户端,但每个客户端的通道都使用阻塞模式。这是我的服务器代码:

class server {
    public static void main(String args[])
         throws Exception {

        ServerSocketChannel channel = ServerSocketChannel.open();
        channel.configureBlocking(false);
        channel.socket().bind(new java.net.InetSocketAddress("localhost", 8005));
        System.out.println("Server attivo porta 8005");
        Selector selector = Selector.open();
        channel.register(selector, SelectionKey.OP_ACCEPT);

        for(;;) {
          selector.select();
          Set keys = selector.selectedKeys();
          Iterator i = keys.iterator();

          while(i.hasNext()) {
            SelectionKey key = (SelectionKey) i.next();

            i.remove();

            if (key.isAcceptable()) {
              SocketChannel client = channel.accept();
              client.configureBlocking(true);

              ObjectInputStream ois = new ObjectInputStream(
                    client.socket().getInputStream());
              String s = (String)ois.readObject();
              System.out.println(s);
            }
          }
        }
    }
}

客户端使用简单的阻塞 I/O,如下所示:

class client {
    public static void main(String args[]) throws Exception {
        SocketChannel channel = SocketChannel.open();

        channel.configureBlocking(true);

        channel.connect(new java.net.InetSocketAddress("localhost", 8005));

        ObjectOutputStream oos = new ObjectOutputStream
              (channel.socket().getOutputStream());

        for (int i = 0; i < 100; i++) {
             oos.writeObject(new String("Hello " + i));
             System.out.println(i);
         }
    }
}

问题是,虽然客户端想写 100 次,但服务器只读取一次消息。服务器和客户端都没有给出任何异常,但我只从服务器获取输出“Hello 0”。我在这里做的事情有什么问题吗?如果是这样,我有什么选择?

谢谢。

更新:在服务器循环中关闭 ObjectInputStream 会导致客户端出现 BrokenPipeException(服务器的行为方式相同)。

【问题讨论】:

  • 在服务器端,您永远不会关闭您的ObjectOutputStream。您要么需要阅读直到获得EOF,要么在获得对象后关闭它并继续循环。
  • @Baldy 你是说 ObjectInputStream 吗?在服务器端,没有输出流,只有输入流。
  • 是的,ObjectInputStream。请参阅下面的答案。
  • @Baldy 请检查更新。在这种情况下它没有帮助。感谢您的调查。

标签: java sockets socket.io


【解决方案1】:

问题是您只是在检查与key.isAcceptable() 的新连接。您还需要使用key.isReadble() 检查读取。您应该只从key.isAcceptable() 进行连接设置。

Java ServerSocketChannel SocketChannel (Callback)

【讨论】:

  • 我永远不会让 key.isReadable() 为真。可能是因为客户端 SocketChannel 设置为阻塞模式。
  • 另外,由于它是一个阻塞读取,我知道即使我只检查 key.isAcceptable(),服务器也应该阻塞等待数据进来。
  • 您需要为读取设置解锁模式。另外,请查看我发布的链接,因为您需要在连接时执行其他设置项目才能真正使读取选择器正常工作。由于您尝试使用单个线程完成所有操作,因此阻塞实际上没有意义。
  • 我理解你所说的阻塞 - 但是我将无法在这里使用 ObjectInputStream。这就是为什么我想让读写阻塞,同时启用多路读取。这根本不可能吗?
  • 理想情况下,您需要某种协议,以便知道何时有完整的数据集要转换。我可能会建议查看以 JSON 格式发送数据并使用非字母字符作为消息标记。然后,您只需缓冲入站数据,直到获得标记,然后将其传递给 JSON 解析器以转换为对象。您可以从更轻松的调试中受益,因为您可以轻松地在线查看原始数据和更轻松的版本控制(解析器可以忽略未知字段等)。由于ObjectWriter 不节省空间,因此您不会看到显着的尺寸损失。
【解决方案2】:

问题在于服务器没有等待客户端发送所有数据。在客户端服务器程序中,您需要做的是在两者之间建立清晰的协议,以便在传输/接收数据时它们是同步的。这通常是通过发送指定符号或在完成后关闭连接来指示传输结束的方式来完成的

【讨论】:

  • 但是在每次读取后关闭服务器中的 ObjectOutputStream 会在随后的写入尝试中给我一个 BrokenPipeException。
  • 请检查更新——我试图关闭输出流,但它给了我一个损坏的管道异常。非常感谢您的调查。
  • 由于这里是客户端写的,写完后客户端应该关闭连接,这样可以确保服务器按预期进行
  • 但是在客户端添加shutdownOutput也无济于事。你能说得具体一点吗?
猜你喜欢
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
  • 2021-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
相关资源
最近更新 更多