Заставьте Java IO Socket слушать так же, как ServerSocket - PullRequest
1 голос
/ 09 мая 2019

Я делаю интеграцию обмена финансовыми сообщениями следующим образом:

  1. Сервер имеет интерфейс для прослушивания запросов из клиентского сокета на конкретный IP-адрес и порт
  2. Сервер отправляетответ на каждый запрос, обратно в сокет клиента
  3. Кроме того, сервер отправляет запросы в тот же сокет клиента

Отлично работает следующее:

  1. Клиентский сокет (объект Socket Java IO) успешно отправляет запросы на интерфейс сервера
  2. Клиентский сокет успешно получает ответ на каждый запрос
try {
    Socket clientSocket = new Socket("example.com", 8888);    
    BufferedWriter output = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
    output.write(data);
    output.flush();
    BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    // Read responses or new request from input
} catch (IOException e) {
    e.printStackTrace();
}

Предполагается, что клиентский сокетполучать любой запрос от сервера - так же, как он получает ответы от того же сервера.Однако когда сервер инициирует запрос к клиентскому сокету, запрос никогда не принимается.Однако мы можем отследить трафик из tcpdump в клиентской среде.

Как заставить клиентский сокет прослушивать запросы от сервера, а не только ответы?

Обновление

Может помочь кое-что прояснить в этой интеграции:

a.«Сервер» в данном случае представляет собой стороннюю систему с правилами интеграции

b.Мой клиентский сокет отправляет сообщение на сервер (см. Выше)

c.Моя реализация прослушивает ответы и запросы от стороннего системного сервера , либо путем создания моего серверного сокета (исключено), либо с использованием самого клиентского сокета Я отправляю с (решение, которое я искал)

Ответы [ 2 ]

0 голосов
/ 11 мая 2019

Это очень распространенная ошибка, вы пишете сообщение без записи "\ n" (идентификатор конечной строки) в конце, поэтому сообщения не будут прочитаны. Чтобы исправить это, используйте PrintWriter с println .

Это отправит строку в другой сокет.

Вот пример модели сервера для каждого клиента

//create a new server socket with the port as a parameter, this will bind it to the specified port: 6000
        ServerSocket server = new ServerSocket(6000);
        System.out.println("Binded");
        //create a while loop accepting sockets
        while(true)
        {
            //accept a socket
            Socket client = server.accept();
            System.out.println("Client has connected");
            //create a new thread for this socket
            new Thread(() ->
            {
                try
                {
                    /*
                    create a print writer so you can write a line, not only a message like BufferedWriter does,
                    if for some reason you still want to use BufferedWriter use
                    writer.write(message + "\n");
                     */
                    PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
                    //Create a new reader
                    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    System.out.println("Waiting for requests...");
                    //create a while loop reading requests (lines)
                    String request;
                    while((request = reader.readLine()) != null)
                    {
                        System.out.println("Received message: " + request);
                        //here find the correct response and return it, I just sent a message, replace it with the correct response
                        writer.println("Hello there! How are you today?");
                        //flush, flushing will write the data to the client
                        writer.flush();
                    }
                } catch(IOException e)
                {
                    //print an exception if it occurred, if an exception occurrs its most likely just a disconnection exception
                    e.printStackTrace();
                }
            }).start();
        }

а вот пример клиента

//connect to the server at "localhost" on port 6000
        Socket client = new Socket("localhost", 6000);
        System.out.println("Connected");
        /*
        create a print writer so you can write a line, not only a message like BufferedWriter does,
        if for some reason you still want to use BufferedWriter use
        writer.write(message + "\n");
        */
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
        //Create a new reader
        BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
        //write a request
        writer.println("Hi there!");
        //flush, flushing will write the data to the server
        writer.flush();
        System.out.println("Written");
        System.out.println("Waiting for responses...");
        //create a while loop reading responses (lines)
        //you may want to do this while loop in another thread
        String response;
        while((response = reader.readLine()) != null)
        {
            System.out.println("Received response: " + response);
        }

Также, если это связано с финансовой информацией, я рекомендую использовать TLS (SSL) .

Вам не нужно беспокоиться о том, что Java уже реализовала его и упростила его использование, вот пример сервера

//create a new SSL server socket with the port as a parameter, this will bind it to the specified port: 6000
        //you create it by getting the default SSLServerSocketFactory which will create a new SSLServerSocket
        //you need to cast it since it actually returns ServerSocket but SSLServerSocket extends ServerSocket and this returns SSLServerSocket so it is safe
        SSLServerSocket server = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(6000);
        System.out.println("Binded");
        //set the enabled ciphersuites, until you buy a certificate set only to ciphersuites with "anon" more info on ciphersuites on https://en.wikipedia.org/wiki/Cipher_suite
        server.setEnabledCipherSuites(new String[]{"TLS_ECDH_anon_WITH_AES_256_CBC_SHA"});
        //create a while loop accepting sockets
        while(true)
        {
            //accept a socket a SSLSocket
            SSLSocket client = (SSLSocket) server.accept();
            System.out.println("Client has connected");
            //create a new thread for this socket
            new Thread(() ->
            {
                try
                {
                    //begin a handshake more info about handshakes in https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/sy10660_.htm
                    client.startHandshake();
                    /*
                    create a print writer so you can write a line, not only a message like BufferedWriter does,
                    if for some reason you still want to use BufferedWriter use
                    writer.write(message + "\n");
                     */
                    PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
                    //Create a new reader
                    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    System.out.println("Waiting for requests...");
                    //create a while loop reading requests (lines)
                    String request;
                    while((request = reader.readLine()) != null)
                    {
                        System.out.println("Received message: " + request);
                        //here find the correct response and return it, I just sent a message, replace it with the correct response
                        writer.println("Hello there! How are you today?");
                        //flush, flushing will write the data to the client
                        writer.flush();
                    }
                } catch(IOException e)
                {
                    //print an exception if it occurred, if an exception occurrs its most likely just a disconnection exception
                    e.printStackTrace();
                }
            }).start();
        }

А вот пример клиента

//connect to the server at "localhost" on port 6000
        //you create a SSLSocket by getting the default SSLSocketFactory which will create a new SSLSocket
        //you need to cast it since it actually returns Socket but SSLSocket extends Socket and this returns SSLSocket so it is safe
        SSLSocket client = (SSLSocket) SSLSocketFactory.getDefault().createSocket("localhost", 6000);
        System.out.println("Connected");
        //set the enabled ciphersuites to everything supported so the server can decide the ciphersuite, you can modify this to specified ciphersuites
        client.setEnabledCipherSuites(client.getSupportedCipherSuites());
        //begin a handshake more info about handshakes in https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/sy10660_.htm
        client.startHandshake();
        /*
        create a print writer so you can write a line, not only a message like BufferedWriter does,
        if for some reason you still want to use BufferedWriter use
        writer.write(message + "\n");
        */
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
        //Create a new reader
        BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
        //write a request
        writer.println("Hi there!");
        //flush, flushing will write the data to the server
        writer.flush();
        System.out.println("Written");
        System.out.println("Waiting for responses...");
        //create a while loop reading responses (lines)
        //you may want to do this while loop in another thread
        String response;
        while((response = reader.readLine()) != null)
        {
            System.out.println("Received response: " + response);
        }
0 голосов
/ 10 мая 2019

Это решение этой проблемы:

  • Создайте поток сервера, который будет прослушивать с помощью клиентского сокета. Ниже приведен код для прослушивающего потока сервера:
public class MessageServer extends Thread {

    private Socket clientSocket;

    // The constructor takes in the client socket
    public MessageServer(Socket clientSocket) {
        this.clientSocket = clientSocket;
    }

    public void run() {
        while(true) {
            try {
                BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                BufferedWriter output = new BufferedWriter(new OutputStreamWriter(serverSocket.getOutputStream()));
                // Read from BufferedReader
                // Logic to check if message is a response or new request and handle appropriately
                // Server posts responses to requests using the same socket
                output.write("response here...");
                output.flush();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }
}
  • Внутри конструктора клиентского сокета запустите серверный поток и предоставьте ему клиентский сокет, как показано в коде:
public class MessageClient {

    public Socket clientSocket;

    public MessageClient(Socket clientSocket) {
        this.clientSocket = clientSocket;
        // Run the server thread, supply it with the client socket
        new MessageServer(clientSocket).start();
    }

    public void send(String data) {
        try {   
            BufferedWriter output = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
            output.write(data);
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Это прекрасно работает.

...