2010-11-26 9 views
0

私の問題は、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() 

方法:これは最初のメッセージすなわちsendBroadcastMessage( "wantDetails" + achannel.soを送るべきであると仮定し

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

はイムcket()。getInetAddress()+ "" +ポート、from);これは、他のメソッド呼び出し、つまりsendBroadcastMessage( "create" + userName + "" + xPosn + "" + zPosn)を待っているようで、両方のメッセージをアプリケーションロジックに影響する1つのメッセージとして送信しているようです。理想的には、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(); 
} 

これらはsendBroadcastMessageに使用されている方法()です。

おかげで、

jibbyのララ

編集: 何これについては、私はいくつかのチャットアプリからこのパッチを得た:

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

答えて

0

おそらくあなたはしかし

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

を意図しました、あなたの問題は、あなたが何らかのタイプのものがあると仮定しているように見えますメッセージ間のマジックマーカー。しかし、そのような仕切りは存在しない。ストリームは単なるバイトストリームです。ブロッキングモードで読み込んだ場合、少なくとも1バイトは得られますが、これは複数の書き込みにまたがる可能性がありますが、メッセージの開始と終了を期待するストリームにインクルードしない限り、あなたは知る方法がありません。

単純なアプローチは、メッセージの先頭にメッセージの長さを書き込み、すべてのメッセージを取得するまで、たかだか1つのメッセージを読むことです。何かのようなもの。

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

回答ありがとうございますが、これはこれらのメッセージの間に4つの追加文字を挿入し、それらを連結して送信しています。 –

+0

が正しい。受信者へのその方法は、4バイトを読み取って長さを決定し、メッセージの長さを事前に知ることができる。 –

+0

純粋なテキスト形式が必要な場合は、それを行うことができますが、NIOでメッセージの境界を見つけるためにそれをデコードするのは難しいです。 –

関連する問題