• 【转】 Pro Android学习笔记(七一):HTTP服务(5):多线程调用HttpClient


    目录(?)[-]

    1. 应用共享HttpClient对象的同步问题
    2. 创建共享HttpClient代码
      1. 创建共享对象
      2. 创建可共享的HttpClient对象
    3. 使用共享HttpClient对象的代码
      1. 基础代码
      2. 修改HTTP连接的参数
    4. 使用共同的Appcliation对象

    文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件,转载须注明出处:http://blog.csdn.net/flowingflying/

    应用共享HttpClient对象的同步问题

    在之前的例子中,HttpClient只用于某个请求,我们可以为整个应用创建一个共享的HttpClient对象。这就存在多线程使用的问题,而HttpClient已经考虑这个问题,只需要创建一个使用ThreadSafeClientConnManager的DefaultHttpClient对象。

    创建共享HttpClient代码

    创建共享对象

    创建共享对象的方式是通用,如下:

    public class CustomHttpClient { 
        private static HttpClient client = null;  //应用共享的对象
         
        /* 采用private的构造器,禁止了其他类通过CustomHttpClient xx = new CustomHttpClient();这种方式创建对象,确保对象的唯一性 */
       private CustomHttpClient(){ 
        } 
        /* 通过静态调用获取对象,第一次调用为空时进行创建 */ 
        public static synchronized HttpClient getCustomHttpClient(){
     
            if(client == null){ 
               /*如果对象为空,创建之*/ 
                ... ... 
            } 
            return client; 
        } 
        /*禁止clone,同样也是保证对象的唯一性*/ 
        public Object clone() throws CloneNotSupportedException{ 
            throw new CloneNotSupportedException(); 
        } 
        
    }

    创建可共享的HttpClient对象

    下面给出上面代码中省略的部分,当对象为空是,创建HttpClient对象的代码,为了方便理解,代码从可以从后往前看。

    //【2.1】设置Http参数 
    HttpParams params = new BasicHttpParams();
     
    /* 设置HttpParam是的基本参数,其实都是对应http请求的消息头。其中三个都很好理解,重点介绍一些setUserExpectContinue。 一般都设置为flase,设置为true通常是传递request消息很大(例携带大文件),而服务器可能需要认证,我们不希望传完这个大文件,才收到服务器的拒绝。HTTP是TCP流方式,当server收到请求的头字段是Except:100-continue, 不在等待整个请求,返回100 continue应答继续读取,或者给出拒绝请求(final Status code,如4xx)。 具体可以参考:http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 */
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
    HttpProtocolParams.setUseExpectContinue(params, true); 
    HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83)" +
         " AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"); 
    /* 设置超时时间。超时的异常均属于IOException,此外ClientProtocolException也是与IOException*/
    // 从ClientConnectionManager获取连接的时间,这是从连接池中获取连接的超时设置,只有在连接池所有连接都在使用的情况下才可能出现超时。超时会扔出ConnectionPoolTimeoutException。一个HttpClient对应管理器,有连接池,里面有多个连接(socket),这是我对其架构的猜测。
    ConnManagerParams.setTimeout(params, 1000); 
    // 这是连接到远端web server的超时设置,超时会扔出ConnectTimeoutException
    HttpConnectionParams.setConnectionTimeout(params, 5000);//连接超时
    // 这是发送请求消息后,最多等待多长时间得到响应的设置,超时会扔出SocketTimeoutException
    HttpConnectionParams.setSoTimeout(params, 10000);//socket超时
    //【2.2】设置Sheme,注册了http和https 
    SchemeRegistry schReg = new SchemeRegistry(); 
    schReg.register(new Scheme("http",PlainSocketFactory.getSocketFactory(), 80)); 
    schReg.register(new Scheme("https",PlainSocketFactory.getSocketFactory(), 443)); 

    //【2】ClientConnectionManager用于管理HTTP连接,我们使用同一个client来处理请求,要确保多线程的使用安全,采用ThreadSafeClientConnManager,是线程安全的连接池。如果多个线程同时请求,或有延迟情况。
    ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg);
    //【1】以ThreadSafeClientConnManager为管理器参数,创建可进行多线程调用的同步保护的HttpClient对象
    client = new DefaultHttpClient(conMgr,params);
     

    使用共享HttpClient对象的代码

    基础代码

    下面给出Activity调用这个共享的HttpClient的代码:

    public class HttpActivity extends Activity{ 
        private HttpClient client = null; 
        
        protected void onCreate(Bundle savedInstanceState) {  
             …… //UI处理等 
            client = CustomHttpClient.getCustomHttpClient();        
            getHttpContent(); 
        } 
        
        private void getHttpContent(){ 
            try{  
                HttpGet request = new HttpGet("http://www.google.com");            
                /* 在处理response时,利用Android提供的BasicResponseHandler:handleResponse(HttpResponse response),Returns the response body as a String. if the response was successful (a 2xx status code).  */       
                String page = client.execute(request,new BasicResponseHandler()); 
                Log.d("PRO-HTTP",page); 
            }catch(IOException e){ 
                e.printStackTrace();  
            } 
        } 

    修改HTTP连接的参数

    我们在创建HttpClient时已经设置了有关的HTTP连接参数,实际对应的是HTTP请求消息中的消息头,如果某个请求需要对这些参数进行修改,不应对公共属性进行修改,否则会影响到其他请求,而是通过对具体的request请求进行设置。代码例子如下:

    // 我们设置了内部网的一个空地址,通过LogCat中连接超时出现的时间,来判断参数修改是否成功
    HttpGet request = new HttpGet("http://192.168.0.199");              

    // 读取httpClient的参数设置 
    HttpParams clientParams=client.getParams(); 
    Log.d("PRO-HTTP",Log.d(String.valueOf(HttpConnectionParams.getConnectionTimeout(clientParams)));//显示为5000
    Log.d("PRO-HTTP",String.valueOf(HttpConnectionParams.getSoTimeout(clientParams)));//显示为10000  
                 
    // 原来设置的连接超时是5秒,下面将重新设置该参数,设为20秒,我们将新的参数设置在request中,将不影响其他的请求
    HttpParams params = request.getParams(); 
    HttpConnectionParams.setConnectionTimeout(params, 20000);//20s 
    request.setParams(params);  
    Log.d("PRO-HTTP",String.valueOf(HttpConnectionParams.getConnectionTimeout(params)));//显示20000
    Log.d("PRO-HTTP",String.valueOf(HttpConnectionParams.getSoTimeout(params))); //显示0

    使用共同的Appcliation对象

    对于应用全局共享同一对象,使人想起appclication对象,对于Android应用,都会有一个application对象,在在应用中可以通过getApplicationContext()或者getApplication()来获得。如果我们没有自定义的Application类,就是用android.app.Application。我们当然也可以将HttpClient对象放置在自定义的application类,但是为了这点小事来是Application类变得复杂并不可取。

    在此,我们将探讨自定义的Appcliation。很简单,只要创建自定义的Application类即可,至于application对象的创建,均有系统来完成。下面我们在自定义的Application中加入一个计数器。

    import android.app.Application; 

    public class CustomApplication extends Application
        private int counter = 0; 
        
        public int getCounter(){ 
            return ++counter; 
        } 
    }

    在应用的所有组件都都可以application对象,且是唯一的一个。从运行结果看出,获得这个对象有好几种方式。

    CustomApplication app = (CustomApplication)getApplication(); 
    Log.d("PRO-wei","counter: " + app.getCounter());  //测试一下计数器是否正常
    Log.d("PRO-wei","context: " + app); 
    Log.d("PRO-wei","context: " + app.getApplicationContext());  //测试一下获得app类的其他方式 
    Log.d("PRO-wei","context: " + getApplicationContext());  //测试一下获得app类的其他方式

    本博文涉及的例子代码,可以在Pro Android学习:Http service小例子中下载。

    相关链接: 我的Android开发相关文章

  • 相关阅读:
    针对WannaRen勒索软件的梳理与分析——无文件攻击使用也很多
    记一次 PowerShell 免杀实战
    powershell渗透工具——后渗透工具Empire使用教程
    绕过PowerShell执行策略方法
    线程插入技术——不就是DLL进程注入嘛,干嘛整这么多幺蛾子!造词这么多。。。
    powershell渗透工具——Powershell内网渗透利器之PowerSploit,场景真tm多啊
    powershell渗透工具——powercat工具详细分析
    从网络安全应急响应看EDR的一些Case
    检测远程线程注入DLL——todo,待深入
    后门种类——网站后门、rootkit、CS后门,当然2类就直接是正向后门和反向后门,里面最难的当属线程插入后门,其他的像ping隧道、克隆账户啥的都比较好检测
  • 原文地址:https://www.cnblogs.com/blongfree/p/5048050.html
Copyright © 2020-2023  润新知