javaNIO中的缓冲区写入/发送消息问题
我的问题是关于 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();
}
My problem is concerning JAVANIO client server message passing,i m unsure about defining the problem technically but:
it seems that buffer is caching the data and when it is done then it is sending all together which is disturbing logic:
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()
method responsible for broadcasting messages from server:
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);
}
}
i m assuming that this should send the first message i.e sendBroadcastMessage( "wantDetails " + achannel.socket().getInetAddress() + " " + port,from); but this is not,it seems that it is waiting for other method call i.e sendBroadcastMessage( "create " + userName + " "+xPosn+" "+zPosn,from);and then sending both message as one message which is affecting application logic.ideally it should or it should send the first message after first call to sendBroadcastMessage and then when client recive the first then other call should be processed.
these are methods which are using in 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();
}
please suggest some solution.
thanks,
jibby lala
Edit :
what about this,i got this patch from some chat app:
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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
也许您是有意的
但是,您的问题似乎是您假设消息之间存在某种类型的魔术标记。然而,不存在这样的分隔器。流只是字节流。当您在阻塞模式下读取时,您将至少获得一个字节,您可能会获得更多字节,这可能跨越多次写入,但除非您在流中包含您期望消息开始和结束的位置,否则您将无法知道。
一种简单的方法是在消息的开头写入消息的长度,并最多读取一条消息,直到获得全部消息。类似的东西。
perhaps you intended
However, you problem appears to be that you assume there is some type of magic marker between messages. However, no such divider exists. A stream is just a stream of bytes. When you read in a blocking mode you will get atleast one byte, you may get more this may span what was multiple writes but unless you include in the stream where you expect a message to start and end, you will have no way of knowing.
A simple approach is to write the length of the message at the start of the message and read at most single message until you get all of it. Something like.