2010-11-26 56 views
0

Mon problème concerne le passage du message du serveur client JAVANIO, je ne suis pas sûr de pouvoir définir le problème techniquement mais: il semble que le tampon cache les données et quand c'est fait, il envoie tout ensemble est logique inquiétante:Bufferwriting/envoi de messages problème dans 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() 
méthode

responsable de la diffusion de messages de serveur:

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

im en supposant que cela devrait envoyer le premier message-à-dire sendBroadcastMessage ("wantDetails" + achannel.so cket(). getInetAddress() + "" + port, à partir de); mais cela ne l'est pas, il semble qu'il attend l'appel d'une autre méthode, c'est-à-dire sendBroadcastMessage ("create" + userName + "" + xPosn + "" + zPosn, from), puis envoie le message comme un message qui affecte la logique de l'application. Idéalement, il devrait ou devrait envoyer le premier message après le premier appel à sendBroadcastMessage et ensuite lorsque le client reçoit le premier, puis l'autre appel devrait être traité.

ce sont des méthodes qui utilisent dans 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(); 
} 

s'il vous plaît suggérer une solution.

grâce,

Jibby lala

Edit: ce que ce sujet, je suis arrivé ce patch de certaines applications de chat:

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

Répondre

0

peut-être vous aviez l'intention

while(writeBuffer.remaining()>0) 
     channel.write(writeBuffer); 

Cependant , votre problème semble être que vous supposez qu'il y a un certain type de marqueur magique entre les messages. Cependant, aucun diviseur existe. Un flux est juste un flux d'octets. Quand vous lisez dans un mode de blocage, vous aurez au moins un octet, vous pouvez obtenir plus de ce qui a été écrit plusieurs fois, mais à moins d'inclure dans le flux où vous attendez un message commence et se termine, vous n'aurez aucun moyen de le savoir.

Une approche simple consiste à écrire la longueur du message au début du message et à lire au plus un message jusqu'à ce que vous obteniez tout. Quelque chose comme.

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

Merci pour la réponse, mais cela insère 4 caractères supplémentaires entre ces messages et les concaténant encore, puis l'envoi. –

+0

correct. De cette façon, le récepteur peut lire les 4 octets pour déterminer la longueur et connaître à l'avance la longueur du message. –

+0

Si vous avez besoin d'un format texte pur, vous pouvez le faire, mais le décoder pour trouver les limites du message avec NIO est plus compliqué. –