• 1. 第七章 Android网络通信第七章 Android网络通信
  • 2. 本章内容Android平台网络通信 Android Http通信 Android Socket通信 Android SSL通信 蓝牙 WIFI第七章 Android网络通信
  • 3. Android网络通信 Android SDK 中一些与网络有关的包如下所示:包描述java.net提供与网络通信相关的类,包括流和数据包socket、Internet协议和常见HTTP处理。该包是一个多功能网络资源。有经验的Java开发人员可以立即使用这个熟悉的包创建应用程序。java.io虽然没有提供现实网络通信功能,但是仍然非常重要。该包中的类由其他Java包中提供的socket和链接使用。它们还用于与本地文件的交互。java.nio包含表示特定数据类型的缓冲区的类。适用于两个基于java语言的端点之间的通信。org.apache.*表示许多为HTTP通信提供精确控制和功能的包。可以将Apache视为流行的开源Web服务器。android.net除核心java.net.*类以外,包含额外的网络访问socket。该包包括URI类,后者频繁用于Android应用程序开发,而不仅仅是传统的联网。android.net.http包含处理SSL证书的类。第七章 Android网络通信
  • 4. Android平台网络通信 Android与服务器通信的方式一般有两种: http通信方式: httpURLConnetction接口、 apache的接口——httpClient接口。http通信也分为post方式和get方式。 socket通信方式 第七章 Android网络通信
  • 5. Tcp连接 要想明白Socket连接,先要明白TCP连接。手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。  建立起一个TCP连接需要经过“三次握手”:  第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;  第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;  第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 第七章 Android网络通信
  • 6. HTTP连接 HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。  HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。  1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。  2)在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。  由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”、“无状态”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即使不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。  第七章 Android网络通信
  • 7. Android HTTP通信—Http的工作方式 HTTP协议采用了请求/响应的工作方式。基于HTTP1.0协议的客户端在每次向服务器发出请求后,服务器就会向客户端返回响应消息(包括请求是否正确以及所请求的数据),在确认客户端已经收到响应消息后,服务端就会关闭网络连接。在这个数据传输过程中,并不保存任何历史信息和状态信息,因此,HTTP协议也被认为是无状态的协议。 HTTP1.0通讯过程如图所示:第七章 Android网络通信
  • 8. Android HTTP通信—Http的工作方式 HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持。当客户端使用HTTP1.1协议连接到服务器后,服务器就将关闭客户端连接的主动权交还给客户端;也就是说,在客户端向服务器发送一个请求并接收以一个响应后,只要不调用Socket类的close方法关闭网络连接,就可以继续向服务器发送HTTP请求。 HTTP1.1通讯过程如图所示:第七章 Android网络通信
  • 9. SOCKET连接套接字(socket)概念  套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息(全相关):连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。  应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。  建立socket连接  建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。第七章 Android网络通信
  • 10. SOCKET连接套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。  服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。  客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。  连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。第七章 Android网络通信
  • 11. SOCKET连接与TCP连接 创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。 第七章 Android网络通信
  • 12. HTTP连接 HTTP连接使用的是“请求—响应”的方式(2次握手),不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。第七章 Android网络通信
  • 13. Android HTTP通信—什么是Http协议 HTTP协议是一种应用层协议,HTTP是HyperText Transfer Protocol(超文本传输协议)的英文缩写。 HTTP可以通过传输层的TCP协议在客户端和服务器之间传输数据。HTTP协议主要用于Web浏览器和Web服务器之间的数据交换。我们在使用IE或Firefox浏览网页或下载Web资源时,通过在地址栏中输入http://host:port/path,开头的4个字母http就相当于通知浏览器使用HTTP协议来和host所确定的服务器进行通讯。 HTTP协议诞生于上世纪90年代初;第一个被广泛使用的版本是HTTP0.9。在随后的HTTP1.0中,增加了很多在HTTP0.9中没有的特性;在最新的HTTP1.1中,对HTTP1.0做了更进一步的改进;HTTP1.1将是HTTP协议的最后一个版本。 想深入了解HTTP协议,请查看RFC2616或通过www.w3c.org来了解HTTP协议的详情。第七章 Android网络通信
  • 14. Android HTTP通信—Http1.1 HTTP1.1除了支持持久连接外,还将HTTP1.0的请求方法从原来的三个(GET、POST和HEAD)扩展到了八个(OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT)。而且还增加了很多请求和响应字段,如上述的持久连接的字段Connection。这个字段有两个值,Close和Keep-Alive。如果使用Connection:Close,则关闭HTTP1.1的持久连接的功能,要打开HTTP1.1的持久连接的功能,必须使用Connection:Keep-Alive,或者不加Connection字段(因为HTTP1.1在默认情况下就是持久连接的)。 除了这些,还提供了身份认证、状态管理和缓存(Cache)等相关的请求头和响应头。第七章 Android网络通信
  • 15. Android HTTP通信—Http协议的特点1.支持客户/服务器模式; 2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP 协议简单,使得HTTP 服务器的程序规模小,因而通信速度很快; 3.灵活:HTTP 允许传输任意类型的数据对象。正在传输的类型由Content-Type 加以标记; 4.无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快;第七章 Android网络通信
  • 16. Android HTTP通信—Http协议详解http://host[":"port][abs_path] http 表示要通过HTTP 协议来定位网络资源;host 表示合法的Internet 主机域名或者IP 地址;port 指定一个端口号,为空则使用缺省端口80;abs_path 指定请求资源的URI;如果URL 中没有给出abs_path,那么当它作为请求URI时,必须以“/”的形式给出,通常这个工作浏览器自动帮我们完成。例如: 1、输入:www.eoeandroid.com 浏览器自动转换成:http://www.eoeandroid.com/ http 请求由三部分组成:请求行、消息报头、请求正文。 1)请求行: Method Request-URI HTTP-Version CRLF 其中Method 表示请求方法;Request-URI 是一个统一资源标识符;HTTP-Version 表示请求的HTTP 协议版本;CRLF 表示回车和换。第七章 Android网络通信
  • 17. Android HTTP通信—Http协议请求方法请求方法(所有方法全为大写)有多种,各个方法的解释如下: GET 请求获取Request-URI 所标识的资源; POST 在Request-URI 所标识的资源后附加新的数据; HEAD 请求获取由Request-URI 所标识的资源的响应消息报头; PUT 请求服务器存储一个资源,并用Request-URI 作为其标识; DELETE 请求服务器删除Request-URI 所标识的资源; TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断; CONNECT 保留将来使用; OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求。 应用举例: GET 方法:GET /form.html HTTP/1.1 (CRLF) POST 方法:POST /reg.jsp HTTP/1.1 (CRLF)第七章 Android网络通信
  • 18. Android HTTP通信—Http响应2)HTTP 响应也是由三个部分组成:状态行、消息报头、响应正文 、状态行格式如下: HTTP-Version Status-Code Reason-Phrase CRLF 其中,HTTP-Version 表示服务器HTTP 协议的版本;Status-Code 表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。 状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值: 1xx:指示信息--表示请求已接收,继续处理 2xx:成功--表示请求已被成功接收、理解、接受 3xx:重定向--要完成请求必须进行更进一步的操作 4xx:客户端错误--请求有语法错误或请求无法实现 5xx:服务器端错误--服务器未能实现合法的请求第七章 Android网络通信
  • 19. Android HTTP通信—Http常见状态码描述常见状态代码、状态描述、说明: 200 OK //客户端请求成功 400 Bad Request //客户端请求有语法错误,不能被服务器所理解 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate 报//头域一起使用 403 Forbidden //服务器收到请求,但是拒绝提供服务 404 Not Found //请求资源不存在,eg:输入了错误的URL 500 Internal Server Error //服务器发生不可预期的错误 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后, //可能恢复正常 eg:HTTP/1.1 200 OK (CRLF)第七章 Android网络通信
  • 20. Android HTTP通信--HttpClient实例在表单提交中Get和POST主要有以下五种区别: 1.get是从服务器上获取数据,post是向服务器传送数据。 2.get是把参数数据队列加到提交表单的 ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTPpost机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。 3.对于get方式,服务器端用 Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。 4.get 传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。 5.get安全性非常低,post安全性较高。第七章 Android网络通信
  • 21. HttpClient—通过Get方式获取请求数据 Android的Get方式首先要初始化  HttpClient client = new DefaultHttpClient();    HttpGet request = new HttpGet(); 在初始化url地址是,可以预先定义一个字符串,在初始化HttpClient时作为构造函数的参数输入;亦可在创建好HttpGet的实例后,采用request.setURL()的方式设置地址。Get方式出了可以访问无参数的地址外也可带参数访问。 实例源码见备注:其中googleWeatherUrl2可以为一个无参数的网络地址,也可以是带参数的网络地址,在本例中 googleWeatherUrl2=http://www.google.com/ig/api?hl=zh-cn&weather=chengdu,第七章 Android网络通信
  • 22. HttpClient—通过Post方式获取请求数据 很多情况下,需要通过POST 将本地的数据发送给服务器,但是post方式比get方式要复杂。首先要通过HttpPost来构建一个post请求。方式如下: HttpPost httppost = new HttpPost(url); 另外需要使用NameValuePair来保存客户端传递的参数,可以使用BasicNameValuePair来构造一个要被传递的参数,通过add方法把这些参数加入到NameValuePair中,代码为: List params = new ArrayList(); params.add(new BasicNameValuePair(valuename,value)); 其他的方式post方式与get方式没有多大差别,可以通过HttpClient来请求连接,返回并响应处理。 实例源码见备注第七章 Android网络通信
  • 23. HttpClient实例运行结果展示注意,要在AndroidManifest.xml中加入 允许用户访问网络。运行时的初始状态Get方式Post方式第七章 Android网络通信
  • 24. Android URL通信 Java网络编程熟悉的人,肯定不会对HttpURLConnection陌生,HttpURLConnection属于JavaAPI的标准接口,包含在包java.net.*中。Android平台的网络应用绝大部分都是基于Java的编程接口的,也就是说我们开发类似的运用的时候可以有多种选择,比J2me确实好多了。 在Android中除了使用WebView控件访问网络以外,还有用代码方式访问网络的方法,代码方式有时候会显得更加灵活。本节介绍使用URLConnection对象和HttpClient组件访问网络的方法。而这两种方法和Java Web开发中的使用方式几乎没有区别,而Web开发的相关资料比比皆是,因此有兴趣的同学学完本讲之后可以专门去研究一下HttpClient4.0的内容,以求更深入的学习。第七章 Android网络通信
  • 25. Android URL通信下面提供了访问 HTTP 服务的基本功能。使用这部分接口的基本操作主要包括: 第一,创建 URL 以及 HttpURLConnection 对象 。 第二,连接参数设置。 第三,连接到服务器。 第四, 向服务器写数据。 最后一步,从服务器读取数据。 URL的使用方法如下面的代码,见备注。第七章 Android网络通信
  • 26. Android URL通信 其中URL的通信方式也可以分别采用前面章节介绍过的Post和Get两种方式来实现。 HttpURLConnection是java的标准类,继承自URLConnection类,URLConnection与HttpURLConnection都是抽象类,无法直接实例化对象。其对象主要通过URL的openConnection方法获得,创建一个httpURLConnection连接的代码如下所示: URL url = new UR(“http://www.baidu.com”); HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); openConnection方法只创建URLConnection或者HttpURLConnection实例,但是并不进行真正的连接操作。并且,每次openConnection都将创建一个新的实例。因此,在连接之前我们可以对其一些属性进行设置,比如超时时间等。第七章 Android网络通信
  • 27. Android URL通信下面对HttpURLConnetcion实例的属性设置: //设置输入/输出流 connection.setDoOutput(true); connection.setDoInput(true); //设置请求的方式为Get或者Post connection.setRequestMethod(“GET”); connection.setRequestMethod(“POST”); //在设置POST方式时要注意,POST请求方式不能够使用缓存 connection.setUseCaches(false); 在完成HttpURLConnection实例的初始化以后,我们可以分别使用Get和POST方式来完成一个实例。第七章 Android网络通信
  • 28. Android URL通信实例—布局文件 在该实例中Android设备的主界面主要包括一个静态文本框,两个按钮以及一个文本框用来显示请求返回的数据结果。整个Activity的布局如下: 第七章 Android网络通信
  • 29. Android URL通信实例—Get方式Get用于获取静态页面,只要把参数写在URL后面即可传送数据。一般只需要创建一个HttpURLConnection: URL url=new URL(http://www.google.cn/hk); HttpURLConnection urlConn=(HttpURLConnection)url.openConnection(); 注意:HttpURLConnection是Java的标准类,继承自URLConnection类,两者都是抽象类,无法进行实例化对象。其对象主要通过URL的openConnection方法获得 采用get方式的HttpURLConnetction实例源码见备注:此外,还需在AndroidManifest.xml中配置: 第七章 Android网络通信
  • 30. Android URL通信实例—Post方式在Post中,openConnection方法只创建了URLConnection或者HttpURLConnection实例,但是并不进行真正的连接操作。并且,每次openConnection都将创建一个新的实例。因此,连接之前我们需要对其一些属性进行操作,比如超过时间等。下面是对HttpURLConnection实例的属性设置: //设置输入(输出)流 connection.setDoOutput(true); connection.setDoInput(true); //设置方式为POST connection.setRequestMethod("POST"); //Post请求不能使用缓存 connection.setUseCaches(false); //关闭HttpURLConnection连接 urlConn.disconnect(); 采用post方式的HttpURLConnetction实例源码见备注:第七章 Android网络通信
  • 31. Android URL通信实例效果图URL通信的Get方式和Post方式效果图如下:运行时的初始状态Get方式Post方式第七章 Android网络通信
  • 32. Android 套接字(Socket)通信什么是套接字(Socket)? Network API是典型的用于基于TCP/IP网络Java程序与其他程序通讯,Network API依靠Socket进行通讯。 Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中,如图:第七章 Android网络通信
  • 33. Android 套接字(Socket)通信 分析一下上图,Host A上的程序A将一段信息写入Socket中,Socket的内容被Host A的网络管理软件访问,并将这段信息通过Host A的网络接口卡发送到Host B,Host B的网络接口卡接收到这段信息后,传送给Host B的网络管理软件,网络管理软件将这段信息保存在Host B的Socket中,然后程序B才能在Socket中阅读这段信息。 假设在图中的网络中添加第三个主机Host C,那么Host A怎么知道信息被正确传送到Host B而不是被传送到Host C中了呢? 基于TCP/IP网络中的每一个主机均被赋予了一个唯一的IP地址。每一个基于TCP/IP网络通讯的程序都被赋予了唯一的端口和端口号,端口是一个信息缓冲区,用于保留Socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每一个程序(端口号就像房屋中的房间号),低于256的短口号保留给标准应用程序。第七章 Android网络通信
  • 34. Android 套接字(Socket)通信—Socket类 两个常用的构造函数是 Socket(InetAddress addr, int port) 和 Socket(String host, int port),两个构造函数都创建了一个基于Socket的连接服务器端流套接字的流套接字。 对于第一个InetAddress子类对象通过addr参数获得服务器主机的IP地址,对于第二个函数host参数包被分配到InetAddress对象中,如果没有IP地址与host参数相一致,那么将抛出UnknownHostException异常对象。两个函数都通过参数port获得服务器的端口号。 如果创建了一个Socket对象,那么它可能通过调用Socket的 getInputStream()方法从服务程序获得输入流读传送来的信息,也可能通过调用Socket的 getOutputStream()方法获得输出流来发送消息。第七章 Android网络通信
  • 35. Android 套接字(Socket)通信—Socket类 下面我们将示范一个流套接字的客户程序,这个程序将创建一个Socket对象,Socket将访问运行在指定主机端口10000上的服务程序,如果访问成功客户程序将给服务程序发送一系列命令并打印服务程序的响应。 SSClient的源代码见备注:运行这段程序将会得到下面的结果: Tue Jan 29 18:11:51 CST 2002 TUESDAY 29 29第七章 Android网络通信
  • 36. Android 套接字(Socket)通信—Socket类 在SSClient源代码编译完成后,可以输入java SSClient 来执行这段程序,如果有合适的程序运行在不同的主机上,采用主机名/IP地址为参数的输入方式,比如www.sina.com.cn是运行服务器程序的主机,那么输入方式就是java SSClient www.sina.com.cn。技巧   Socket类包含了许多有用的方法。比如 getLocalAddress()将返回一个包含客户程序IP地址的InetAddress子类对象的引用; getLocalPort()将返回客户程序的端口号; getInetAddress()将返回一个包含服务器IP地址的InetAddress子类对象的引用; getPort()将返回服务程序的端口号第七章 Android网络通信
  • 37. Android 套接字编程实例a) 创建Socket的方法: Socket(InetAddress remoteAddress,int remotePort) 利用Socket的构造函数,可以创建一个TCP套接字后,先连接到指定的远程地址和端口号。 b) 操作Socket的方法 InputStream getInputStream() OutputStream getOutputStream() void close() 操作TCPsocket的图如下所示:第七章 Android网络通信
  • 38. Android 套接字通信—ServerSocket类 由于SSClient使用了流套接字,所以服务程序也要使用流套接字。这就要创建一个ServerSocket对象,ServerSocket有几个构造函数,最简单的是ServerSocket(int port),当使用ServerSocket(int port)创建一个ServerSocket对象,port参数传递端口号,这个端口就是服务器监听连接请求的端口,如果在这时出现错误将抛出IOException异常对象,否则将创建ServerSocket对象并开始准备接收连接请求。 接下来服务程序进入无限循环之中,无限循环从调用ServerSocket的accept()方法开始,在调用开始后accept()方法将导致调用线程阻塞直到连接建立。在建立连接后accept()返回一个最近创建的Socket对象,该Socket对象绑定了客户程序的IP地址或端口号。第七章 Android网络通信
  • 39. Android 套接字编程实例 ServerSocket:这个类是实现了一个服务器端的Socket,利用这个类可以监听来自网络的请求。 a) 创建ServerSocket的方法: ServerSocket(Int localPort) ServerSocket(int localport,int queueLimit) ServerSocket(int localport,int queueLimit,InetAddress localAddr) 创建一个ServerSocket必须指定一个端口,以便客户端能够向该端口号发送连接请求。端口的有效范围是0-65535 b) ServerSocket操作 Socket.accept() void close accept()方法为下一个传入的连接请求创建Socket实例,并将已成功连接的Socket实例返回给服务器套接字,如果没有连接请求,accept()方法将阻塞等待;close方法用于关闭套接字第七章 Android网络通信
  • 40. Android 套接字通信—ServerSocket类 为了示范我们在上面谈到的慨念并完成SSClient程序,下面我们创建一个SSServer程序,程序将创建一个ServerSocket对象来监听端口10000的连接请求,如果成功服务程序将等待连接输入,开始一个线程处理连接,并响应来自客户程序的命令。 这段程序的代码见备注。运行这段程序将得到下面的输出: Server starting... Accepting Connection... Closing Connection...第七章 Android网络通信
  • 41. Android 套接字编程实例基于TCP的Socket实例的Server端和Client端的代码见备注。Activity的布局文件main.xml为: 第七章 Android网络通信
  • 42. Android 套接字编程实例需要注意的是需要在AndroidMainfest.xml文件中加入一行允许用户访问网络的代码: 服务器端初始状态客户端初始状态运行时服务器状态运行时客户端状态第七章 Android网络通信
  • 43. Android 套接字通信—数据报套接字 使用流套接字的每个连接均要花费一定的时间,要减少这种开销,网络API提供了第二种套接字:自寻址套接字(datagram socket),数据报使用UDP发送寻址信息(从客户程序到服务程序或从服务程序到客户程序),不同的是可以通过数据报套接字发送多IP信息包,数据报信息包含在自寻址包中,此外自寻址包又包含在IP包内,这就将寻址信息长度限制在60000字节内。图4显示了位于IP包内的数据报包的自寻址信息。第七章 Android网络通信
  • 44. Android 套接字通信—数据报套接字 数据报套接字工作包括下面三个类:DatagramPacket, DatagramSocket,和 MulticastSocket。DatagramPacket对象描绘了数据报包的地址信息,DatagramSocket表示客户程序和服务程序数据报套接字,MulticastSocket描绘了能进行多点传送的数据报套接字,这三个类均位于java.net包内。 在使用数据报之前,你需要首先熟悉DatagramPacket类,地址信息和数据报以字节数组的方式同时压缩入这个类创建的对象中。   DatagramPacket有数个构造函数,即使这些构造函数的形式不同,但通常情况下他们都有两个共同的参数:byte [] buffer 和 int length,buffer参数包含了一个对保存数据报信息的字节数组的引用,length表示字节数组的长度。第七章 Android网络通信
  • 45. 使用基于UDP的Socketa) 创建DatagramPacket DatagramSocket(byte [] data,int offset,int length,InetAddress remoteAddr,int remotePort) 该构造函数创建一个数据报文对象,数据包含在第一个参数当中 b) 创建DatagramSocket创建 DatagramSocket(int localPort) 以上构造函数将创建一个UDP套接字; c) DatagramSocket:发送和接受 void send(DatagramPacket packet) void receive(DatagramPacket packet) send()方法用来发送DatagramPacket实例。一旦创建连接,数据报将发送到该套接字所连接的地址; receive()方法将阻塞等待,知道接收到数据报文,并将报文中的数据复制到指定的DatagramPacket实例中。 对AndroidManifest.xml的配置一定不要忘了: 编程方式跟Tcp方式一样,有兴趣的同学可以去尝试实现。第七章 Android网络通信
  • 46. Android SSL通信Android SSL通信模式: Android平台下的应用开发采用JAVA语言,在Android提供的默认类库中,javax.net.ssl类库包实现了通用的SSL功能。具体实现时,只需将证书文件和CA信任列表load到对应的KeyStore中,并用这些KeyStore初始化需要打开的SSLContext,然后建立连接,底层虚拟机就实现了单(双)向握手过程,之后只要简单的使用BufferReader和BufferWriter就实现了SSL加密传输。 Android的私钥和信任证书的格式必须是BKS格式的,通过配置本地JDK,让keytool可以生成BKS格式的私钥和信任证书,java本身没有BouncyCastle密库 。为了实现消息认证。 Server需要: 1) KeyStore:其中保存服务端的私钥 2) Trust KeyStore:其中保存客户端的授权证书 Clinet需要: 1) KeyStore:其中保存客户端的私钥 2) Trust KeyStore:其中保存服务端的授权证书第七章 Android网络通信
  • 47. Android SSL通信—服务端密钥文件的生成使用java自带的keytool命令,去生成这样信息文件:1) 生成服务端私钥,并且导入到服务端KeyStore文件中2) 根据私钥,导出服务端证书3) 将服务端证书,导入到客户端的TrustKeyStore中第七章 Android网络通信
  • 48. Android SSL通信—客户端密钥文件的生成采用同样的方法,生成客户端的私钥,客户端的证书,并且导入到服务端的Trust KeyStore中。 keytool -genkey -alias clientkey -keystore kclient.keystore keytool -export -alias clientkey -keystore kclient.keystore -file client.crt keytool -import -alias clientkey -file client.crt -keystore tserver.keystore有兴趣的同学可以参考备注里的客户端和服务端实现的代码,看看Android SSL通信的效果。第七章 Android网络通信
  • 49. Android 蓝牙通信—蓝牙的基本知识蓝牙(Bluetooth,亦译作“蓝芽”),是一种无线个人局域网(Wireless PAN),最初由爱立信创制,后来由蓝牙技术联盟订定技术标准。据说为了强调此技术及应用尚在萌芽阶段的意义,故将Bluetooth中文译名为较文雅的“蓝芽”,并在台湾进行商业的注册。在2006年,蓝牙技术联盟组织已将全球中文译名统一改采直译为“蓝牙”。蓝牙的标准是IEEE 802.15.1,蓝牙协议工作在无需许可的ISM(Industrial Scientific Medical)频段的2.45GHz。最高速度可达723.1kb/s。为了避免干扰可能使用2.45GHz的其它协议,蓝牙协议将该频段划分成79频道,(带宽为1MHZ)每秒的频道转换可达1600次。 拿蓝牙与WiFi相比是不适当的,因为WiFi是一个更加快速的协议,覆盖范围更大。虽然两者使用相同的频率范围,但是WiFi需要更加昂贵的硬件。蓝牙设计被用来在不同的设备之间创建无线连接,而WiFi是个无线局域网协议。两者的目的是不同的。第七章 Android网络通信
  • 50. Android 蓝牙通信—蓝牙的基本知识开放式无线通讯标准 设备短距离互联解决方案定义:优势:无需驱动程序——独特的配置文件 小型化无线电 低功率、低成本、安全性、稳固 易于使用、即时连接第七章 Android网络通信
  • 51. Android 蓝牙通信—蓝牙的基本知识蓝牙协议栈:核心协议层(基带、主控制层接口HCI、链路管理协议LMP、逻辑链路控制和适配协议L2CAP、服务发现协议SDP) 线缆替换协议层(无线射频通信RFCOMM) 电话控制协议层(二进制电话控制标准TCS-BIN、电话控制协议标准的AT命令集合) 选用协议层(PPP、TCP、IP、UDP、OBEX、IrMC、WAP、WAE)具体介绍见备注第七章 Android网络通信
  • 52. Android 蓝牙通信—蓝牙的基本知识蓝牙协议栈图解:vCard/vCalOBEXWAEWAPTCS-BINTCS-ATUDPTCP/IPPPPRFCOMMSDPL2CAP语音LMP基带蓝牙无线电信道主控制器接口(HCI)第七章 Android网络通信
  • 53. Android 蓝牙通信—蓝牙的基本知识蓝牙立体声音频传输规范(A2DP) 基本图像规范(BIP) 基本打印规范(BPP) 无线电话规范(CTP) 蓝牙耳机规范(HP) 文件传输规范(FTP) ……蓝牙规范(profile)——为了保证蓝牙设备的互通性而制定的一系列规范蓝牙应用规范。蓝牙应用是根据蓝牙SIG(特殊兴趣小组)所称的“应用规范”进行分类的,“profiles”就是形成使用模式的规程。蓝牙应用规范的目的是为应用的互操作性提供构架。蓝牙应用规范根据某个协议所能支持的特殊使用模式或功能来对这个协议的消息和特性进行详细说明。使用模式包括传送、局域网访问、目标推进和同步。一些蓝牙应用规范仍在定义之中,这儿列出由Bluetooth SIG(special interest group)制定的一部分profile 。第七章 Android网络通信
  • 54. Android平台的蓝牙编程 Android平台支持蓝牙网络协议栈,实现蓝牙设备之间数据的无线传输。本小节描述了怎样利用android平台提供的蓝牙API去实现蓝牙设备之间的通信。 蓝牙设备之间的通信主要包括了四个步骤: 设置蓝牙设备 寻找局域网内可能或者匹配的设备 连接设备 设备之间的数据传输 Android所有关于蓝牙开发的类都在android.bluetooth包下,一共有8个类,以下是建立蓝牙连接的所需要的一些基本类:第七章 Android网络通信
  • 55. Android平台的蓝牙编程-- BluetoothAdapter BluetoothAdapter类:代表了一个本地的蓝牙适配器,是所有蓝牙交互的的入口点。利用它你可以发现其他蓝牙设备,查询绑定了的设备,使用已知的MAC地址实例化一个蓝牙设备和建立一个BluetoothServerSocket(作为服务器端)来监听来自其他设备的连接。 BluetoothAdapter里的方法很多,常用的有以下几个:       cancelDiscovery() 根据字面意思,是取消发现,也就是说当我们正在搜索设备的时候调用这个方法将不再继续搜索。       disable()关闭蓝牙。       enable()打开蓝牙   getAddress()获取本地蓝牙地址       getDefaultAdapter()获取默认BluetoothAdapter,实际上,也只有这一种方法获取BluetoothAdapter       getName()获取本地蓝牙名称       getRemoteDevice(String address)根据蓝牙地址获取远程蓝牙设备       getState()获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)       isDiscovering()判断当前是否正在查找设备,是返回true       isEnabled()判断蓝牙是否打开,已打开返回true,否则,返回false第七章 Android网络通信
  • 56. Android平台的蓝牙编程-- BluetoothDevice BluetoothDevice类:代表了一个远端的蓝牙设备,使用它请求远端蓝牙设备连接或者获取远端蓝牙设备的名称、地址、种类和绑定状态。(其信息是封装在bluetoothsocket中)。 获取BluetoothDevice的目的——创建BluetoothSocket这个类: createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个BluetoothSocket。 其他方法,如getAddress(),getName(),同BluetoothAdapter。第七章 Android网络通信
  • 57. Android平台的蓝牙编程-- Bluetoothsocket Bluetoothsocket类:代表了一个蓝牙套接字的接口(类似于tcp中的套接字),是应用程序通过输入、输出流与其他蓝牙设备通信的连接点。 一共5个方法,分别是       close(),与服务器断开关闭       connect(),与服务器建立连接       getInptuStream(),获取输入流       getOutputStream(),获取输出流       getRemoteDevice(),获取远程设备,指的是获取bluetoothSocket指定连接的那个远程蓝牙设备。第七章 Android网络通信
  • 58. Android平台的蓝牙编程-- Blueboothserversocket Blueboothserversocket类:打开服务连接来监听可能到来的连接请求(属于server端),为了连接两个蓝牙设备必须有一个设备作为服务器打开一个服务套接字。当远端设备发起连接连接请求的时候,并且已经连接到了的时候,Blueboothserversocket类将会返回一个bluetoothsocket。 只有三个方法: 两个重载的accept(),accept(int timeout)。两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,直到接收到了客户端的请求(或是过期之后),都会阻塞线程,应该放在新线程里运行。这两个方法都返回一个BluetoothSocket,最后的连接也是服务器端与客户端的两个BluetoothSocket的连接。 close()关闭连接方法。第七章 Android网络通信
  • 59. Android平台的蓝牙编程在编程之前,需要在AndroidMainfest.xml中加入操作权限,代码如下: 1、获取本地蓝牙: 必须确定你的设备支持蓝牙,并保证他可以用。如果你的设备支持蓝牙,将它使能。当然,有两种方法,一种是在你的系统设置里开启蓝牙,另外一中是在你的应用程序里启动蓝牙功能,第一种方法就不讲了,具体讲一个第二种方法: 首先通过调用静态方法getDefaultAdapter()获取蓝牙适配器bluetoothadapter,以后你就可以使用该对象了。如果返回为空,则说明设备不支持蓝牙功能。 BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // Device does not support Bluetooth }第七章 Android网络通信
  • 60. Android平台的蓝牙编程 其次,调用isEnabled()来查询当前蓝牙设备的状态,如果返回为false,则表示蓝牙设备没有开启,接下来你需要封装一个ACTION_REQUEST_ENABLE请求到intent里面。例如: if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } 至此,如不出意外,恭喜你的蓝牙设备已经开启了,接下来需要查找周边可能存在的蓝牙设备了。第七章 Android网络通信
  • 61. Android平台的蓝牙编程2、查找设备: 使用bluetoothadapter类里的方法,你可以查找远端设备或者查询在你手机上已经匹配(或者说绑定)的其他手机了。当然需要确定对方蓝牙设备已经开启或者已经开启了“被发现使能“功能(对方设备是可以被发现的是你能够发起连接的前提条件)。如果该设备是可以被发现的,会反馈回来一些对方的设备信息,比如名字、MAC地址等,利用这些信息,你的设备就可以选择去向对方初始化一个连接。 如果你是第一次与该设备连接,那么一个配对的请求就会自动的显示给用户。 当设备配对好之后,他的一些基本信息(主要是名字和MAC)被保存下来并可以使用蓝牙的API来读取。使用已知的MAC地址就可以对远端的蓝牙设备发起连接请求。第七章 Android网络通信
  • 62. Android平台的蓝牙编程怎么查询匹配好的设备: 在建立连接之前你必须先查询配对好了的蓝牙设备集(你周围的蓝牙设备可能不止一个),以便你选取哪一个设备进行通信,例如你可以查询所有配对的蓝牙设备,并使用一个数组适配器将其打印显示出来: SetpairedDevices=mBluetoothAdapter.getBondedDevices(); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } 建立一个蓝牙连接只需要MAC地址就已经足够了。第七章 Android网络通信
  • 63. Android平台的蓝牙编程3、扫描设备: 扫描设备,只需要简单的调用startDiscovery()方法,这个扫描的过程大概持续是12秒,应用程序为了ACTION_FOUND动作需要注册一个BroadcastReceiver来接受设备扫描到的信息。对于每一个设备,系统都会广播ACTION_FOUND动作。 扫描设备的样例见备注。 注意:扫描的过程是一个很耗费资源的过程,一旦你找到你需要的设备之后,在发起连接请求之前,确保你的程序调用cancelDiscovery()方法停止扫描。显然,如果你已经连接上一个设备,启动扫描会减少你的通信带宽。 如果你想使你的设备能够被其他设备发现,将ACTION_REQUEST_DISCOVERABLE动作封装在intent中并调用startActivityForResult(Intent, int)方法就可以了。第七章 Android网络通信
  • 64. Android平台的蓝牙编程 在你的应用程序中,想建立两个蓝牙设备之间的连接,你必须实现客户端和服务器端的代码(因为任何一个设备都必须可以作为服务端或者客户端)。一个开启服务来监听,一个发起连接请求(使用服务器端设备的MAC地址)。 当他们都拥有一个蓝牙套接字在同一RFECOMM信道上的时候,可以认为他们之间已经连接上了。 当一个连接监听到的时候,服务端获取到蓝牙套接字。当客户可打开一个FRCOMM信道给服务器端的时候,客户端获取到蓝牙套接字。注意:在此过程中,如果两个蓝牙设备还没有配对好的,android系统会通过一个通知或者对话框的形式来通知用户。RFCOMM连接请求会在用户选择之前阻塞。第七章 Android网络通信
  • 65. Android平台的蓝牙连接—服务端服务端的连接: 当你想要连接两台设备时,一个必须作为服务端(通过持有一个打开的bluetoothserversocket),目的是监听外来连接请求,当监听到以后提供一个连接上的bluetoothsocket给客户端,当客户端从bluetoothserversocket得到bluetoothsocket以后就可以销毁bluetoothserversocket,除非你还想监听更多的连接请求。建立服务套接字和监听连接的基本步骤如下:1、首先通过调用listenUsingRfcommWithServiceRecord(String, UUID)方法来获取bluetoothserversocket对象。2、其次调用accept()方法来监听可能到来的连接请求,当监听到以后,返回一个连接上的蓝牙套接字bluetoothsocket。3、最后,在监听到一个连接以后,需要调用close()方法来关闭监听程序。第七章 Android网络通信
  • 66. Android平台的蓝牙连接—服务端注意:accept()方法不应该放在主Acitvity里面,因为他是一种阻塞调用(在没有监听到连接请求之间程序就一直停在那里)。解决方法是新建一个线程来管理。示例代码见备注。第七章 Android网络通信
  • 67. Android平台的蓝牙连接—客户端客户端连接 为了初始化一个与远端设备的连接,需要先获取代表该设备的一个bluetoothdevice对象。通过bluetoothdevice对象来获取bluetoothsocket并初始化连接: 使用bluetoothdevice里的方法createRfcommSocketToServiceRecord(UUID)来获取bluetoothsocket。UUID就是匹配码。 调用connect()方法。如果远端设备接收了该连接,他们将在通信过程中共享RFFCOMM信道,并且connect()方法返回。示例代码见备注。 注意:conncet()方法也是阻塞调用,一般建立一个独立的线程中来调用该方法。在设备discover过程中不应该发起连接connect(),这样会明显减慢速度以至于连接失败。且数据传输完成只有调用close()方法来关闭连接,这样可以节省系统内部资源。第七章 Android网络通信
  • 68. Android平台的蓝牙连接—客户端管理连接(主要涉及数据的传输): 当设备连接上以后,每个设备都拥有各自的bluetoothsocket。现在你就可以实现设备之间数据的共享了。 1. 首先通过调用getInputStream()和getOutputStream()方法来获取输入输出流。然后通过调用read(byte[]) 和 write(byte[]).方法来读取或者写数据。 2. 实现细节:以为读取和写操作都是阻塞调用,需要建立一个专用线程来管理。线程示例见备注:第七章 Android网络通信
  • 69. Android WIFI—WIFI简介 Wi-Fi 原先是无线保真的缩写,Wi-Fi 的英文全称为wireless fidelity,在无线局域网的范畴是指“无线相容性认证”,实质上是一种商业认证,同时也是一种无线联网的技术,以前通过网线连接电脑,而现在则是通过无线电波来连网;常见的就是一个无线路由器,那么在这个无线路由器的电波覆盖的有效范围都可以采用WIFI连接方式进行联网,如果无线路由器连接了一条ADSL线路或者别的上网线路,则又被称为“热点”。 Wi-Fi是一种帮助用户访问电子邮件、Web和流式媒体的互联网技术。它为用户提供了无线的宽带互联网访问。同时,它也是在家里、办公室或在旅途中上网的快速、便捷的途径。能够访问 Wi-Fi 网络的地方被称为热点。Wi-Fi或802.11G在2.4Ghz频段工作,所支持的速度最高达54Mbps。另外还有两种802.11空间的协议,包括(a)和(b)。它们也是公开使用的,但802.11G在世界上最为常用。第七章 Android网络通信
  • 70. WIFI模块第七章 Android网络通信
  • 71. WIFI网卡的状态 WIFI网卡的状态是由一系列的整形常量来表示的: 0 --> WIFI_STATE_DISABLING 1 --> WIFI_STATE_DISABLED 2 --> WIFI_STATE_ENABLING 3 --> WIFI_STATE_ENABLED 4 --> WIFI_STATE_UNKNOWN 其中0表示网卡正在关闭;1表示网卡不可用,2表示网卡正在打开,3表示网卡可用,4表示未知网卡状态。第七章 Android网络通信
  • 72. AndroidMenifest.xml中WIFI权限设置   //修改网络状态的权限   //修改wifi状态的权限   //访问网络权限    //访问wifi权限第七章 Android网络通信
  • 73. 对WIFI网卡的操作过程Android开发Wifi主要包括以下几个类和接口: 1、ScanResult 主要用来描述已经检测出的接入点,包括接入点的地址、接入点的名称、身份认证、频率、信号强度等信息。 2、WifiConfiguration WiFi网络的配置,包括安全配置等。 3、WifiInfo WiFi无线连接的描述,包括接入点、网络连接状态、隐藏的接入点、IP地址、连接速度、MAC地址、网络ID、信号强度等信息。 4、WifiManager 提供了管理WiFi连接的大部分API,它主要包括如下内容: 已经配置好的网络清单。这个清单可以查看和修改,而且可以修改个别记录的属性。当连接中有活动的Wi-Fi网络时,可以建立或者关闭这个链接,并且可以查询有关网络状态的动态信息。对接入点的扫描结果包含足够的信息来决定需要与什么接入点建立连接。还定义了许多常量来表示Wi-Fi状态的改变。第七章 Android网络通信
  • 74. 对WIFI网卡的操作过程对wifi网卡进行操作需要通过WifiManger对象来进行,获取该对象的方法如下: WifiManger wifiManger =  (WifiManger)Context.getSystemService(Service.WIFI_SERVICE);  打开wifi网卡:wifimanger.setWifiEnabled(true);  关闭wifi网卡:wifiManger.setWifiEnablee(false);  获取网卡的当前的状态:wifiManger.getWifiState(); 添加一个配置好的网络连接:wifiManger.addNetwork(); 计算信号的强度:wifiManger.calculateSignalLevel(); 比较两个信号的强度:wifiManger.compareSignalLevel(); 创建一个WiFi锁:wifiManger.createWifiLock(); 从接入点断开:wifiManger.disconnect(); 扫描已存在的接入点:wifiManger.startScan(); 更新已经配置好的网络:wifiManger.updateNetwork();第七章 Android网络通信
  • 75. Android WIFI开发用例—布局文件Main.xml的内容为:
  • 76. Android WIFI开发用例— AndroidMainfest.xml 第七章 Android网络通信
  • 77. Android WIFI开发用例— java代码Java代码见备注运行结果展示: (注:模拟器没有WIFI网卡,只是模拟网卡的打开过程)WIFI没打开之前检查WIFI开启WIFI网卡第七章 Android网络通信