【发布时间】:2015-01-07 22:33:30
【问题描述】:
我正在尝试创建两个应用程序之间的消息监视器。这个想法是这个监视器在简单的客户端/服务器应用程序中间工作,并将消息记录到标准输出。该程序必须防止客户端/服务器出现故障(断开连接、超时等)。在代码中,我将客户端称为“起源”,将服务器称为“命运”。当前的问题是当服务器死机时,我的程序不知道,当客户端收到新消息时,出现此错误“软件导致连接中止:套接字写入错误”。当服务器重新启动时,此错误继续存在。我想当我在代码中询问“if (!socketToDestiny.isConnected())”时,它并没有真正连接。我确信问题在于我如何管理流中的“关闭”。
这是程序的代码,希望你能帮助我。
package interceptorprocess;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
public class GenericInterceptorProcess implements Runnable
{
private final String prefix_log_messages = "[CONNECTOR]";
//COMMUNICATION'S ORIGIN'S VARIABLES
ServerSocket serverSocketLocal;
Socket socketForLocal;
DataInputStream streamFromOrigin;
DataOutputStream streamToOrigen;
int len_message_from_origen;
byte[] buffer_msg_origin = new byte[4096];
byte[] message_origin = null;
//COMMUNICATION'S DESTINY'S VARIABLES
Socket socketToDestiny;
DataInputStream streamFromDestiny;
DataOutputStream streamToDestiny;
int len_message_from_destiny;
byte[] buffer_msg_destiny = new byte[4096];
byte[] message_destiny;
@Override
public void run()
{
//OCCASIONAL USE
String aux;
try
{
logger("STARTING SERVER --- PORT NUMBER: " + "1234");
//CREATING THE LOCAL SERVER SOCKET
serverSocketLocal = new ServerSocket(1234);
//CREATING THE DESTINITY CONNECTION WITH 15 TIMEOUT'S SECONDS
socketToDestiny = new Socket();
socketToDestiny.setSoTimeout(15000);
//THIS LOOP MAINTAINS THE CONNECTIVITY WITH ONE CLIENT AT TIME
while ( true )
{
logger("WAITING FOR A CONNECTION OF A CLIENT...");
socketForLocal = serverSocketLocal.accept();
//CREATING THE ORIGIN'S STREAMS
streamFromOrigin = new DataInputStream(socketForLocal.getInputStream());
streamToOrigen = new DataOutputStream(socketForLocal.getOutputStream());
logger("CONNECTED CLIENT: " + socketForLocal.getRemoteSocketAddress() );
//THIS LOOP MAINTAINS THE MESSAGES'S CHANGES
while ( true )
{
logger("WAITING FOR A MESSAGE..");
len_message_from_origen = streamFromOrigin.read(buffer_msg_origin);
if ( len_message_from_origen < 0 )
{
closeOriginStream();
break;
}
message_origin = new byte[len_message_from_origen];
//SAVE THE ORIGIN'S MESSAGE INTO AN ARRAY WHO HAS THE EXACT SIZE OF THIS MESSAGE
System.arraycopy(buffer_msg_origin, 0, message_origin, 0, len_message_from_origen);
aux = new String(message_origin);
logger("RECEIVED MESSAGE FROM ORIGIN: " + aux);
//TRY TO CONNECT TO DESTINY
try
{
if ( !socketToDestiny.isConnected() )
socketToDestiny.connect(new InetSocketAddress("10.10.200.200",1234),5000);
}
catch(IOException ex)
{
logger("CONNECTION REJECTED BY DESTINY: " + ex.getMessage());
continue;
}
//CREATING THE DESTINY'S STREAMS
streamFromDestiny = new DataInputStream(socketToDestiny.getInputStream());
streamToDestiny = new DataOutputStream(socketToDestiny.getOutputStream());
logger("SENDING MESSAGE TO DESTINY: " + aux);
//I HAD TO PUT THIS BLOCK BECAUSE IF THE DESTINY APPLICATIONS FAILS
//OR NOT ANSWER, THE PROGRAM MUST KEEP LISTENING THE FOLLOWING MESSAGES
try
{
//SENDING MESSAGE TO DESTINY
streamToDestiny.write(message_origin);
//READING THE ANSWER MESSAGE
logger("READING MESSAGE FROM DESTINY...");
len_message_from_destiny = streamFromDestiny.read(buffer_msg_destiny);
}
//IN ONE OF THE FOLLOWINGS TWO CATCHS I GET THE ERROR
catch (SocketTimeoutException ex)
{
logger("IT DIDN'T COULD RETRIEVE A MESSAGE FROM DESTINY: " + ex.getMessage());
continue;
}
catch (SocketException ex)
{
//THE "socketToDestiny.isConnected()" ALWAYS RETURNS TRUE SINCE THE FIRST SUCCESSFULLY
//CONNECTION, AFTER THAT, IF THE SOCKET IS DISCONNECTED, IT REMAINS RETURNING "true".
//THUS, I HAD TO MAKE THE NEXT CODE BLOCK
streamFromDestiny.close();
streamToDestiny.close();
socketToDestiny.close();
socketToDestiny = new Socket();
socketToDestiny.setSoTimeout(confs.timeout_destiny);
socketToDestiny.connect(new InetSocketAddress(confs.destiny_ip,confs.destiny_port),confs.timeout_connections);
streamFromDestiny = new DataInputStream(socketToDestiny.getInputStream());
streamToDestiny = new DataOutputStream(socketToDestiny.getOutputStream());
logger("TRYING TO RECONNECT WITH DESTINY AND SEND THE MESSAGE... ");
logger("READING MESSAGE FROM DESTINY AFTER ERROR...");
len_message_from_destiny = streamFromDestiny.read(buffer_msg_destiny);
}
message_destiny = new byte[len_message_from_destiny];
//SAVE THE DESTINY'S MESSAGE INTO AN ARRAY WHO HAS THE EXACT SIZE OF THIS MESSAGE
System.arraycopy(buffer_msg_destiny, 0, message_destiny, 0, len_message_from_destiny);
aux = new String(message_destiny);
logger("RECEIVED MESSAGE FROM DESTINY " + aux);
//SENDING THE ANSWER BACK TO THE ORIGIN
logger("SENDING BACK THE MESSAGE TO ORIGIN...");
streamToOrigen.write(message_destiny);
logger("MESSAGE DELIVERED SUCCESSFULLY!");
} //INTERNAL LOOP OF MESSAGES
} //INTERNAL LOOP OF CLIENTS
} //TRY
catch(IOException ex )
{
logger("THE SERVICE DIED: " + ex.getMessage() );
ex.printStackTrace();
} //CATCH
} //RUN
private void closeDestinyStream() throws IOException
{
streamFromDestiny.close();
streamToDestiny.close();
}
private void closeOriginStream() throws IOException
{
streamFromOrigin.close();
streamToOrigen.close();
}
private void closeAll() throws IOException
{
closeDestinyStream();
closeOriginStream();
}
private void logger(String message)
{
System.out.println(Utilidades.date() + " " + prefix_log_messages + " " + message);
}
}
问候!
对不起,我的英语不是母语。
【问题讨论】:
-
使用传统的客户端/服务器模型,当有趣的事情出现时简单地附加到日志文件不是更容易吗?我不知道你为什么要听和重复你说的话,而你自己可以很容易地写下来。我认为不需要中间人。
-
您好,是的,我同意您的观点,但我无法访问客户端/服务器的代码,而是可以访问 IP 和端口配置。该程序用于测试目的。如果我们这样做,接下来,我们可以更改消息的某些部分。
-
尝试注释掉您对
socketToDestiny.setSoTimeout()的调用 -
MMMM 我将失去“超时”功能,我需要它。
-
只要你知道你在做什么。该行将在运行 15 秒后使您的代码崩溃。 javadoc 说“将此选项设置为非零超时,对与此 Socket 关联的 InputStream 的 read() 调用将仅阻塞这段时间。如果超时到期,则会引发 java.net.SocketTimeoutException,虽然 Socket 仍然有效。必须在进入阻塞操作之前启用该选项才能生效。超时必须> 0。超时为零被解释为无限超时。我认为这是你的问题。