• 安卓 网络编程


      这几天学校实训项目需要开始学习安卓编程,其中有一部分是涉及网络知识,

     1 private class SendThread extends Thread
     2     {
     3         public SendThread(String s)
     4         {
     5             mURL = s;
     6         }
     7         public void run()
     8         {
     9             BasicHttpParams httpParams;
    10             httpParams = new BasicHttpParams();
    11             HttpConnectionParams.setConnectionTimeout(httpParams, 3000);
    12             HttpConnectionParams.setSoTimeout(httpParams, 3000);
    13 //            HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
    14             DefaultHttpClient httpClient = new DefaultHttpClient(httpParams);
    15             while(true)
    16             {
    17                 String url = mURL; 
    18                 if(mURL == null)
    19                     continue;
    20                 HttpPost post = new HttpPost(url);
    21                 try {
    22                     HttpResponse response = httpClient.execute(post);
    23                     Log.i("http","send");
    24                 } catch (ClientProtocolException e) {
    25                     // TODO Auto-generated catch block
    26                     e.printStackTrace();
    27                 } catch (IOException e) {
    28                     // TODO Auto-generated catch block
    29                     e.printStackTrace();
    30                 }
    31             }
    32         }
    33     }

    这是关于向一个服务器使用post方法发送一个请求的线程,在一开始编写时因为粗心的原因将

     DefaultHttpClient httpClient = new DefaultHttpClient(httpParams);

    这个误写入了while循环体中,结果可想而知,程序不断的新建 httpClient,导致整个CPU和内存的浪费。速度被拖得急慢。

    以下是关于从服务器获取视频流的代码

     1 public void cameraRec()
     2     {
     3         new Thread()
     4         {
     5             public void run()
     6             {
     7                 while(true)
     8                 {try
     9                 {
    10                     URL  url =new URL("http://192.168.1.102:1280/snapshot.cgi?user=admin&pwd=123456");
    11                     InputStream is = url.openStream();
    12                     MainActivity.mBitmap = BitmapFactory.decodeStream(is);
    13                     Log.i("htp","rec");
    14                     if(MainActivity.mBitmap !=null)
    15                         mHandler.sendEmptyMessage(Base.MESSAGE_PIC);
    16                     sleep(30);
    17                 }
    18                 catch(Exception e)
    19                 {
    20                 }
    21                 }
    22             }
    23 //            @Override
    24 //            public void run() {
    25 //                 String flag = "Content-Length: ";
    26 //             String flag1 = "
    ";
    27 //                URL mURL;
    28 //                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    29 //                
    30 //                try {
    31 //                    mURL = new URL("http://192.168.1.102:1280"
    32 //                                + "/videostream.cgi"
    33 //                                + "?user=admin&pwd=123456&resolution=32&rate=1");
    34 //                    
    35 //                    InputStream input = mURL.openStream();
    36 //                    
    37 //                    //if(input != null) mStopStream = false;
    38 //                    
    39 //                    int readLength = -1;
    40 //                    String strData;
    41 //                    
    42 //                    while (true) {
    43 //                        byte[] buffer = new byte[1024];
    44 //                        readLength= input.read(buffer,0,1024);
    45 //                        
    46 //                        if(readLength > 0) {
    47 //                            strData= new String (buffer, readLength);
    48 //
    49 //                            int index = strData.indexOf(flag);
    50 //                            int index1 = strData.indexOf(flag1,index);
    51 //                            
    52 //                            int streamLength = 0;
    53 //                            
    54 //                            if(index1 != -1) {
    55 //                                streamLength = Integer.parseInt(strData.substring(index+flag.length(), index1));
    56 //                            }
    57 //                            
    58 //                            if(streamLength > 0) {
    59 //                                if((index1+4) < readLength) {
    60 //                                    outStream.write(buffer, index1+4, readLength-index1-4);
    61 //                                    streamLength = streamLength - readLength+index1+4;
    62 //                                }
    63 //                                //将剩下读取的视频流存储到buffer1
    64 //                                byte[] buffer1 = new byte[streamLength];
    65 //                                int length = 0;
    66 //                                while(length < streamLength) {
    67 //                                    length += input.read(buffer1,length,streamLength-length);
    68 //                                }
    69 //                                
    70 //                                outStream.write(buffer1,0,streamLength);  // 将剩余的stream写入outStream
    71 //                                
    72 //                                byte[] data = outStream.toByteArray();
    73 //                                MainActivity.mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    74 //                                //System.out.println("bitmap = " + bitmap);
    75 //                                if(MainActivity.mBitmap != null) {
    76 //                                    mHandler.sendEmptyMessage(Base.MESSAGE_PIC);   //报告到UI界面,更新图像
    77 //                                }
    78 //                                outStream.reset();
    79 //                            }
    80 //                        }
    81 //                    }
    82 //                    
    83 //                    //input.close();
    84 //                    
    85 //                } catch (IOException e) {
    86 //                    e.printStackTrace();
    87 //                }
    88 //                
    89 //                try {
    90 //                    outStream.close();
    91 //                } catch (IOException e) {
    92 //                    e.printStackTrace();
    93 //                }
    94 //            }
    95         }.start();
    96     }

    *****************************************************************

    以下摘自:http://blog.csdn.net/heng615975867/article/details/9012303

    尽管Android官网推荐在2.3及后续版本中使用HttpURLConnection作为网络开发首选类,但在连接管理和线程安全方面,HttpClient还是具有很大优势。就目前而言,HttpClient仍是一个值得考虑的选择。对于HttpClient的优化,可以从以下几个方面着手:

        (1)采用单例模式(重用HttpClient实例)
        对于一个通信单元甚至是整个应用程序,Apache强烈推荐只使用一个HttpClient的实例。例如:

        private static HttpClient httpClient = null;
     
        private static synchronized HttpClient getHttpClient() {
           if(httpClient == null) {
               final HttpParams httpParams = new BasicHttpParams();  
               httpClient = new DefaultHttpClient(httpParams); 
           }  
      
          return httpClient;
        }

        (2)保持连接(重用连接)
        对于已经和服务端建立了连接的应用来说,再次调用HttpClient进行网络数据传输时,就不必重新建立新连接了,而可以重用已经建立的连接。这样无疑可以减少开销,提升速度。
        在这个方面,Apache已经做了“连接管理”,默认情况下,就会尽可能的重用已有连接,因此,不需要客户端程序员做任何配置。只是需要注意,Apache的连接管理并不会主动释放建立的连接,需要程序员在不用的时候手动关闭连接。

        (3)多线程安全管理的配置
        如果应用程序采用了多线程进行网络访问,则应该使用Apache封装好的线程安全管理类ThreadSafeClientConnManager来进行管理,这样能够更有效且更安全的管理多线程和连接池中的连接。
        (在网上也看到有人用MultiThreadedHttpConnectionManager进行线程安全管理的,后查了下Apache的API,发现MultiThreadedHttpConnectionManager是API 2.0中的类,而ThreadSafeClientConnManager是API 4.0中的类,比前者更新,所以选择使用ThreadSafeClientConnManager。另外,还看到有PoolingClientConnectionManager这个类,是API 4.2中的类,比ThreadSafeClientConnManager更新,但Android SDK中找不到该类。所以目前还是选择了ThreadSafeClientConnManager进行管理)
        例如:

        ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry); 
        httpClient = new DefaultHttpClient(manager, httpParams);

        (4)大量传输数据时,使用“请求流/响应流”的方式
        当需要传输大量数据时,不应使用字符串(strings)或者字节数组(byte arrays),因为它们会将数据缓存至内存。当数据过多,尤其在多线程情况下,很容易造成内存溢出(out of memory,OOM)。

        而HttpClient能够有效处理“实体流(stream)”。这些“流”不会缓存至内存、而会直接进行数据传输。采用“请求流/响应流”的方式进行传输,可以减少内存占用,降低内存溢出的风险。
        例如:

        // Get method: getResponseBodyAsStream()
        // not use getResponseBody(), or getResponseBodyAsString()
        GetMethod httpGet = new GetMethod(url);  
        InputStream inputStream = httpGet.getResponseBodyAsStream();

        // Post method: getResponseBodyAsStream()
        PostMethod httpPost = new PostMethod(url);  
        InputStream inputStream = httpPost.getResponseBodyAsStream(); 

        (5)持续握手(Expect-continue handshake)
        在认证系统或其他可能遭到服务器拒绝应答的情况下(如:登陆失败),如果发送整个请求体,则会大大降低效率。此时,可以先发送部分请求(如:只发送请求头)进行试探,如果服务器愿意接收,则继续发送请求体。此项优化主要进行以下配置:

        // use expect-continue handshake
        HttpProtocolParams.setUseExpectContinue(httpParams, true);

        (6)“旧连接”检查(Stale connection check)
        HttpClient为了提升性能,默认采用了“重用连接”机制,即在有传输数据需求时,会首先检查连接池中是否有可供重用的连接,如果有,则会重用连接。同时,为了确保该“被重用”的连接确实有效,会在重用之前对其进行有效性检查。这个检查大概会花费15-30毫秒。关闭该检查举措,会稍微提升传输速度,但也可能出现“旧连接”过久而被服务器端关闭、从而出现I/O异常。
        关闭旧连接检查的配置为:
        // disable stale check
        HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);

        (7)超时设置
        进行超时设置,让连接在超过时间后自动失效,释放占用资源。

        // timeout: get connections from connection pool
        ConnManagerParams.setTimeout(httpParams, 1000);  
        // timeout: connect to the server
        HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
        // timeout: transfer data from server
        HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);

        (8)连接数限制
        配置每台主机最多连接数和连接池中的最多连接总数,对连接数量进行限制。其中,DEFAULT_HOST_CONNECTIONS和DEFAULT_MAX_CONNECTIONS是由客户端程序员根据需要而设置的。

        // set max connections per host
        ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS)); 
        // set max total connections
        ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);

        经过优化后,上一篇日志中的getHttpClient()方法代码如下:

       

    [java] view plaincopy
     
     
    1. private static synchronized HttpClient getHttpClient() {  
    2.     if(httpClient == null) {  
    3.         final HttpParams httpParams = new BasicHttpParams();    
    4.           
    5.         // timeout: get connections from connection pool  
    6.         ConnManagerParams.setTimeout(httpParams, 1000);    
    7.         // timeout: connect to the server  
    8.         HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);  
    9.         // timeout: transfer data from server  
    10.         HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);   
    11.           
    12.         // set max connections per host  
    13.         ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS));    
    14.         // set max total connections  
    15.         ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);  
    16.           
    17.         // use expect-continue handshake  
    18.         HttpProtocolParams.setUseExpectContinue(httpParams, true);  
    19.         // disable stale check  
    20.         HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);  
    21.           
    22.         HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);    
    23.         HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);   
    24.             
    25.         HttpClientParams.setRedirecting(httpParams, false);  
    26.           
    27.         // set user agent  
    28.         String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";  
    29.         HttpProtocolParams.setUserAgent(httpParams, userAgent);       
    30.           
    31.         // disable Nagle algorithm  
    32.         HttpConnectionParams.setTcpNoDelay(httpParams, true);   
    33.           
    34.         HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);    
    35.           
    36.         // scheme: http and https  
    37.         SchemeRegistry schemeRegistry = new SchemeRegistry();    
    38.         schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));    
    39.         schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));  
    40.   
    41.         ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);    
    42.         httpClient = new DefaultHttpClient(manager, httpParams);   
    43.     }         
    44.       
    45.     return httpClient;  
    46. }  

     

        附录:关于HttpURLConnection的优化,网上资料不多。从Android官网上看到一点,整理如下:

        (1)上传数据至服务器时(即:向服务器发送请求),如果知道上传数据的大小,应该显式使用setFixedLengthStreamingMode(int)来设置上传数据的精确值;如果不知道上传数据的大小,则应使用setChunkedStreamingMode(int)——通常使用默认值“0”作为实际参数传入。如果两个函数都未设置,则系统会强制将“请求体”中的所有内容都缓存至内存中(在通过网络进行传输之前),这样会浪费“堆”内存(甚至可能耗尽),并加重隐患。

        (2)如果通过流(stream)输入或输出少量数据,则需要使用带缓冲区的流(如BufferedInputStream);大量读取或输出数据时,可忽略缓冲流(不使用缓冲流会增加磁盘I/O,默认的流操作是直接进行磁盘I/O的);

        (3)当需要传输(输入或输出)大量数据时,使用“流”来限制内存中的数据量——即:将数据直接放在“流”中,而不是存储在字节数组或字符串中(这些都存储在内存中)。

     

        参考文章:

        http://hc.apache.org/httpclient-3.x/performance.html

        http://blog.csdn.net/androidzhaoxiaogang/article/details/8198400

        http://guowww.diandian.com/post/2011-11-07/15351973

        http://blog.csdn.net/ken831001/article/details/7925309

        http://www.iteye.com/topic/1117362

        http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html

        http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingClientConnectionManager.html

     

  • 相关阅读:
    C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)
    Xamarin如何使用终端设备的NFC功能传递卡号等信息给Web页面(Android)
    C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)
    C# Winform中自定义筛选及自带统计行的Datagridview控件
    C#下Excel的普通处理和报表设计
    JVM 垃圾回收算法
    谈数据库的性能优化
    RedisService
    bean 与 map 互转.
    RedisService
  • 原文地址:https://www.cnblogs.com/pray/p/3891574.html
Copyright © 2020-2023  润新知