首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >javaNIO中的缓冲区写入/发送消息问题

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

Stack Overflow用户
提问于 2010-11-27 04:46:48
回答 1查看 882关注 0票数 0

我的问题是关于JAVANIO客户端服务器消息传递,我不确定从技术上定义这个问题,但是:看起来buffer正在缓存数据,当它完成后,它会一起发送,这是令人不安的逻辑:

代码语言:javascript
复制
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()

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

代码语言:javascript
复制
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);然后将这两条消息作为一条消息发送,这是影响应用程序logic.ideally的一条消息,或者它应该在第一次调用sendBroadcastMessage之后发送第一条消息,然后当客户端收到第一个调用时,应该处理其他调用。

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

代码语言:javascript
复制
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();
 }

请建议一些解决方案。

谢谢,

摇摆拉拉

编辑:这个怎么样,我从一些聊天应用上得到了这个补丁:

代码语言:javascript
复制
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();
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-11-27 04:56:11

也许你是有意

代码语言:javascript
复制
 while(writeBuffer.remaining()>0)
      channel.write(writeBuffer);

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

一种简单的方法是在消息的开头写入消息的长度,并读取最多一条消息,直到您获得所有消息。就像这样。

代码语言:javascript
复制
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();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4288444

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档