現在、ノンブロッキング SocketChannel (Java 1.6) を使用して、Redis サーバーのクライアントとして機能しています。Redis はソケットを介してプレーンテキスト コマンドを直接受け入れ、CRLF で終了し、同様に応答します。簡単な例を次に示します。
送信: 'PING\r\n'
RECV: '+PONG\r\n'
Redis は、\r\n で終わるデータの多くのセクションをすべて単一の応答の一部として、(要求内容に応じて) 巨大な応答を返すこともできます。
標準のwhile(socket.read() > 0) {//append bytes}ループを使用して、ソケットからバイトを読み取り、クライアント側でそれらを再アセンブルして応答にします。
注: 私はセレクターを使用していません。サーバーに接続された複数のクライアント側 SocketChannel を使用して、送受信コマンドのサービスを待機しています。
私が混乱しているのは、ノンブロッキングモードでのSocketChannel.read()メソッドのコントラクトです。具体的には、サーバーが送信を完了し、メッセージ全体を取得したことを知る方法です。
戻りが速すぎてサーバーに返信する機会を与えるのを防ぐための方法がいくつかありますが、私が行き詰まっていることの1つは次のとおりです。
- read()がバイトを返し、その後の呼び出しでバイトを返さずに、別の後続の呼び出しで再びいくつかのバイトを返すことは可能ですか?
基本的に、少なくとも 1 バイトを受信し、最終的にread()が 0 を返す場合、サーバーが応答を完了したことを信頼できますか?それとも、サーバーがビジー状態で、一部を返した可能性がありますか?待って試行し続けると、さらにバイトが増えますか?
read() が 0 バイトを返した後でもバイトを送信し続けることができる場合(以前の読み取りが成功した後)、サーバーが私との通信をいつ終了したかを知る方法がわかりません。スタイル通信は、サーバーがいつ「完了」したかを知ることさえできます。
ご存じのように、接続が停止していて、これらが標準的な長寿命の DB 接続でない限り、read は -1 を返しません。したがって、リクエストごとに閉じたり開いたりすることはありません。
一般的な回答 (少なくともこれらの NIO の質問に対して) は、Grizzly、MINA、または Netty を調べることであることを知っています。可能であれば、サードパーティの依存関係を採用する前に、これらすべてが生の状態でどのように機能するかを本当に知りたいです。
ありがとうございました。
ボーナス質問:
私は当初、ブロッキング SocketChannel がこれを使用する方法になると考えていました。コマンドを処理して応答を返すまで、発信者に何もしてほしくないからです。
それがより良い方法であることが判明した場合、指定されたバッファーを満たすのに十分なバイトがない限り、SocketChannel.read() がブロックされるのを見て少し混乱しました...すべてをバイト単位で読み取ることはできませんこのデフォルトの動作が実際にどのように使用されるのかわかりません...サーバーから返される応答の正確なサイズがわからないため、SocketChannel.read() への呼び出しは常にタイムアウトになるまでブロックされます (その時点で、コンテンツがバッファに残っていることが最終的にわかります)。
ブロッキングメソッドは常に読み取り時にハングアップするため、ブロッキングメソッドを使用する正しい方法についてはよくわかりません。