Java NIOサーバ:リモートホストが既存の接続を強制的にシャットダウン

1889 ワード

Java NIOチャットルームでは、クライアントが強制的にシャットダウンすると、サーバは「java.io.IOException:リモートホストが既存の接続を強制的にシャットダウンした」と報告し、サーバはエラーを報告した後に動作を停止します.エラーはクライアントがシャットダウンしたことを意味しますが、サーバはこのソケットチャネルからデータを読み込んでIOExceptionを放出します.これは,クライアントが異常にシャットダウンすると,サーバのセレクタがクライアントソケットに対応するソケットチャネルSelectionKeyを取得し,このkeyの興味はOP_READは、このチャネルからデータを読み出す際にクライアントがソケットを閉じているため、「java.io.IOException:リモートホストが既存の接続を強制的に閉じた」というエラーが発生します.この問題を解決するのも簡単です.つまり、サーバがデータを読み込むときに異常が発生した場合、現在のkeyをキャンセルしてチャネルを閉じます.次のコードです.

//   key          
SocketChannel channel = (SocketChannel) key.channel();  
//       1024k      
ByteBuffer buffer = ByteBuffer.allocate(1024);  
StringBuffer sb = new StringBuffer();  
//             
int count = 0;  
try{  
    count = channel.read(buffer);  
}catch(IOException e){  
    key.cancel();  
    channel.socket().close();  
    channel.close();  
    return;  
}

catchでkeyがキャンセルされたためreadMsgが戻るとrunメソッドは下に進み続け、前のコードは「java.nio.channels.CancelledKeyException」エラーを報告するので、現在のkeyが有効かどうかを判断する必要があります.
前のコード:
//  key       " "  
if (key.isReadable()) {  
    readMsg(key);  
}  
//  key       " "  
if (key.isWritable()) {  
    writeMsg(key);  
}  

修正後のコード:
//  key       " "  
if (key.isValid() && key.isReadable()) {  
    readMsg(key);  
}  
//  key       " "  
if (key.isValid() && key.isWritable()) {  
    writeMsg(key);  
} 

このように改良されたチャットルームサービス側では,クライアントが異常に強制的に閉鎖されると,サーバが適切に処理され,エラーも報告されず,稼働を停止することもない.改良後は比較的安定して運行している.
参考資料:
http://blog.csdn.net/abc_key/article/details/29295569