Bufferwriting/sending messages problem in javaNIO
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_S开发者_运维百科LEEP);
} catch (InterruptedException e) {
}
}
} catch (ClosedChannelException cce) {
} catch (Exception e) {
}
// get ready for another write if needed
writeBuffer.rewind();
}
perhaps you intended
while(writeBuffer.remaining()>0)
channel.write(writeBuffer);
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.
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();
}
精彩评论