Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.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 使用Apache';HttpClient';_Java_Linux_Sockets_Timeout_Apache Httpclient 4.x - Fatal编程技术网

Java 使用Apache';HttpClient';

Java 使用Apache';HttpClient';,java,linux,sockets,timeout,apache-httpclient-4.x,Java,Linux,Sockets,Timeout,Apache Httpclient 4.x,我使用4与API通信,大部分时间我都会执行冗长的PUT操作。由于这些可能发生在不稳定的Internet连接上,我需要检测连接是否中断,并可能需要重试(使用恢复请求) 为了在现实世界中尝试我的日常工作,我启动了PUT操作,然后我翻转了笔记本电脑的Wi-Fi开关,导致任何数据流立即完全中断。然而,直到最终抛出SocketException需要很长时间(可能5分钟左右) 如何加快处理速度?我想将超时设置为30秒左右。 更新: 澄清一下,我的请求是一个PUT操作。因此,在很长一段时间(可能是几个小时)内

我使用4与API通信,大部分时间我都会执行冗长的PUT操作。由于这些可能发生在不稳定的Internet连接上,我需要检测连接是否中断,并可能需要重试(使用恢复请求)

为了在现实世界中尝试我的日常工作,我启动了PUT操作,然后我翻转了笔记本电脑的Wi-Fi开关,导致任何数据流立即完全中断。然而,直到最终抛出SocketException需要很长时间(可能5分钟左右)

如何加快处理速度?我想将超时设置为30秒左右。

更新:

澄清一下,我的请求是一个PUT操作。因此,在很长一段时间(可能是几个小时)内,唯一的操作是write()操作,而没有读取操作。有一个,但我找不到一个用于写操作的

我使用自己的实体实现,因此我直接写入OutputStream,一旦Internet连接中断,OutputStream几乎会立即阻塞。如果OutputStreams有一个超时参数,这样我就可以写出
out.write(nextChunk,30000)我自己也能发现这样的问题。实际上我试过:

公共类TimeoutHttpEntity扩展HttpEntityWrapper{
公共超时HttpEntity(HttpEntity包装属性){
超级(包装性);
}
@凌驾
public void writeTo(OutputStream outstream)引发IOException{
try(TimeOutputStreamWrapper=新的TimeOutputStreamWrapper(扩展,30000)){
super.writeTo(包装器);
}
}
}
公共类TimeOutputStreamWrapper扩展了OutputStream{
私有最终输出流委托;
私有最终长超时;
private final ExecutorService ExecutorService=Executors.newSingleThreadExecutor();
公共TimeOutputStreamWrapper(OutputStream委托,长超时){
this.delegate=委托;
this.timeout=超时;
}
@凌驾
公共无效写入(int b)引发IOException{
executeWithTimeout(()->{
委托书(b);
返回null;
});
}
@凌驾
公共无效写入(字节[]b)引发IOException{
executeWithTimeout(()->{
委托书(b);
返回null;
});
}
@凌驾
公共无效写入(字节[]b,int off,int len)引发IOException{
executeWithTimeout(()->{
代表。注销(b、off、len);
返回null;
});
}
@凌驾
public void close()引发IOException{
试一试{
executeWithTimeout(()->{
delegate.close();
返回null;
});
}最后{
executorService.shutdown();
}
}
private void executeWithTimeout(最终可调用任务)引发IOException{
试一试{
executorService.submit(任务).get(超时,时间单位为毫秒);
}捕获(超时异常e){
抛出新的IOException(e);
}捕获(执行例外){
最终可丢弃原因=e.getCause();
如果(导致IOException实例){
抛出(IOException)原因;
}
抛出新错误(原因);
}捕捉(中断异常e){
抛出新错误(e);
}
}
}
公共类TimeOutputStreamWrapperTest{
私有静态最终字节[]DEMO_数组=新字节[]{1,2,3};
私有TimeOutputStreamWrapper流包装器;
私有输出流delegateOutput;
公共无效设置(长超时){
delegateOutput=mock(OutputStream.class);
streamWrapper=新的TimeoutOutputStreamWrapper(delegateOutput,超时);
}
@后置法
public void teardown()引发异常{
streamWrapper.close();
}
@试验
public void write_writesByte()引发异常{
//设置
设置(长最大值);
//执行
streamWrapper.write(演示数组);
//评价
验证(delegateOutput)。写入(DEMO_数组);
}
@测试(expectedExceptions=DemoIOException.class)
public void write_passesthrueexception()引发异常{
//设置
设置(长最大值);
doThrow(DemoIOException.class).when(delegateOutput.write)(DEMO_数组);
//执行
streamWrapper.write(演示数组);
//由预期异常执行的评估
}
@测试(expectedExceptions=IOException.class)
public void write_throwsIOException_onTimeout()引发异常{
//设置
最终倒计时闩锁执行完成=新倒计时闩锁(1);
设置(100);
doAnswer(新答案){
@凌驾
公共Void应答(invocationmock调用)抛出可丢弃的{
执行完毕。等待();
返回null;
}
}).when(delegateOutput).write(DEMO_数组);
//执行
试一试{
streamWrapper.write(演示数组);
}最后{
执行完毕。倒计时();
}
//由预期异常执行的评估
}
公共静态类DemoIOException扩展了IOException{
}
}
这有点复杂,但在我的单元测试中效果很好。它在现实生活中也可以工作,除了
HttpRequestExecutor
捕获第127行中的异常并尝试关闭连接。但是,当尝试关闭连接时,它首先尝试刷新连接,这会再次阻塞连接

我可能能够深入研究HttpClient,并找出如何防止这种刷新操作,但它已经不是一个很好的解决方案,而且它将变得更糟

更新


看起来这不能在Java级别上完成。我能在另一个层次上做吗?(我正在使用Linux)。

您可以使用RequestConfig配置套接字超时:

RequestConfig myRequestConfig = RequestConfig.custom()
    .setSocketTimeout(5000)  // 5 seconds
    .build();
当您进行呼叫时,只需分配新配置即可。比如说,

HttpPut httpPut = new HttpPut("...");
httpPut.setConfig(requestConfig);
...
HttpClientContext context = HttpClientContext.create();
....
httpclient.execute(httpPut, context);

有关超时配置的详细信息,有一个很好的解释。

Java阻塞I/O不支持写入操作的套接字超时。您完全可以由OS/JRE来解锁被阻塞的线程
public static class IdleConnectionMonitorThread extends Thread {

private final HttpClientConnectionManager connMgr;
private volatile boolean shutdown;

public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
    super();
    this.connMgr = connMgr;
}

@Override
public void run() {
    try {
        while (!shutdown) {
            synchronized (this) {
                wait(5000);
                // Close expired connections
                connMgr.closeExpiredConnections();
                // Optionally, close connections
                // that have been idle longer than 30 sec
                connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
            }
        }
    } catch (InterruptedException ex) {
        // terminate
    }
}

public void shutdown() {
    shutdown = true;
    synchronized (this) {
        notifyAll();
    }
}}