使用 Java 在应用程序之间创建消息监视器

Creating a monitor of messages between applications with Java

我正在尝试创建两个应用程序之间的消息监视器。这个想法是这个监视器在简单的 client/server 应用程序中间工作,并将消息记录到标准输出。该程序必须防止 client/server 失败(断开连接、超时等)。在代码中,我将客户端称为 "origin",将服务器称为 "destiny"。当前的问题是当服务器死机时我的程序不知道,当来自客户端的新消息到来时,出现此错误"Software caused connection abort: socket write error"。当服务器再次启动时,此错误继续存在。我想当我在代码 "if ( !socketToDestiny.isConnected() )" 中询问时,它并没有真正连接。我确定问题出在我如何管理流中的 "close"。

这是程序的代码,希望你能帮到我。

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);
}
}

此致!

抱歉我的英语不好,我不是母语人士。

根据Java API,

public boolean isConnected()

Returns the connection state of the socket.

Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfuly connected prior to being closed.

Returns:
    true if the socket was successfuly connected to a server
Since:
    1.4

请注意,即使您关闭套接字,isConnect() 仍然return为真,因此很可能您的 isConnect() 用法不正确。

根据 Sumit Singh 对这个问题的回答,

How do I check if a Socket is currently connected in Java?

socket.isConnected() returns always true once the client connects (and even after the disconnect) weird !!

因此,即使在断开连接之后,isConnected() 也会 return 为真。所以我的假设(和你的一样)是虽然你捕获了 SocketWrite 异常,但 isConnected() 仍然 return 为真。我无法对此进行测试,因为它不是一个有效的示例。但是,您可以这样做:

try {

    //write message to server

} catch ( SocketException e ) {

    //we lost the connection, right? then print if the socket is connected
    System.out.println( socketToDestiny.isConnected() );
}

看看输出是什么。如果输出还是true,那么我们就发现问题了。如果我的假设是正确的,我会建议您尝试在 catch 语句中重新连接。例如:

try {

    //write message to server

} catch ( SocketException e ) {

    //we lost the connection, so let's try to reconnect
    while ( true ) {
        try {
            socketToDestiny.connect( ...ip address ... );
            break; 
        } catch ( IOException e2 ) {

            //keep trying to reconnect!
            continue;
        }
    }
}