Как сохранить открытые сокеты TCP? - PullRequest
0 голосов
/ 10 октября 2018

Наше приложение поддерживает пинг-понг в виде диалога со многими серверами (каждый сервер имеет соответствующий поток, в котором выполняются эти соединения).Приведенный ниже код работает, но он открывает новое соединение для каждого нового запроса и используется только один раз, что вскоре приводит к достижению максимального ограничения соединения, установленного сервером.

DataProvider.java

public static ZnResult sendTcpQuery(String xml, String url, int port) {
    List<ZnXmlResult> results = new ArrayList<>();
    String xmlString = xml != null ? new String((xml + "\n").getBytes()) : "";
    int error = ZnResult.OK;
    try (Socket clientSocket = new Socket(url, port)) {
        clientSocket.setSoTimeout(CONNECTION_TIMEOUT);
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        try (BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"))) {
            outToServer.writeBytes(xmlString);
            try (StringWriter responseFromServer = new StringWriter()) {
                String readLine;
                while ((readLine = inFromServer.readLine()) != null) {
                    ...
                }
            }
            outToServer.close();
            clientSocket.close();
        }
    } catch (Exception ex) {
        LOG.error("Exception {}", url + ":" + port, ex);
        error = ZnResult.ERR;
    }
    return error == ZnResult.OK ? new ZnResult(results) : new ZnResult(error);
}

Как я могу это преобразовать, чтобы все можно было сделать за одно соединение?Я подумал, что я бы сделал что-то вроде этого:

SocketFactory.java

public class SocketFactory {
private static HashMap<String, Socket> socketsByAddress = new HashMap<>();
private static HashMap<Socket, DataOutputStream> outputStreamsBySocket = new HashMap<>();
private static HashMap<Socket, BufferedReader> readersBySocket = new HashMap<>();

public static Socket getSocket(String address) {
    String ip = Tools.getIpFromAddress(address);
    int port = Tools.getPortFromAddress(address);
    Socket socket = socketsByAddress.get(address);
    if (socket == null) {
        try {
            socket = new Socket(ip, port);
            socket.setSoTimeout(60000);
            socketsByAddress.put(address, socket);
        } catch (IOException ex) {
            Logger.getLogger(SocketFactory.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    return socket;
}

public static DataOutputStream getOutputStream(Socket socket) {
    DataOutputStream outputStream = outputStreamsBySocket.get(socket);
    if (outputStream == null) {
        try {
            outputStream = new DataOutputStream(socket.getOutputStream());
            outputStreamsBySocket.put(socket, outputStream);
        } catch (IOException ex) {
            Logger.getLogger(SocketFactory.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    return outputStream;
}

public static BufferedReader getReader(Socket socket) {
    BufferedReader reader = readersBySocket.get(socket);
    if (reader == null) {
        try {
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            readersBySocket.put(socket, reader);
        } catch (IOException ex) {
            Logger.getLogger(SocketFactory.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    return reader;
}
}

DataProvider.java

public static ZnResult sendTcpQuery(String xml, String url, int port) {
    List<ZnXmlResult> results = new ArrayList<>();
    int error = ZnResult.OK;
    try {
        String xmlString = xml != null ? new String((xml + "\n").getBytes()) : "";
        Socket clientSocket = SocketFactory.getSocket(url + ":" + port);
        DataOutputStream outToServer = SocketFactory.getOutputStream(clientSocket);
        BufferedReader inFromServer = SocketFactory.getReader(clientSocket);
        outToServer.writeBytes(xmlString);
        try (StringWriter responseFromServer = new StringWriter()) {
            String readLine;
            while ((readLine = inFromServer.readLine()) != null) {
                ...
            }
        }
    } catch (Exception ex) {
        LOG.error("Exception {}", url + ":" + port, ex);
        error = ZnResult.ERR;
    }
    return error == ZnResult.OK ? new ZnResult(results) : new ZnResult(error);
}

, но это просто не работает, и только первыйодин пройти.

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Этот цикл читает до конца потока.

while ((readLine = inFromServer.readLine()) != null) {

Поток заканчивается только один раз.то есть вы не можете завершить поток, но позже используйте его снова.

Что вам нужно сделать вместо этого;

  • имеет завершающую строку, которая не может появляться в ваших данных.например, дождитесь, когда "[EOF]"
  • отправит сначала длину данных и прочитает только столько данных.
0 голосов
/ 10 октября 2018

Попробуйте запустить объект Socket, используя URL-адрес, а не IP-адрес, как вы делали в первом коде, и посмотрите, работает ли он для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...