我认为当客户端使用 readObject 从服务器等待 java 对象时,如果服务器关闭,则会在客户端上导致 IOException。但这种情况不会发生,即使服务器挂掉,客户端也不知道,并继续无限期地等待 readObject。 如果这种行为是正常的,我希望一些专家告诉我是否有一种方法可以对服务器何时死亡进行建模,以便我可以在服务器恢复时重新连接到它。 如果服务器的死亡导致客户端出现异常,我希望帮助找出为什么我没有得到这种行为(我要疯了)。
我留下下面的代码。谢谢。
@覆盖 公共无效运行(){
QueryCommunicationObject qcoRecibido;
while(true){
try {
qcoRecibido=(QueryCommunicationObject) SmartSecretary.getSocketAltasOis().readObject();
// Comprobamos que está correctamente firmado
if( SmartSecretary.getFirmaPublicaAltas().comprobar(QueryCommunicationObject.qcoToByteArrayPreSignature(qcoRecibido), qcoRecibido.getSignedHash()) ){
// Comprobamos que nos envía el QCO el servidor de altas
if(Arrays.equals(qcoRecibido.getDireccionOrigen(),SmartSecretary.getDireccionPublicaAltas())){
if(qcoRecibido.getTipo()==8){ //
SmartSecretary.getDireccionesAutorizadas().add(new OriginAddressWrapper(qcoRecibido.getDocumento()));
}else if(qcoRecibido.getTipo()==7){ // Eliminación de usuario autorizado
// Eliminamos al usuario
// en Documento mapeamos la direccion origen a ser eliminada
SmartSecretary.getDireccionesAutorizadas().remove(new OriginAddressWrapper(qcoRecibido.getDocumento()));
}else{
System.out.println("$$$$$$ Recibido QCO Indebido con servidor de altas, Tipo:"+qcoRecibido.getTipo());
}else{
logger.log(Level.INFO, "$$$$$$ SecretaryAltasQCOListener: ServidoRecibido QCO bien firmado pero desde una IP distinta al servidor de altas");
}
}else{ // Si recibimos un QCO mal firmado
System.out.println("$$$$$$ QCO con el ACK Mal firmado por Servidor de altas:");
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "$$$$$$ Error IO de en socket con el Servidor de Altas:"+ex.getMessage());
// Iniciamos la reconexión
try {
SmartSecretary.getSocketAltas().close();
} catch (Exception ex1) {
logger.log(Level.SEVERE, "$$$$$$ Se cierra el hilo por error de I/O con el servidor de Altas:"+ex1.getMessage());
}
// Necesaria por si somos llamados ante una reconexión, evitamos que antes de acabar de ejecutarnos otros posibles threads intenten
// enviar por un socket que no existe
SmartSecretary.setSocketAltas(null);
new SecretaryAltasIniciateCommunication().start();
System.out.println("$$$$$$ SecretaryAltasIniciateCommunication: CREAMOS UNA NUEVA INSTANCIA PARA RECONECTAR desde SecretaryAltasQCOListener");
// Dejamos que termine el hilo
break;
} catch (ClassNotFoundException ex) {
logger.log(Level.SEVERE, "$$$$$$ No se ha recibido un objeto QCO válido, desde el Servidor de Altas:"+ex.getMessage());
} catch (Exception ex){ // Añadida porque en pruebas me dio una excepción RuntimeException en teoría corregida por Oracle. Tambien una
// NullPointerException
logger.log(Level.SEVERE, "$$$$$$ SecretaryAltasIniciateCommunication: Ha llegado excepci\u00f3n no capturada. Mensaje:"+ ex.getMessage());
}
}
System.out.println("$$$$$$ SecretaryAltasQCOLIsterner: I DIE:");
}
您可能对互联网的运作方式感到困惑。您的客户端无法区分只是花时间向您发送数据的服务器和已经死亡的服务器之间的区别。要知道服务器已完全放弃/崩溃/突然挂起,需要有人主动向您发送一个包含数据“Hello - 该服务器已死亡”的数据包。鉴于服务器死机了,it肯定不会这样做。
操作系统可以完成这项工作;请注意,服务器进程已经终止,并在终止它们之前通过它所拥有的所有 TCP/IP 连接发送良好的挂断信号,但您现在依赖于该服务器的各种行为,显然这并没有发生。
互联网是基于数据包的 - 发生的情况是某些发送者已停止发送数据包,并且无法判断这是否意味着它已经死亡或仅仅意味着它很慢。
此问题的通常解决方案是超时。您假设“如果 30 秒内没有数据包到达,我们就断定服务器已死亡”。也许只是速度太慢,但如果是这样的话我们就会放弃; 30 秒太长了。”您可以使用
.setSoTimeout
在原始套接字上设置这些选项,并且您可以通过启动 Timer
或自行管理 30 秒超时并在底层 close()
上显式调用 InputStream
来自行完成。然后在你的 readObject 代码中会发生异常。