我正在为我定期轮询并根据特定响应发送消息的服务器设置Java客户端。我用于课程的策略如下:
public class PollingClient {
private HttpClient client = getHttpClient(); // I get a DefaultHttpClient this way so it's easier to add connection manager and strategy etc to the client later
private HttpPost httpPost = getHttpPost(); // same idea, I set headers there
public String poll () {
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("id", someId));
String responseString = null;
try {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
httppost.setURI(polluri));
httppost.setEntity(formEntity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
responseString = EntityUtils.toString(entity);
}
EntityUtils.consume(entity);
} catch (Exception e) {
e.printStackTrace();
}
}
public void send(String msg) {
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("msg", msg));
formparams.add(new BasicNameValuePair("id", someId));
String responseString = null;
try {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
httppost.setURI(new URI(URL + "send"));
httppost.setEntity(formEntity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
responseString = EntityUtils.toString(entity);
}
EntityUtils.consume(entity);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我启动了一个在3秒左右进行轮询的线程。我可以根据轮询结果从主线程发送消息。代码可以正常工作,但不断给我以下两个例外,但在两者之间保持不变。
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
org.apache.http.NoHttpResponseException: The target server failed to respond.
我可以将异常静音,但我想知道发生了什么。我无法通过Google找到任何解决方案。我试图使用内容,在send方法中创建一个新的HttpPost
对象,这样的东西到目前为止没有任何帮助。
对于这种情况,什么是好策略。我目前在keep-alive
对象中设置了HttpPost
标头,以防万一。除此之外,我认为我没有做任何事情。我认为这与整体战略有关。我不想为每个连接创建新对象,但我也不知道建议使用什么级别的重用。谢谢你的帮助。哦..这是HttpClient 4.2.2
答案 0 :(得分:1)
我最终使用下面的代码。它有效......不知道为什么。
DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
答案 1 :(得分:1)
@ Saad的回答非常有帮助,但在尝试加载带有许多并发请求的测试单个URL时,我遇到了延迟。
这是解决问题的更新版本。
DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
int maxConnections = 100;
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(maxConnections));
params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, maxConnections);
ThreadSafeClientConnManager conman = new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry());
client = new DefaultHttpClient(conman, params);
答案 2 :(得分:0)
这些方法不同步,您从不同的线程调用。在poll()操作正在进行时,您的代码是否可能尝试调用send()?我想如果你试图使用同一个对象同时发出两个请求,HttpClient将不会喜欢它。
(如果这是问题,一个简单的修复方法是将synchronized关键字添加到两个方法中,假设您不介意阻止调用它们的线程。)
答案 3 :(得分:0)
这可能有些过分,但您可能会考虑使用专用于http连接处理的线程。该线程将花费睡眠,直到轮询或发送信号为止。这样做的好处是只使用了一个连接。