简体   繁体   English

如何保持TCP套接字打开?

[英]How to keep TCP sockets open?

Our application has a ping-pong like conversation with many servers (each server has a corresponding thread where those connections are made). 我们的应用程序具有与许多服务器的类似乒乓的对话(每个服务器都有一个用于建立这些连接的对应线程)。 Code below works, but it opens a new connection for every new request and is used only once, which soon leads to reaching max connection cap set by server. 下面的代码可以工作,但是它为每个新请求打开一个新连接,并且只能使用一次,这很快就会达到服务器设置的最大连接上限。

DataProvider.java 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);
}

How can I transform it, so everything can be done within one connection? 如何转换它,以便所有事情都可以在一个连接中完成? I figured I would do something like this: 我想我会做这样的事情:

SocketFactory.java 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 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);
}

but it just doesn't work and only the first one go through. 但是它只是行不通,只有第一个通过。

This loop reads until the end of the stream. 该循环读取直到流结束。

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

A stream only ends once. 流仅结束一次。 ie you can't end the stream but later use it again. 即您不能结束流,但是稍后再使用它。

What you need to do instead; 您需要做什么?

  • have a terminating line which can't occur in your data. 有一个终结行,该终结行不会出现在您的数据中。 eg wait for "[EOF]" 例如,等待"[EOF]"
  • send the length of data first and read only that much data. 首先发送数据长度,仅读取那么多数据。

尝试像第一个代码中那样使用URL而不是IP地址来初始化Socket对象,然后查看它是否对您有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM