8

我正在为我定期轮询并根据特定响应向其发送消息的服务器设置 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 找到任何解决方案。我尝试过使用内容,HttpPost在 send 方法中创建一个新对象,诸如此类的东西,但到目前为止没有任何帮助。

对于这种情况有什么好的策略。我目前keep-alive在对象中设置标题HttpPost以防万一。除此之外,我不认为有什么我做的。我认为这与整体战略有关。我不想为每个连接创建新对象,但我也不知道推荐的重用级别。谢谢你的帮助。哦.. 这是 HttpClient 4.2.2

4

4 回答 4

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);
于 2014-04-08T09:53:14.077 回答
1

我最终使用了下面的代码。它有效......不知道为什么。

DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
于 2012-12-20T12:28:45.530 回答
0

这些方法不同步,您从不同的线程调用。当 poll() 操作正在进行时,您的代码是否有可能尝试调用 send()?如果您尝试使用同一个对象同时发出两个请求,我想 HttpClient 不会喜欢它。

(如果这是问题所在,一个简单的解决方法是将 synchronized 关键字添加到这两个方法中,假设您不介意阻塞调用它们的线程。)

于 2012-12-20T01:13:50.077 回答
0

这可能是矫枉过正,但您可能会考虑有一个专用于 http 连接处理的线程。该线程将一直处于睡眠状态,直到轮询或发出信号发送。这样做的好处是只使用一个连接。

于 2012-12-20T04:48:52.763 回答