使用NIO选择器从客户端向服务器发送自定义消息

时间:2016-01-17 20:07:22

标签: java sockets nio

正如标题所示,我坚持正确使用选择器。我想到的过程是,首先将此客户端作为线程运行时,它将连接到服务器,等待确认(CONNACK)然后继续。到目前为止这么好,我收到的消息SUCCESS!服务器设置为在接受连接后读取。

while (iterator.hasNext()) {
     final SelectionKey key = (SelectionKey) iterator.next();

     iterator.remove();

     try (SocketChannel keySocketChannel = (SocketChannel) key.channel()) {

     //attempt connection
     if (key.isConnectable()) {
             System.out.print("Connecting");

             if (keySocketChannel.isConnectionPending()) {
                 keySocketChannel.finishConnect();
             }

             while (keySocketChannel.read(buffer) != -1) {
                 buffer.flip();

                 charBuffer = decoder.decode(buffer);
                 System.out.print(".");

                 if (buffer.hasRemaining()) {
                        buffer.compact();
                 } else {
                        buffer.clear();
                 }
                 if (charBuffer.toString().equals(MessageType.CONNACK.getName())) {
                        System.out.println("SUCCESS!");

                        //At this point, it makes sense that the next operation
                        //is a write.
                        key.interestOps(SelectionKey.OP_WRITE);
                        break;
                  }
                  try {
                        Thread.sleep(500);
                  } catch (InterruptedException e) {
                  }
              }
              System.out.println("SUCCESS!");
              key.interestOps(SelectionKey.OP_WRITE);
     } else if (key.isConnectable())  {
              System.out.println("connectable");
     } else if (key.isWritable()) {
              System.out.println("write key");
              write(key, socketChannel);
     } else if (key.isReadable()) {
              System.out.println("read key");
     }
              System.out.println("oops");
     } catch (IOException e) {
              e.printStackTrace();
     }
}

问题是当我调用publish方法时。我打算做的是将请求放在同步队列中。然后在write方法中(当key.isWritable()时)它检查队列,如果找到任何内容,则将其发送到服务器。

PUBLISH

 @Override
        public void publish(String message) {
            //create publish request
            final Request request = new Request(this.topic, message, MessageType.PUBLISH);

            System.out.println("Adding request to queue..");
            synchronized (this.dataQueue) {
                dataQueue.add(request);
            }
            this.selector.wakeup();
        }

问题是它永远不会到达key.isWritable()(因此,打印“写密钥”)。问题是什么?

1 个答案:

答案 0 :(得分:1)

当你要写东西时,只需写下来,然后检查返回值。 OP_WRITE只应在write()刚刚返回零的情况下使用。这里有很多答案,很多都是我的。