Hi,
I am new to HTTP Components. I wrote a short server which is based on the
Asynchronous HTTP Server example. I am using httpcore-4.2.2 and
httpcore-nio-4.2.2. I wrote a short test program that loads my server. I
see that after ~500,000 requests I get a socket leak of ~600 sockets. I got
84 SocketTimeoutException during the test. After I got to a big number of
leak sockets the application stopped responding and I couldn't even connect
to it with remote debugger.
bellow is my test.
Regards,
Nir
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package httpsample;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.net.InetSocketAddress;
import java.net.URL;
import java.security.KeyStore;
import java.util.Calendar;
import java.util.logging.Level;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.nio.DefaultHttpServerIODispatch;
import org.apache.http.impl.nio.DefaultNHttpServerConnection;
import org.apache.http.impl.nio.DefaultNHttpServerConnectionFactory;
import org.apache.http.impl.nio.SSLNHttpServerConnectionFactory;
import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.NHttpConnectionFactory;
import org.apache.http.nio.NHttpServerConnection;
import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
import org.apache.http.nio.protocol.HttpAsyncExchange;
import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
import org.apache.http.nio.protocol.HttpAsyncRequestHandlerRegistry;
import org.apache.http.nio.protocol.HttpAsyncResponseProducer;
import org.apache.http.nio.protocol.HttpAsyncService;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.ListeningIOReactor;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.ImmutableHttpProcessor;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;
import org.apache.log4j.xml.DOMConfigurator;
/**
* HTTP/1.1 file server based on the non-blocking I/O model and capable of
direct channel
* (zero copy) data transfer.
*/
public class Httpsample {
static private org.apache.log4j.Logger log =
org.apache.log4j.Logger.getLogger(Httpsample.class.getName());
static private final int DFLT_NUM_WORKERS = 200;
static private final int DFLT_PORT = 20003;
static public boolean STAND_ALONE = false;
public static void main(String[] args) throws Exception {
int numOfWorkers = DFLT_NUM_WORKERS;
int port = DFLT_PORT;
for ( int i = 0; i < args.length; i++) {
switch (i){
case 0:
port = Integer.parseInt(args[i]);
break;
case 1:
numOfWorkers = Integer.parseInt(args[i]);
break;
case 2:
STAND_ALONE = true;
break;
}
}
// start log4j system
Calendar now = Calendar.getInstance();
System.setProperty("log4j.year",
Integer.toString(now.get(Calendar.YEAR)));
System.setProperty("log4j.month",
Integer.toString(now.get(Calendar.MONTH) + 1));
System.setProperty("log4j.day",
Integer.toString(now.get(Calendar.DATE)));
System.setProperty("log4j.hours",
Integer.toString(now.get(Calendar.HOUR_OF_DAY)));
System.setProperty("log4j.minutes",
Integer.toString(now.get(Calendar.MINUTE)));
System.setProperty("log4j.seconds",
Integer.toString(now.get(Calendar.SECOND)));
DOMConfigurator.configure("log.xml");
// HTTP parameters for the server
HttpParams params = new SyncBasicHttpParams();
params
.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 *
1024)
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "VascoDE/1.1");
// Create HTTP protocol processing chain
HttpProcessor httpproc = new ImmutableHttpProcessor(new
HttpResponseInterceptor[] {
// Use standard server-side protocol interceptors
new ResponseDate(),
new ResponseServer(),
new ResponseContent(),
new ResponseConnControl()
});
// Create request handler registry
HttpAsyncRequestHandlerRegistry reqistry = new
HttpAsyncRequestHandlerRegistry();
// Register the default handler for all URIs
reqistry.register("*", new HttpFileHandler());
// Create server-side HTTP protocol handler
HttpAsyncService protocolHandler = new HttpAsyncService(
httpproc, new DefaultConnectionReuseStrategy(), reqistry,
params) {
@Override
public void connected(final NHttpServerConnection conn) {
System.out.println(conn + ": connection open");
super.connected(conn);
}
@Override
public void closed(final NHttpServerConnection conn) {
System.out.println(conn + ": connection closed");
super.closed(conn);
}
};
// Create HTTP connection factory
NHttpConnectionFactory<DefaultNHttpServerConnection> connFactory;
if (port == 8443) {
// Initialize SSL context
ClassLoader cl = Httpsample.class.getClassLoader();
URL url = cl.getResource("my.keystore");
if (url == null) {
System.out.println("Keystore not found");
System.exit(1);
}
KeyStore keystore = KeyStore.getInstance("jks");
keystore.load(url.openStream(), "secret".toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keystore, "secret".toCharArray());
KeyManager[] keymanagers = kmfactory.getKeyManagers();
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(keymanagers, null, null);
connFactory = new SSLNHttpServerConnectionFactory(sslcontext,
null, params);
} else {
connFactory = new DefaultNHttpServerConnectionFactory(params);
}
// Create server-side I/O event dispatch
IOEventDispatch ioEventDispatch = new
DefaultHttpServerIODispatch(protocolHandler, connFactory);
// Create server-side I/O reactor
IOReactorConfig conf = new IOReactorConfig();
conf.setIoThreadCount(numOfWorkers);
ListeningIOReactor ioReactor = new DefaultListeningIOReactor(conf);
try {
// Listen of the given port
ioReactor.listen(new InetSocketAddress(port));
// Ready to go!
ioReactor.execute(ioEventDispatch);
} catch (InterruptedIOException ex) {
System.err.println("Interrupted");
} catch (IOException e) {
System.err.println("I/O error: " + e.getMessage());
}
System.out.println("Shutdown");
}
static class HttpFileHandler implements
HttpAsyncRequestHandler<HttpRequest> {
public HttpFileHandler() {
super();
}
@Override
public HttpAsyncRequestConsumer<HttpRequest> processRequest(
final HttpRequest request,
final HttpContext context) {
// Buffer request content in memory for simplicity
return new BasicAsyncRequestConsumer();
}
class testResProducer extends BasicAsyncResponseProducer {
public testResProducer(HttpResponse response) {
super(response);
}
@Override
public synchronized HttpResponse generateResponse() {
log.debug("generating response - producer" + this);
//return super.generateResponse();
HttpResponse res = super.generateResponse();
log.debug("generated response - producer" + this);
return res;
}
@Override
public void failed(Exception ex) {
log.error( "failed to send response- producer" + this, ex);
super.failed(ex);
}
}
@Override
public void handle(
final HttpRequest request,
final HttpAsyncExchange httpexchange,
final HttpContext context) throws HttpException,
IOException {
HttpResponse response = httpexchange.getResponse();
try {
String method = request.getRequestLine().getMethod();
if ( method.equals("POST")) {
new
POSTHandler().processRequest((HttpEntityEnclosingRequest)request,
response);
} else {
new GETHandler().processRequest(request, response);
}
}catch (Exception ex) {
log.error("failed to submit response", ex);
response.setStatusCode(500);
}
HttpAsyncResponseProducer producer = new
testResProducer(response);
log.debug("submiting responce with producer" + producer);
httpexchange.submitResponse(producer);
}
}
}