SNMP 4 JパケットTCP-メッセージ送信時の1つのBUG
実際の使用では、クライアント(工業スイッチ)とローカルサービス側の接続が常に中断されているという問題が発見されました.もちろん、タイムアウトで自動的にクリーンアップされるわけではありません.
この割り込みは、確立して正常に使用できる場合もあれば、接続したのに正常に使用されない場合もあります.バックグラウンドログ印刷では、接続が存在するのにチャネルが閉じているとエラーが発生しています.
複数回のテストとブレークポイント追跡を経て、スイッチが一定時間実用的でない場合、接続が中断したと認定し、すぐに接続再構築を行いますが、この場合、サービス側がクライアントにメッセージを送信している場合、一定の確率で接続が確立しても使用できない場合があります.
このような場合、接続チャネルがオフになっていることをどこかでエラーが発生します.D e faultTcpTransportMapping内部クラスサーバThreadのprocessPendingメソッド:
彼が異常を起こした後、チャネルの接続を閉じ、状態変化イベントの通知を行うことができます.
しかし、スイッチの再接続後はすぐに使用できるはずですが、なぜチャネルが使用できないと報告されたのでしょうか.
いくつかの異常処理でチャネルを閉じたと思いますが、追跡とテストはこの問題ではないはずです.
彼がpendingというオブジェクトを操作しており、スレッドが安全であることを見て、私はこのオブジェクトに関する操作を追跡しました.彼の定義はこうです.
メッセージ送信時に操作されるコレクションです.
トレースブレークポイントは、クライアントが使用できない場合にメッセージを送信するとif((s==null)‖(s.isClosed()‖(!s.isConnected())の判定領域に入ることを発見します.この領域のコード実行の操作は、このアドレスに対してクライアント接続を確立し、データを送信することです.
これは明らかに間違っています.また、彼が接続を確立したときにスイッチの再起動や接続の再構築中だったため、エラーは報告されません.そのため、このメッセージはクライアント側がサービス側であるとして処理されます.
プロセスメソッドを実行するときはentry.getSocket().getChannel().close(); 前にスイッチのクライアントが接続されていましたが、接続が確立されたばかりでentryが実行されました.getSocket().getChannel().close();この接続を使用してメッセージを送信すると、チャネルが閉じていることをずっと示します.
私の提案は、ここでは接続が存在しないと認定してこのメッセージをクライアントメッセージとして送信するべきではなく、サービス側でなければ上記の判断領域を行うべきである.
また、DefaultTcpTransportMappingクラスにサービス側の属性があるかどうかは、次のとおりです.
もしあなたがサービス側であれば、この属性はTRUEです.
メッセージを送信するときは、次のように判断します.
もしあなたのメッセージがサービス側として送信された場合、この接続が正常に確立され、プログラムがまだ処理されている場合、メッセージは送信に成功します.
ITEYEサイトでオリジナルをご覧ください.ありがとうございます.
http://cuisuqiang.iteye.com/ !
自作ブログアドレス:http://www.javacui.com/、内容はITEYEと同期!
この割り込みは、確立して正常に使用できる場合もあれば、接続したのに正常に使用されない場合もあります.バックグラウンドログ印刷では、接続が存在するのにチャネルが閉じているとエラーが発生しています.
複数回のテストとブレークポイント追跡を経て、スイッチが一定時間実用的でない場合、接続が中断したと認定し、すぐに接続再構築を行いますが、この場合、サービス側がクライアントにメッセージを送信している場合、一定の確率で接続が確立しても使用できない場合があります.
このような場合、接続チャネルがオフになっていることをどこかでエラーが発生します.D e faultTcpTransportMapping内部クラスサーバThreadのprocessPendingメソッド:
private void processPending() {
synchronized (pending) {
for (int i=0; i<pending.size(); i++) {
SocketEntry entry = (SocketEntry)pending.getFirst();
try {
// Register the channel with the selector, indicating
// interest in connection completion and attaching the
// target object so that we can get the target back
// after the key is added to the selector's
// selected-key set
if (entry.getSocket().isConnected()) {
entry.getSocket().getChannel().register(selector,
SelectionKey.OP_WRITE);
}
else {
entry.getSocket().getChannel().register(selector, SelectionKey.OP_CONNECT);
}
}
catch (IOException iox) {
logger.error(iox);
// Something went wrong, so close the channel and
// record the failure
try {
entry.getSocket().getChannel().close();
TransportStateEvent e =
new TransportStateEvent(DefaultTcpTransportMapping.this,
entry.getPeerAddress(),
TransportStateEvent.STATE_CLOSED,
iox);
fireConnectionStateChanged(e);
}
catch (IOException ex) {
logger.error(ex);
}
lastError = iox;
if (SNMP4JSettings.isFowardRuntimeExceptions()) {
throw new RuntimeException(iox);
}
}
}
}
}
彼が異常を起こした後、チャネルの接続を閉じ、状態変化イベントの通知を行うことができます.
しかし、スイッチの再接続後はすぐに使用できるはずですが、なぜチャネルが使用できないと報告されたのでしょうか.
いくつかの異常処理でチャネルを閉じたと思いますが、追跡とテストはこの問題ではないはずです.
彼がpendingというオブジェクトを操作しており、スレッドが安全であることを見て、私はこのオブジェクトに関する操作を追跡しました.彼の定義はこうです.
private LinkedList pending = new LinkedList();
メッセージ送信時に操作されるコレクションです.
public void sendMessage(Address address, byte[] message) throws java.io.IOException {
Socket s = null;
SocketEntry entry = (SocketEntry) sockets.get(address);
if (logger.isDebugEnabled()) {
logger.debug("Looking up connection for destination '"+address+ "' returned: "+entry);
logger.debug(sockets.toString());
}
if (entry != null) {
s = entry.getSocket();
}
if ((s == null) || (s.isClosed()) || (!s.isConnected())) {
if (logger.isDebugEnabled()) {
logger.debug("Socket for address '"+address+ "' is closed, opening it...");
}
pending.remove(entry);
SocketChannel sc = null;
try {
// Open the channel, set it to non-blocking, initiate connect
sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress(((TcpAddress)address).getInetAddress(), ((TcpAddress)address).getPort()));
s = sc.socket();
entry = new SocketEntry((TcpAddress)address, s);
entry.addMessage(message);
sockets.put(address, entry);
synchronized (pending) {
pending.add(entry);
}
selector.wakeup();
logger.debug("Trying to connect to "+address);
}
catch (IOException iox) {
logger.error(iox);
throw iox;
}
}
else {
entry.addMessage(message);
synchronized (pending) {
pending.add(entry);
}
selector.wakeup();
}
}
トレースブレークポイントは、クライアントが使用できない場合にメッセージを送信するとif((s==null)‖(s.isClosed()‖(!s.isConnected())の判定領域に入ることを発見します.この領域のコード実行の操作は、このアドレスに対してクライアント接続を確立し、データを送信することです.
これは明らかに間違っています.また、彼が接続を確立したときにスイッチの再起動や接続の再構築中だったため、エラーは報告されません.そのため、このメッセージはクライアント側がサービス側であるとして処理されます.
プロセスメソッドを実行するときはentry.getSocket().getChannel().close(); 前にスイッチのクライアントが接続されていましたが、接続が確立されたばかりでentryが実行されました.getSocket().getChannel().close();この接続を使用してメッセージを送信すると、チャネルが閉じていることをずっと示します.
私の提案は、ここでは接続が存在しないと認定してこのメッセージをクライアントメッセージとして送信するべきではなく、サービス側でなければ上記の判断領域を行うべきである.
また、DefaultTcpTransportMappingクラスにサービス側の属性があるかどうかは、次のとおりです.
private boolean serverEnabled = false;
もしあなたがサービス側であれば、この属性はTRUEです.
メッセージを送信するときは、次のように判断します.
// TODO ,
if (!serverEnabled) {
もしあなたのメッセージがサービス側として送信された場合、この接続が正常に確立され、プログラムがまだ処理されている場合、メッセージは送信に成功します.
ITEYEサイトでオリジナルをご覧ください.ありがとうございます.
http://cuisuqiang.iteye.com/ !
自作ブログアドレス:http://www.javacui.com/、内容はITEYEと同期!