【问题标题】:Repeated calls by Restlet client to Restlet server hangsRestlet 客户端对 Restlet 服务器的重复调用挂起
【发布时间】:2011-11-23 19:19:23
【问题描述】:

我正在使用 Restlet 来实现 Web 服务。客户端(也使用Restlet)连续多次调用服务器,但少量调用成功完成后,进一步的调用将服务器挂起,显示消息:

INFO:停止接受新的连接和事务。考虑增加最大线程数。

我试过了:

getContext().getParameters().add("maxThreads", "200");

但这无济于事。在任何情况下,客户端似乎应该能够进行无限数量的调用,并且增加 maxThreads 只会增加限制。看起来我没有在每次客户调用后释放一些资源或断开连接,但我不知道该怎么做。

以下(我可以做到的很小)独立程序演示了该问题。它启动一个简单的服务器,然后客户端多次调用它:

/** You may copy, modify, and re-use this code as you see fit - Jim Irrer */
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.restlet.Application;
import org.restlet.Component;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.Server;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Status;
import org.restlet.representation.InputRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.Directory;

public class SimpleServerPut extends Component implements Runnable {
    private static final int PORT = 8080;

    private static int readToByteArray(InputStream inputStream, byte[] buf) throws IOException {
        int length = 0;
        int b;
        while ((b = inputStream.read()) != -1) {
            buf[length++] = (byte)b;
        }
        return length;
    }

    @Override
    public void run() {
        getContext().getParameters().add("maxThreads", "200");

        // Create the HTTP server and listen on port PORT
        SimpleServerPut simpleServer = new SimpleServerPut();
        Server server = new Server(Protocol.HTTP, PORT, simpleServer);
        simpleServer.getClients().add(Protocol.FILE);

        // Create an application  
        Application application = new Application(simpleServer.getContext()) {  
            @Override  
            public Restlet createRoot() {  
                return new Directory(getContext(), "C:");  
            }  
        };

        // Attach the application to the component and start it  
        simpleServer.getDefaultHost().attach("/stuff/", application);
        try {
            server.start();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override  
    public void handle(Request request, Response response) {  
        // assume the worst
        response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
        response.setEntity("No no - Bad client!  Only do PUTs.", MediaType.TEXT_PLAIN);

        try {
            if (request.getMethod() == Method.PUT) {
                InputStream inputStream = request.getEntity().getStream();
                byte[] buf = new byte[64*1024];
                int totalLength = readToByteArray(inputStream, buf);
                response.setStatus(Status.SUCCESS_OK);
                String msg = "Number of bytes received: " + totalLength;
                response.setEntity(msg, MediaType.TEXT_PLAIN);
                System.out.println("server: " + msg);
                return;
            }
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static String callServer() throws IOException {
        String urlText = "http://localhost:" + PORT + "/";
        ClientResource clientResource = new ClientResource(urlText);
        clientResource.setReferrerRef(urlText);

        byte[] buf = new byte[1000];
        for (int i = 0; i < buf.length; i++) {
            buf[i] = (byte)((int)'a' + (i%26));
        }
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buf);
        Representation representation = new InputRepresentation(byteArrayInputStream, MediaType.APPLICATION_OCTET_STREAM);
        Representation representation2 = clientResource.put(representation);
        byte[] responseBuf = new byte[16*1024];
        int length = readToByteArray(representation2.getStream(), responseBuf);
        Response response = clientResource.getResponse();
        Status status = response.getStatus();
        return "status: " + status + "    message: " + new String(responseBuf, 0, length);
    }

    // Start server and call it a bunch of times
    public static void main(String[] args) throws Exception {
        SimpleServerPut simpleServer = new SimpleServerPut();
        new Thread(simpleServer).start();
        Thread.sleep(200);  // cheap trick to make sure that server is running
        // make a bunch of client calls
        for (int t = 0; t < 100; t++) {
            System.out.println("client count: " + (t+1) + "    " + callServer());
        }
        System.exit(0);
    }
}

【问题讨论】:

  • maxThreads键值对参数需要在org.restlet.Server中设置,而不是在org.restlet.Component中。像这样:Server server = mycomponent.getServers().add(Protocol.HTTP, "localhost", 9090); server.getContext().getParameters().add("maxThreads", "20");

标签: java rest restlet


【解决方案1】:

我们只能通过直接停止 ClientResource 的关联客户端(使用 Restlet 2.0.15 版)来解决问题:

Client c = (Client)clientResource.getNext();
try {
    c.stop();
} catch (Exception e) {
   //handle exception
}   

【讨论】:

  • 看来我也必须这样做才能让线程迅速死亡,但也许这是特定版本的 Restlet 的问题? (请参阅上面@kassius-vargas-prestes 的回答)-您使用的是哪个版本?
  • 我们使用的版本是 2.0.15,是目前最新的稳定版本(现在仍然是)
  • 谢谢,我们使用的是同一个版本,所以我暂时将这个显式的 .stop() 留在我们的代码库中。
【解决方案2】:

添加一行,让客户端释放资源:

    Response response = clientResource.getResponse();
    Status status = response.getStatus();
    clientResource.release();   // add this line

给客户,一切正常。如果客户端死亡,最终服务器会超时,但这需要一段时间。

【讨论】:

    【解决方案3】:

    我已经解决了下载Restlet API的最后一个稳定版本的问题

    显然我一直使用的 .jar 是旧版本,release() 命令不起作用。

    更新前客户端日志只输出客户端的启动:

    Sep 05, 2012 9:50:19 AM org.restlet.engine.http.connector.HttpClientHelper start
    INFO: Starting the default HTTP client
    

    现在它也在输出停止:

    Sep 05, 2012 9:50:19 AM org.restlet.engine.http.connector.HttpClientHelper stop
    INFO: Stopping the default HTTP client
    

    【讨论】:

    • 您介意明确说明您使用的是哪个版本以及哪个版本解决了问题吗?它将帮助其他人(包括我!)调试问题。
    【解决方案4】:

    除了调用 ClientResource.release() 之外,您可能还想在表示上调用 exhaust()。

    Representation responseRepresentation = response.getEntity();
    if (responseRepresentation != null) {
        try {
            responseRepresentation.exhaust();
        } catch (IOException e) {
            // handle exception
        }
        responseRepresentation.release();
    }
    

    this thread的相关讨论。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多