Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
尝试重用Java客户端套接字失败_Java_Sockets_Http_Servlets - Fatal编程技术网

尝试重用Java客户端套接字失败

尝试重用Java客户端套接字失败,java,sockets,http,servlets,Java,Sockets,Http,Servlets,我有一个与第三方控制器通信的软件驱动程序;我有一个使用后者的API,但它的源代码不可见,供应商在试图改进方面也不合作 情况如下 为了向控制器发送请求,我将一个XML数据包作为HTTP POST的内容发送到servlet,然后servlet向我发送响应。由以前的开发人员实现的原始代码使用java.net.Socket稳定地工作。然而,我们的驱动程序是这样实现的,即为每个发送的请求创建一个新的套接字,并且,如果驱动程序变得繁忙,第三方控制器将难以跟上套接字处理的步伐。事实上,他们的支持人员对我说:“

我有一个与第三方控制器通信的软件驱动程序;我有一个使用后者的API,但它的源代码不可见,供应商在试图改进方面也不合作

情况如下

为了向控制器发送请求,我将一个XML数据包作为HTTP POST的内容发送到servlet,然后servlet向我发送响应。由以前的开发人员实现的原始代码使用java.net.Socket稳定地工作。然而,我们的驱动程序是这样实现的,即为每个发送的请求创建一个新的套接字,并且,如果驱动程序变得繁忙,第三方控制器将难以跟上套接字处理的步伐。事实上,他们的支持人员对我说:“你真的需要在每个请求之间留出5秒钟……”。这在商业上是不可接受的

为了提高性能,我想尝试让套接字的一端保持打开状态,并无限期地重用套接字(当然,考虑到连接可能意外中断,但这是我最不关心的问题,也是可以管理的)。然而,无论我做什么,结果是如果我使用Comms.getSocket(false),就会为每个请求创建一个新的套接字,并且一切正常,但在繁忙时会出现瓶颈。如果使用Comms.getSocket(true),则会发生以下情况:

  • 控制器被发送第一个请求
  • 控制器响应第一个请求
  • 控制器收到第二个请求(可能5秒后)
  • 控制器从不响应第二个请求或之后的任何请求
  • postRequest()不断被调用:在前12秒,控制台输出“Input Shutdown?false”,但在那之后,代码不再到达那里,也无法通过bw.write()和bw.flush()调用
控制器允许HTTP 1.0和1.1,但他们的文档中说关于保持活动状态的内容太多了。我已经尝试了这两种方法,下面的代码显示我也添加了Keep-Alive头,但是作为服务器的控制器,我猜是忽略了它们——我想我没有办法知道,是吗?在HTTP 1.0模式下,控制器肯定会返回“连接:关闭”,但在HTTP 1.1模式下不会这样做

服务器端很可能坚持“每个请求一个套接字”的方法。

然而,我想知道我是否在以下代码中做了任何错误(或遗漏了什么),以实现我想要的:

private String postRequest() throws IOException {
    String resp = null;
    String logMsg;
    StringBuilder sb = new StringBuilder();
    StringBuilder sbWrite = new StringBuilder();
    Comms comms = getComms();
    Socket socket = comms.getSocket(true);
    BufferedReader br = comms.getReader();
    BufferedWriter bw = comms.getWriter();
    if (null != socket) {
        System.out.println("Socket closed ? " + socket.isClosed());
        System.out.println("Socket bound ? " + socket.isBound());
        System.out.println("Socket connected ? " + socket.isConnected());

        // Write the request
        sbWrite
            .append("POST /servlet/receiverServlet HTTP/1.1\r\n")
            .append("Host: 192.168.200.100\r\n")
            .append("Connection: Keep-Alive\r\n")
            .append("Keep-Alive: timeout=10\r\n")
            .append("Content-Type: text/xml\r\n")
            .append("Content-Length: " + requestString.length() + "\r\n\r\n")
            .append(requestString);
        System.out.println("Writing:\n" + sbWrite.toString());
        bw.write(sbWrite.toString());
        bw.flush();

        // Read the response
        System.out.println("Input shut down ? " + socket.isInputShutdown());
        String line;
        boolean flag = false;
        while ((line = br.readLine()) != null) {
            System.out.println("Line: <" + line + ">");
            if (flag) sb.append(line);
            if (line.isEmpty()) flag = true;
        }
        resp = sb.toString();
    }
    else {
        System.out.println("Socket not available");
    }
    return resp; // Another method will parse the response
}

有人能帮忙吗?

如果我们假设keep-alive东西按预期工作,我认为行
而((line=br.readLine())!=null)
是错误的,因为这是一种无限循环

readline()
在没有更多数据可读取时返回
null
,例如
EOF
,或者当服务器/客户端关闭连接时,这将中断您的重用套接字解决方案,因为开放流决不会导致
readline()
调用的
null
,而是阻塞

您需要修复有关读取响应的alg(为什么不使用已实现的http客户端?),检查
内容长度
,以及从正文中读取所需数据量时,通过保持套接字活动来进行下一个循环。 在将
flag
设置为
true
之后,您必须知道应该读取什么类型的数据(考虑mime/内容类型),除此之外,还要知道数据的长度,因此使用
readLine()
读取数据在这里可能不是一个好的做法


还要确保服务器允许持久性连接,通过响应相同的
连接:keep-alive
头来检查它是否尊重持久性连接。

如果我们假设keep-alive东西按预期工作,我认为行
而((line=br.readLine())!=null)
是错误的,因为这是一种无限循环

readline()
在没有更多数据可读取时返回
null
,例如
EOF
,或者当服务器/客户端关闭连接时,这将中断您的重用套接字解决方案,因为开放流决不会导致
readline()
调用的
null
,而是阻塞

您需要修复有关读取响应的alg(为什么不使用已实现的http客户端?),检查
内容长度
,以及从正文中读取所需数据量时,通过保持套接字活动来进行下一个循环。 在将
flag
设置为
true
之后,您必须知道应该读取什么类型的数据(考虑mime/内容类型),除此之外,还要知道数据的长度,因此使用
readLine()
读取数据在这里可能不是一个好的做法

另外,通过响应相同的
连接:keep-alive
头,检查服务器是否尊重持久性连接,确保服务器允许持久性连接

public Comms(String ip, int port) {
    this.ip = ip;
    this.port = port;
    initSocket();
}

private void initSocket() {
    try {
        socket = new Socket(ip, port);
        socket.setKeepAlive(true);
        socket.setPerformancePreferences(1, 0, 0);
        socket.setReuseAddress(true);
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
        System.out.println("@@@ CREATED NEW SOCKET");
    }
    catch (UnknownHostException uhe) {
        System.out.println("@@@ UNKNOWN HOST FOR SOCKET");
    }
    catch (IOException ioe) {
        System.out.println("@@@ SOCKET I/O EXCEPTION");
    }
}

public BufferedReader getReader() { return br; }

public BufferedWriter getWriter() { return bw; }

public Socket getSocket(boolean reuse) {
    if (! reuse) initSocket();
    return socket;
}