安卓 网络编程

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

 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 = "\r\n";
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. // timeout: get connections from connection pool
  5. ConnManagerParams.setTimeout(httpParams, 1000);
  6. // timeout: connect to the server
  7. HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
  8. // timeout: transfer data from server
  9. HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
  10. // set max connections per host
  11. ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS));
  12. // set max total connections
  13. ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);
  14. // use expect-continue handshake
  15. HttpProtocolParams.setUseExpectContinue(httpParams, true);
  16. // disable stale check
  17. HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
  18. HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
  19. HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
  20. HttpClientParams.setRedirecting(httpParams, false);
  21. // set user agent
  22. String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
  23. HttpProtocolParams.setUserAgent(httpParams, userAgent);
  24. // disable Nagle algorithm
  25. HttpConnectionParams.setTcpNoDelay(httpParams, true);
  26. HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);
  27. // scheme: http and https
  28. SchemeRegistry schemeRegistry = new SchemeRegistry();
  29. schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
  30. schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
  31. ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
  32. httpClient = new DefaultHttpClient(manager, httpParams);
  33. }
  34. return httpClient;
  35. }

附录:关于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

安卓 网络编程

时间: 2024-11-01 00:31:04

安卓 网络编程的相关文章

《安卓网络编程》之第八篇 安卓与服务器之间通讯JSON

JSON是什么? JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等).这些特性使JSON成为理想的数据交换语言. 易于人阅读和编写,同时也易于机器解析和生成

《安卓网络编程》之第七篇 java编写Service程序

1 import java.io.*; 2 import java.awt.*; 3 import java.awt.event.*; 4 import javax.swing.*; 5 import java.net.*; 6 import java.util.*; 7 8 class Conn extends Thread{ 9 private JTextArea txt; 10 private Socket st; 11 private String msg = null; 12 priv

安卓第八天笔记--网络编程二

安卓第八天笔记--网络编程二 1.网络图片查看器 /** * 网络图片查看器 * 1.获取输入的URL地址,判断是否为空 * 2.建立子线程,获取URl对象new URL(path) * 3.打开连接获取HttpURLConnection conn = (HttpURLConnection) url.openConnection(); * 4.设置连接超时时间conn.setConnectionTimeOut(5000)毫秒 * 5.设置请求方式setRequestMethod * GET或者P

浅谈iOS网络编程之一入门

计算机网络,基本上可以抽象是端的通信.实际在通讯中会用到不同的设备,不同的硬件中,为了能友好的传输信息,那么建立一套规范就十分必要了.先来了解一些基本概念 了解网络中传输的都是二进制数据流.  2.了解网络编程概念. 认识网络: // 网络概念 <1> 经常见到的: 网卡/网线/IP地址/子网掩码/路由地址/DNS服务器地址 作用? // <2> 容易忽略的:MAC地址/数据/数据包 // <3> 网络编程的概念:客户端/服务器/请求/响应/数据流 // 网络是数据交互

【Android实战】----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的

一.简介 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明白为什么Retrofit那么屌.最近也看了一些其源码分析的文章以及亲自查看了源码,发现其对Java网络编程及HTTP权威指南有了一个很好的诠释.一直以来,都信奉一个原则,在这个新技术日新月异的时代,如何在Java界立足,凭借的就两点: 1.基本功,包括:Java基本知识,(Java编程思想.Effective Java),Java进阶(Java虚拟机.Java设计模式).网络相关(这个时

C#网络编程技术FastSocket实战项目演练

一.FastSocket课程介绍 .NET框架虽然微软提供了socket通信的类库,但是还有很多事情要自己处理,比如TCP协议需要处理分包.组包.粘包.维护连接列表等,UDP协议需要处理丢包.乱序,而且对于多连接并发,还要自己处理多线程等等.本期分享课程阿笨给大家带来的是来源于github开源Socket通信中间件:FastSocket,目的就是把大家从繁琐的网络编程技术中彻底地解放和释放出来. 阿笨只想安安静静的学习下网络编程技术Socket后,将学习的成果直接灵活的运用到自己的实际项目中去.

网络编程 -- RPC实现原理 -- RPC -- 迭代版本V1 -- 本地方法调用

网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2--RPC -- 本地方法调用:不通过网络 入门 1. RPCObjectProxy rpcObjectProxy = new RPCObjectProxy(new LocalRPCClient()); : 绑定目标对象 2. IUserService userService = (IUserService) rpcObjectProxy.create(IUserService.class); :返回代理类 3. List<User> u

C#网络程序设计(1)网络编程常识与C#常用特性

    网络程序设计能够帮我们了解联网应用的底层通信原理!     (1)网络编程常识: 1)什么是网络编程 只有主要实现进程(线程)相互通信和基本的网络应用原理性(协议)功能的程序,才能算是真正的网络编程. 2)网络编程的层次 现实中的互联网是按照"TCP/IP分层协议栈"的体系结构构建的,因此程序员必须搞清楚自己要做的是哪个层次上的编程工作. TCP/IP协议体系的实现情况: 其中,网络接口层已经被大多数计算机生产厂家集成在了主板上,也就是经常所说的网卡(NIC).windows操

9. 网络编程:

网络编程: 端口: 物理端口: 逻辑端口:用于标识进程的逻辑地址,不同进程的标识:有效端口:0~65535,其中0~1024系统使用或保留端口. java 中ip对象:InetAddress. import java.net.*; class  IPDemo{ public static void main(String[] args) throws UnknownHostException{ //通过名称(ip字符串or主机名)来获取一个ip对象. InetAddress ip = InetA