博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android端的的网络访问
阅读量:4985 次
发布时间:2019-06-12

本文共 12850 字,大约阅读时间需要 42 分钟。

一.Android端进行网络访问的几种实现方式

  • Socket

   套接字,为TCP/IP协议网络通信的网络操作单元;

   而抽象上来说:Socket只是一个供上层调用的抽象接口,相当于是传输层下的数据,还没经过应用层的封装,或者说不需要应用层的封装,因为直接使用socket连接的有两种情况,第一种情况就是直接获取传输层传输过来的输入流,按顺序合成之后就是一个完整的文件,或者是一个字符串等等不需要所谓的解析;另一种情况就是从socket连接返回的数据进行二次封装,进行应用层解析,达到大牛的网络访问框架,实现应用层封装,不过很多细节需要注意。

  • UrlConnection
    UrlConnection是基于Http协议的,Http协议是应用层的协议,基于Tcp/IP协议之上的协议,是Web浏览器和Web服务器之间的应用层的协议,基于传输层上再进行了一次协议封装,是无状态协议,不需要你往考虑线程、同步、状态治理等,内部是通过socket进行连接和收发数据的,不过一般在数据传输完成之后需要封闭socket连接

联系:UrlConnection基于Http协议,只不过多了封装,本质上也是建立Tcp连接,利用socket进行连接和数据传输,只不过每次连接之后都要手动关闭连接。因此直接使用Socket进行网络通讯得考虑线程治理、客户状态监控等,但是不用发送头信息等,更省流量。

 二.客户端与服务器交互

客户端通过Internet去发送到服务器当中,而Internet内部可以通过三种方式来实现发送信息和数据:
  • 第一种:HTTP协议,也是在工作中最常用的,是建立在TCP/IP基础上实现的。
  • 第二种:FTP协议
  • 第三种:TCP/IP协议,它也是最底层的协议,其它的方式必须是要通过它,但是要想实现这种协议必须要实现socket编程,这种方法是用来上传一些比较大的文件,视频,进行断点续传的操作。

 

三.Android中达到网络访问的封装类/框架

  • HttpURLConnection

    HttpURLConnection只是继承UrlConnection,两者都是接口,只是在该接口的基础上进行简单封装

    从Android4.4开始HttpURLConnection的底层实现采用的是okHttp

  • HttpClient

 

   HttpClient就是对java提供的方法的一些封装,在HttpURLConnection的输入输出流操作,在HttpClient接口里直接封装成HttpPost、HttpGet、HttpResponse。很方便,另外需要注意的是post方式的情况下,我们需要进行字符编码,否则会出错。

   Apache HttpClient早就不推荐httpclient,5.0之后干脆废弃,后续会删除。6.0删除了HttpClient。

 

  • OkHttp

    okhttp是高性能的http库,支持同步、异步,而且实现了spdy、http2、websocket协议,api很简洁易用,和volley一样实现了http协议的缓存。picasso就是利用okhttp的缓存机制实现其文件缓存,实现的很优雅,很正确,反例就是UIL(universal image loader),自己做的文件缓存,而且不遵守http缓存机制。

   OkHttp的最底层是Socket,而不是HTTP,它通过Platform的Class.forName()反射获得当前Runtime使用的socket库

  • volley

    volley是一个简单的异步http库,仅此而已。缺点是不支持同步,这点会限制开发模式。自带缓存,支持自定义请求。不适合大文件上传和下载。
    Volley在Android 2.3及以上版本,使用的是HttpURLConnection,而在Android 2.2及以下版本,使用的是HttpClient。
    Volley自己的定位是轻量级网络交互,适合大量的,小数据传输。
    不过再怎么封装Volley在功能拓展性上始终无法与OkHttp相比。Volley停止了更新,而OkHttp得到了官方的认可,并在不断优化。

  • android-async-http。

    与volley一样是异步网络库,但volley是封装的httpUrlConnection,它是封装的httpClient,而android平台不推荐用HttpClient了,所以这个库已经不适合android平台了。

  • Retrofit

    Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。注意这里并没有说它是网络请求框架,主要原因在于网络请求的工作并不是 Retrofit 来完成的。Retrofit 2.0 开始内置 OkHttp,前者专注于接口的封装,后者专注于网络请求的高效,二者分工协作,宛如古人的『你耕地来我织布』,小日子别提多幸福了。参考
    retrofit与picasso一样都是在okhttp基础之上做的封装,项目中可以直接用了。Retrofit因为也是square出的,所以大家可能对它更崇拜些。Retrofit的跟Volley是一个套路,但解耦的更彻底:比方说通过注解来配置请求参数,通过工厂来生成CallAdapter,Converter,你可以使用不同的请求适配器(CallAdapter), 比方说RxJava,Java8, Guava。你可以使用不同的反序列化工具(Converter),比方说json, protobuff, xml, moshi等等。炒鸡解耦,里面涉及到超多设计模式,个人觉得是很经典的学习案例。虽然支持Java8, Guava你可能也不需要用到。xml,protobuff等数据格式你也可能不需要解析。but,万一遇到鬼了呢。至于性能上,个人觉得这完全取决于请求client,也就是okhttp的性能,跟这些封装工具没太大关系。

四.HttpUrlConnection和HttpClient的简单使用

对于我们熟知的网络访问工具类HttpURLConnection和HttpClient,这两个接口都可以用来开发Http访问。

 

需要引入httpClient包,在本人AS环境,SDK处于23的情况下,需要引入:

android {useLibrary 'org.apache.http.legacy'//httpClient需要包}

需要的权限:

 

简单的使用:

httpURLConnection、HttpClient:

/**     * 使用HTTPUrlConnection例子     * @param username     * @param password     * @return     */    public static String login(String username,String password){        String msg = "";        try {            username = URLEncoder.encode(username,"UTF-8");//这里要注意编码,如果参数含有汉字或是空格(尤其是日期中的空格),不编码会发生错误            password = URLEncoder.encode(password,"UTF-8");        } catch (UnsupportedEncodingException e1) {            // TODO Auto-generated catch block            e1.printStackTrace();        }        //要访问的HttpServlet        String urlStr="http://127.0.0.1:8080/MyProject/getUser?";        //要传递的数        String params ="username="+username+"&password="+password;        urlStr = urlStr+params;        try{            URL url =new URL(urlStr);            //获得连接            HttpURLConnection conn = (HttpURLConnection)url.openConnection();            conn.setConnectTimeout(6000);            conn.setRequestMethod("GET");//请求方式            InputStream in = conn.getInputStream();            BufferedReader reader = new BufferedReader(new InputStreamReader(in, HTTP.UTF_8));            String line = null;            while ((line = reader.readLine()) != null) {                if(msg==null){                    msg=line;                }else{                    msg += line;                }            }            reader.close();            in.close();//关闭数据流            conn.disconnect();        }catch(Exception e){            e.printStackTrace();            return null;        }        return msg;    }    /**     * 使用HttpClient访问,get方式,如果sdk版本为23,需要引入org.apache.http.legacy     * @return     */    private static String loginHttpClientGet(){        // http地址        String httpUrl = "http://192.168.1.110:8080/httpget.jsp?par=HttpClient_android_Get";        //HttpGet连接对象        HttpGet httpRequest = new HttpGet(httpUrl);        String strResult = "";        try        {            //取得HttpClient对象            HttpClient httpclient = new DefaultHttpClient();            //请求HttpClient,取得HttpResponse            HttpResponse httpResponse = httpclient.execute(httpRequest);            //请求成功            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)            {                //取得返回的字符串                strResult = EntityUtils.toString(httpResponse.getEntity());//                mTextView.setText(strResult);            }            else            {//                mTextView.setText("请求错误!");            }            return strResult;        }        catch (ClientProtocolException e)        {//            mTextView.setText(e.getMessage().toString());        }        catch (IOException e)        {//            mTextView.setText(e.getMessage().toString());        }        catch (Exception e)        {//            mTextView.setText(e.getMessage().toString());        }        return strResult;    }    /**     * 使用HttpClient访问,post方式     * @return     */    private static String loginHttpClientPost(){        // http地址        String httpUrl = "http://192.168.1.110:8080/httpget.jsp";        //HttpPost连接对象        HttpPost httpRequest = new HttpPost(httpUrl);        //使用NameValuePair来保存要传递的Post参数        List
params = new ArrayList
(); //添加要传递的参数 params.add(new BasicNameValuePair("par", "HttpClient_android_Post")); String strResult = ""; try { //设置字符集 HttpEntity httpentity = new UrlEncodedFormEntity(params, "gb2312"); //请求httpRequest httpRequest.setEntity(httpentity); //取得默认的HttpClient HttpClient httpclient = new DefaultHttpClient(); //取得HttpResponse HttpResponse httpResponse = httpclient.execute(httpRequest); //HttpStatus.SC_OK表示连接成功 if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //取得返回的字符串 strResult = EntityUtils.toString(httpResponse.getEntity());// mTextView.setText(strResult); } else {// mTextView.setText("请求错误!"); } return strResult; } catch (ClientProtocolException e) {// mTextView.setText(e.getMessage().toString()); } catch (IOException e) {// mTextView.setText(e.getMessage().toString()); } catch (Exception e) {// mTextView.setText(e.getMessage().toString()); } return strResult; }
View Code

socket:

//服务器端public class MyServer {            private  static int count=0;      public static void main(String[]args){                    try {              //实例化服务器套接字 设置端口号8888              ServerSocket server=new ServerSocket(8888);              while(true){                  //连接编号设置                  count=count+1;                  //时间格式                  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");                  //实例化客户端                  Socket client=server.accept();                  //实例化时间  以及 id                  System.out.println(count+":"+sdf.format(System.currentTimeMillis()));                  //获取输出流                  OutputStream out=client.getOutputStream();                  //输出字符串                  String msg="Hello,Android!";                  //写字符串                  out.write(msg.getBytes());              }          } catch (IOException e) {              // TODO Auto-generated catch block              e.printStackTrace();          }                          }  }  //客户端public class MyClientActivity extends Activity {      /** Called when the activity is first created. */      private Button rev=null;      private TextView revtext=null;      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          rev=(Button)findViewById(R.id.rev);              revtext=(TextView)findViewById(R.id.receiver);          rev.setOnClickListener(new receiverlistenr());      }      class receiverlistenr implements OnClickListener{          public void onClick(View v) {              // TODO Auto-generated method stub              try {                  //实例化Socket                  Socket socket=new Socket("169.254.202.149",8888);                  //获得输入流                  InputStream in=socket.getInputStream();                  //缓冲区                  byte[] buffer=new byte[in.available()];                  //读取缓冲区                  in.read(buffer);                  //转换字符串                  String msg=new String(buffer);                  //设置文本框的字符串                  revtext.setText(msg);              } catch (UnknownHostException e) {                  // TODO Auto-generated catch block                  e.printStackTrace();              } catch (IOException e) {                  // TODO Auto-generated catch block                  e.printStackTrace();              }                        }      }  }
View Code

 Socket连接---至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认

 

四.请求报文与响应报文

请求报文的一般格式:

这里写图片描述

通常来说一个HTTP请求报文由请求行、请求报头、空行、和请求数据4个部分组成。

 

GET http://blog.csdn.net/itachi85 HTTP/1.1                                //请求行Host: blog.csdn.net                                                       //请求报头Connection: keep-aliveCache-Control: max-age=0       Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 QQBrowser/9.3.6872.400Accept-Encoding: gzip, deflate, sdchAccept-Language: zh-CN,zh;q=0.8Cookie: bdshare_firstime=1443768140949; uuid_tt_dd=5028529250430960147_20151002;
//不能省略的空格28b5                                            }ysI   1ߡFsgl n- ]{^_ { 'z!     C ,  m# 0 !l   `  4x  ly .ݪ*
...省略

 

 

 

响应报文的一般格式: 

这里写图片描述

HTTP的响应报文由状态行、消息报头、空行、响应正文组成。

 

HTTP/1.1 200 OK                                                         //状态行Server: openresty                                                       //响应报头Date: Sun, 27 Mar 2016 08:26:54 GMTContent-Type: text/html; charset=utf-8Transfer-Encoding: chunkedConnection: keep-aliveKeep-Alive: timeout=20Vary: Accept-EncodingCache-Control: privateX-Powered-By: PHP 5.4.28Content-Encoding: gzip                                                                        //不能省略的空格28b5                                            }ysI   1ߡFsgl n- ]{^_ { 'z!     C ,  m# 0 !l   `  4x  ly .ݪ*    ڴzAt_Xl *  9'O  ɬ  '  ק   3  ^1a...省略

 

如果是请求文件(下载)

 

要从文件已经下载的地方开始继续下载。在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。一般断点下载时才用到 Range 和 Content-Range 实体头。

Range 

用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:

Range:(unit=first byte pos)-[last byte pos] 

Content-Range

用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式: 

Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth] 

请求下载整个文件: 

  1. GET /test.rar HTTP/1.1 
  2. Connection: close 
  3. Host: 116.1.219.219 
  4. Range: bytes=0-801 //一般请求下载整个文件是bytes=0- 或不用这个头

一般正常回应

  1. HTTP/1.1 200 OK 
  2. Content-Length: 801      
  3. Content-Type: application/octet-stream 
  4. Content-Range: bytes 0-800/801 //801:文件总大小

 

 

注意:对于socket网络访问

服务器端:根据serversocket.accept()接收到请求socket,socket的inputstream为请求报文(与Http请求报文一致),并且把数据写入到socket的outputStream中(数据格式与HTTP响应报文一致)。

客户端:根据socket,inputStream为服务器返回的数据

 

五.HTTP的请求方式(八种)的使用环境

据标准(现行的HTTP/1.1)得知有以下8种方法:、、、POST、PUT、DELETE、TRACE和CONNECT。

con.setRequestMethod("");//设置请求状态

 

HTTP请求方法有8种,分别是GET、POST、DELETE、PUT、HEAD、TRACE、CONNECT 、OPTIONS。其中PUT、DELETE、POST、GET分别对应着增删改查,对于移动开发最常用的就是POST和GET了。

  1. GET:请求获取Request-URI所标识的资源(查)
  2. POST:在Request-URI所标识的资源后附加新的数据(增)
  3. HEAD:请求获取由Request-URI所标识的资源的响应消息报头,类似于GET, 但是不返回body信息,用于检查对象是否存在,以及得到对象的元数据
  4. PUT: 请求服务器存储一个资源,并用Request-URI作为其标识(改)
  5. DELETE :请求服务器删除Request-URI所标识的资源(删)
  6. TRACE : 请求服务器回送收到的请求信息,主要用于测试或诊断
  7. CONNECT: HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。用于代理进行传输,如使用SSL
  8. OPTIONS :请求查询服务器的性能,或者查询与资源相关的选项和需求
    1. 获取服务器支持的HTTP请求方法;也是黑客经常使用的方法。
    2. 用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。

  9. PATCH,部分文档更改
  10. PROPFIND查看属性
  11. PROPPATCH, 设置属性
  12. MKCOL,创建集合(文件夹)
  13. COPY, 拷贝
  14. MOVE,移动
  15. LOCK, 加锁
  16. UNLOCK,解锁
  17. TRACE,用于远程诊断服务器

 

 

参考链接:

转载于:https://www.cnblogs.com/could-deng/p/6739927.html

你可能感兴趣的文章
四则运算C++带Qt界面版本,吾王镇楼。。。。。
查看>>
各种获取时间的方法包含各类时间格式
查看>>
安卓7.0手机拍照闪退问题解决
查看>>
黑马程序员------IO(一)
查看>>
springcloud的配置
查看>>
ME525+ Defy+ 刷机指南[zz]
查看>>
支持触屏的jQuery轮播图插件
查看>>
Codesmith
查看>>
差一点搞混了Transactional注解
查看>>
javascript基本函数
查看>>
C#转义字符
查看>>
前端公共库cdn服务推荐//提高加载速度/节省流量
查看>>
python openpyxl内存不主动释放 ——关闭Excel工作簿后内存依旧(MemoryError)
查看>>
snprintf 返回值陷阱 重新封装
查看>>
asp.net GridView多行表头的实现,合并表头
查看>>
C#套打
查看>>
codeforce 932E Team Work(第二类斯特林数)
查看>>
PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类...
查看>>
省市三级菜单
查看>>
C#中的事件
查看>>