简体   繁体   中英

Repeated calls by Restlet client to Restlet server hangs

I am using Restlet to implement a web service. The client (also uses Restlet) makes many consecutive calls to the server, but after a small number of calls complete successfully, further calls hang the server, which shows the message:

INFO: Stop accepting new connections and transactions. Consider increasing the maximum number of threads.

I tried:

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

but that does not help. In any case, it seems like the client should be able to make an unlimited number of calls, and increasing maxThreads just ups the limit. It looks like I am not freeing up some resource or disconnecting after each client call, but I do not know how to do so.

The following (small as I could make it) stand alone program demonstrates the problem. It starts a simple server and then a client calls it a bunch of times:

/** 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);
    }
}

We were only able to solve the problem by stopping the ClientResource's associated client directly (using Restlet version 2.0.15):

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

Add a line so that the client releases the resource:

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

to the client and everything works. Eventually the server times out if the client dies, but that takes a while.

I've solved my problem downloading the last stable release of the Restlet API

Apparently the .jar the I've been using were an old version where the release() command doesn't make any effect.

Before the update the client log only outputs the start of the client:

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

Now it are outputing the stop too:

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

In addition to calling ClientResource.release(), you may want to call exhaust() on the representation.

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

Related discussion in this thread .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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