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 楼答案
也许你是有意的
然而,您的问题似乎是,您假定消息之间存在某种类型的魔法标记。然而,不存在这样的分割线。流就是字节流。当你在阻塞模式下读取时,你会得到至少一个字节,你可能会得到更多,这可能会跨越多个写入,但除非你在流中包含一条消息的开始和结束,否则你将无法知道
一个简单的方法是在消息的开头写下消息的长度,最多读一条消息,直到你得到所有消息。差不多吧