有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

javaNIO中的java缓冲区写入/发送消息问题

我的问题是关于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()+“”+端口,从);但事实并非如此,它似乎正在等待其他方法调用,即sendBroadcastMessage(“create”+用户名+“”+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) 个答案

  1. # 1 楼答案

    也许你是有意的

     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();
    }