代码之家  ›  专栏  ›  技术社区  ›  static void main

javanio中的缓冲写入/发送消息问题

  •  0
  • static void main  · 技术社区  · 15 年前

    我的问题是关于javanio客户机-服务器消息传递,我不确定从技术上定义问题,但是: 缓冲区似乎正在缓存数据,当缓存完成后,它将所有数据一起发送,这是令人不安的逻辑:

    private void sendCreate(String line,SocketChannel from)
     /* A new client wishes to join the world.
    
          This requires the client to find out about the existing
          clients, and to add itself to the other clients' worlds.
    
          Message format: create name xPosn zPosn
    
          Store the user's name, extracted from the "create" message
      */
     { StringTokenizer st = new StringTokenizer(line);
     st.nextToken();                  // skip 'create' word
     userName = st.nextToken();
     String xPosn = st.nextToken();   // don't parse
     String zPosn = st.nextToken();   // don't parse
    
     // request details from other clients
     sendBroadcastMessage( "wantDetails " + achannel.socket().getInetAddress() + " " + port,from);
    
     // tell other clients about the new one
     sendBroadcastMessage( "create " + userName + " "+xPosn+" "+zPosn,from);
    
     } // end of sendCreate()
    

    负责从服务器广播消息的方法:

    private void sendBroadcastMessage(String mesg, SocketChannel from) {
      prepWriteBuffer(mesg);
      Iterator i = clients.iterator();
      while (i.hasNext()) {
       SocketChannel channel = (SocketChannel) i.next();
       if (channel != from)
        channelWrite(channel, writeBuffer);
      }
     }
    

    我假设这应该发送第一条消息,即sendBroadcastmessage(“wantDetails”+achannel.socket().getInetAddress()+“”+port,from);但这不是,它似乎正在等待其他方法调用,即sendBroadcastmessage(“create”+username+“”+xposn+“”+zposn,from);然后将这两条消息作为一条消息发送,这是影响应用程序逻辑。理想情况下,它应该或应该在第一次调用sendBroadcastmessage之后发送第一条消息,然后在客户端接收到第一个调用时处理其他调用。

    以下是sendBroadcastMessage()中使用的方法:

    private void prepWriteBuffer(String mesg) {
      // fills the buffer from the given string
      // and prepares it for a channel write
      writeBuffer.clear();
      writeBuffer.put(mesg.getBytes());
      writeBuffer.putChar('\n');
      writeBuffer.flip();
     }
    
     private void channelWrite(SocketChannel channel, ByteBuffer writeBuffer) {
      long nbytes = 0;
      long toWrite = writeBuffer.remaining();
    
      // loop on the channel.write() call since it will not necessarily
      // write all bytes in one shot
      try {
        nbytes += channel.write(writeBuffer);
    
      } catch (ClosedChannelException cce) {
       cce.printStackTrace();
      } catch (Exception e) {
       e.printStackTrace();
      }
      // get ready for another write if needed
      writeBuffer.rewind();
     }
    

    请提出一些解决方案。

    谢谢,

    吉比拉拉

    编辑: 这个呢,我从一些聊天应用程序得到了这个补丁:

    private void prepWriteBuffer(String mesg) {
            // fills the buffer from the given string
            // and prepares it for a channel write
            writeBuffer.clear();
            writeBuffer.put(mesg.getBytes());
            writeBuffer.putChar('\n');
            writeBuffer.flip();
        }
    
    
    // called needs to remove the channel if it fails, otherwise it will fail forever.
            private void channelWrite(SocketChannel channel, ByteBuffer writeBuffer)  {    
                long nbytes = 0;
                long toWrite = writeBuffer.remaining();
                // loop on the channel.write() call since it will not necessarily
                // write all bytes in one shot
                try {
                while (nbytes != toWrite) {
                    nbytes += channel.write(writeBuffer);
    
                    try {
                        Thread.sleep(CHANNEL_WRITE_SLEEP);
                    } catch (InterruptedException e) {
                    }
                }
            } catch (ClosedChannelException cce) {
            } catch (Exception e) {
            }
            // get ready for another write if needed
            writeBuffer.rewind();
        }
    
    1 回复  |  直到 15 年前
        1
  •  0
  •   Peter Lawrey    15 年前

    也许你是故意的

     while(writeBuffer.remaining()>0)
          channel.write(writeBuffer);
    

    然而,您的问题似乎是您假定消息之间存在某种类型的魔力标记。然而,这种划分并不存在。流只是字节流。当您以阻塞模式读取时,您将得到至少一个字节,您可能会得到更多,这可能跨越多次写入,但除非您包含在流中,在流中您希望消息开始和结束,否则您将无法知道。

    一种简单的方法是在消息的开头写下消息的长度,并且最多只读取一条消息,直到您获得所有消息为止。类似的东西。

    private void prepWriteBuffer(String mesg) {    
      // fills the buffer from the given string    
      // and prepares it for a channel write    
      writeBuffer.clear();
      byte[] bytes = mesg.getBytes());
      writeBuffer.putInt(bytes.length);    
      writeBuffer.put(bytes);
      writeBuffer.flip();    
     } 
    
    
    // called needs to remove the channel if it fails, otherwise it will fail forever.
    private void channelWrite(SocketChannel channel, ByteBuffer writeBuffer) throws IOException {    
     while(writeBuffer.remaining()>0)
          channel.write(writeBuffer);
     writeBuffer.rewind();
    }
    
    推荐文章