NIOシリーズ2:TCP傍受バインディング
注意:本明細書の適合対象はjava NIO APIの使用および非同期イベントモデル(Reactorモード)についてある程度理解する必要があり、主にjava原生NIOを使用してTCPリスニングバインディングを実現する過程と詳細設計について述べる.
最初にTCPアクセスサービスクラスを設計し、このクラスはAPIメソッドを提供し、ローカルの一連のアドレス(ポート)に対するリスニングバインディングを提供し、クラスの初期化後にSelectorのopen操作を以下のように完了した.
提供されるバインディングAPIは、次のように署名されます.
同期が必要な理由複数のスレッドが同時にこのメソッドを呼び出すことを望んでいないため、アドレスバインドが異常になります.
パラメータでは、複数のローカルアドレス(ポート)をリスニングバインドとともに渡すことができます.
NIOのバインド中にイベント登録を行う必要があります(OP_ACCEPTに興味があります).
登録プロセスでは、ロック競合に加えてデッドロックが発生する可能性があるため、通常、バインドアドレスをキューに配置して非同期登録を行うのはreactorスレッドによって処理されます.たとえば、次のようにします.
同期登録から非同期登録に変更すると、実際にバインドを登録するときにポートがバインドされている異常がある可能性があります.非同期の場合、スレッド間通信で異常メッセージを通知し、呼び出し元にフィードバックする必要があります.
上記のコードクリップのwait 0()メソッドがバインド結果を待つように、バインド異常が発生すると放出されます.
上記のコードはまた、NIO非同期モデルが同期APIに変換されることによるモデルインピーダンスが、追加の代価とオーバーヘッド、すなわちスレッド間通信を払うことを示している.
これにより、TCPサービス傍受プロセスが完了し、サービスアクセスおよびデータ伝送に関する設計の詳細が後述される.
最初にTCPアクセスサービスクラスを設計し、このクラスはAPIメソッドを提供し、ローカルの一連のアドレス(ポート)に対するリスニングバインディングを提供し、クラスの初期化後にSelectorのopen操作を以下のように完了した.
selector = Selector.open();
提供されるバインディングAPIは、次のように署名されます.
/**
* Binds to the specified local addresses and start to accept incoming connections. If any address binding failed then
* rollback the already binding addresses. Bind is fail fast, if encounter the first bind exception then throw it immediately.
*
* @param firstLocalAddress
* @param otherLocalAddresses
* @throws throw if bind failed.
*/
synchronized public void bind(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) throws IOException;
同期が必要な理由複数のスレッドが同時にこのメソッドを呼び出すことを望んでいないため、アドレスバインドが異常になります.
パラメータでは、複数のローカルアドレス(ポート)をリスニングバインドとともに渡すことができます.
NIOのバインド中にイベント登録を行う必要があります(OP_ACCEPTに興味があります).
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
ss.setReuseAddress(config.isReuseAddress());
ss.bind(address, config.getBacklog());
ssc.register(selector, SelectionKey.OP_ACCEPT);
登録プロセスでは、ロック競合に加えてデッドロックが発生する可能性があるため、通常、バインドアドレスをキューに配置して非同期登録を行うのはreactorスレッドによって処理されます.たとえば、次のようにします.
bindAddresses.addAll(localAddresses);
if (!bindAddresses.isEmpty()) {
synchronized (lock) {
// wake up for unblocking the select() to process binding addresses
selector.wakeup();
// wait for bind result
wait0();
}
}
同期登録から非同期登録に変更すると、実際にバインドを登録するときにポートがバインドされている異常がある可能性があります.非同期の場合、スレッド間通信で異常メッセージを通知し、呼び出し元にフィードバックする必要があります.
上記のコードクリップのwait 0()メソッドがバインド結果を待つように、バインド異常が発生すると放出されます.
private void wait0() throws IOException {
while (!this.endFlag) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new IOException(e);
}
}
// reset end flag
this.endFlag = false;
if (this.exception != null) {
IOException e = exception;
this.exception = null;
throw e;
}
}
上記のコードはまた、NIO非同期モデルが同期APIに変換されることによるモデルインピーダンスが、追加の代価とオーバーヘッド、すなわちスレッド間通信を払うことを示している.
これにより、TCPサービス傍受プロセスが完了し、サービスアクセスおよびデータ伝送に関する設計の詳細が後述される.