在最近几年里,移动互联网已经是一个炙手可热的领域。移动互联网,简单的说,就是互联网的延伸,将互联网从电脑延伸至手机等移动设备上。伴随着智能手机的普及,以及基于智能手机的各种应用和服务的滋生,如今的移动互联网真正意义上进入了高速发展的阶段。而Android作为智能手机的重要平台之一,必然就会有越来越多的Android应用瞄准这个市场。在现有的Android应用中,有很大一部分都是网络相关的应用。所以,学习网络开发是学习Android应用开发的重要部分。
本章会详细介绍在Android平台上进行网络应用的开发的相关知识。首先会详细介绍如何基于Socket和HTTP协议编程。由于网络操作一般都比较耗时,会详细介绍如何使用多线程和异步处理的方式处理网络请求。最后介绍Android客户端与服务器端进行数据交互的一种通用数据格式——JSON数据格式。
在AndroidSDK中,完全支持JDK本身的TCP、UDP、URL、URLConnection等网络通信的API。同时,AndroidSDK还内置了HttpClient,可以非常方便的发送HTTP请求。
表8-1描述了AndroidSDK中一些与网络有关的package。通过此表可以对Android中网络开发API有一定的了解。
包 |
描述 |
java.net |
提供与联网有关的类,包括流和数据包(datagram)sockets、Internet协议和常见HTTP处理。该包是一个多功能网络资源。 |
java.io |
包中的类由其他Java包中提供的socket和连接使用。它们还用于与本地文件(在与网络进行交互时会经常出现)的交互。 |
java.nio |
包含表示特定数据类型的缓冲区的类。适合用于两个基于Java语言的端点之间的通信。 |
org.apache.* |
表示许多为HTTP通信提供精确控制和功能的包。可以将Apache视为流行的开源Web服务器。 |
android.net |
除核心java.net.*类以外,包含额外的网络访问socket。该包包括URI类,后者频繁用于Android应用程序开发,而不仅仅是传统的联网方面。 |
android.net.http |
包含处理SSL证书的类。 |
android.net.wifi |
包含在Android平台上管理有关WiFi(802.11无线Ethernet)所有方面的类。 |
android.telephony.gsm |
包含用于管理和发送SMS(文本)消息的类。 |
表8-1与网络有关的package
在Android平台上实现网络应用,一般有两种方式。
一种是直接基于Socket编程,一般是针对对于实时性要求较高的场合。比如开发实时监控应用,聊天应用等等。
另一种是基于某种成熟的通讯协议。最常用的就是HTTP协议。
下面的章节,会详细介绍如何实现基于Socket的编程和基于HTTP协议的编程。
经验分享: 如果开发的Android应用需要联网,那么就需要在AndroidManifest.xml中定义相应的权限,否则会抛java.net.SocketException:Permission异常。 在AndroidManifest.xml中定义相应的权限,代码片段如下: <uses-permissionandroid:name=”android.permission.INTERNET”/> |
Socket(套接字)是一种抽象层,应用程序通过它来发送和接收数据,就像应用程序打开了一个文件句柄,将数据读写到稳定的存储器上一样。使用Socket可以将应用程序添加到网络中,并与处于同一网络中的其他应用程序进行通信。一台计算机上的应用程序向socket写入的信息能够被另一台计算机上的另一个应用程序读取,反之亦然。根据不同的底层协议实现,也会有很多种不同的Socket。本章只覆盖了TCP/IP协议的内容,在这个协议当中主要的Socket类型为流套接字(streamsocket)和数据报套接字(datagramsocket)。流套接字将TCP作为其端对端协议,提供了一个可信赖的字节流服务。数据报套接字使用UDP协议,可提供一个“尽力而为”的数据报服务,应用程序可以通过它发送最长65500字节的个人信息。
Socket基本通信模型如图8-1所示:
图8-1Socket基本通信模型图
Socket通信方式有两种,长连接和短连接两种方式。
所谓长连接,指在一个连接上可以连续发送多个数据包,然后断开连接,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。短连接是指通讯双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。
采用长连接和短连接要视情况而定。长连接多用于操作频繁,对正确性要求较高,点对点的通讯的情况。比如很多聊天软件,就采用长连接的方式。长连接一般采用TCP协议的方式。短连接则多用于对正确性要求不高的情况。短连接一般采用UDP协议的方式。
应用程序通过套接字可以进行通信,可以使用UDP协议或者使用TCP协议,但客户端和服务器端的协议运用时应该使用相对应的协议,即客户端使用TCP,那么服务器端使用TCP。
1)TCP协议
长连接方式。首先连接接收方,然后发送数据,保证成功率,速度慢。
TCP通信方式如图8-2所示:
图8-2TCP通信方式图
2)UDP协议
短连接方式。把数据打包成数据包,然后直接发送对应的IP地址,速度快,但是不保证成功率,并且数据大小有限。
和TCP通信对比,UDP通信不使用InputStream和OutputStream。
在Android中开发基于TCP协议的Socket编程,和传统的在JDK下去实现,并没有什么不同。
下面我们来看一个基于TCP协议的Socket通讯的例子,通过这个简单的例子即可理解如何实现服务器端和客户端的简单通信。
TCP协议客户端的实现。
//创建一个Socket对象,指定服务器端的IP地址和端口号 Socketsocket = new Socket("192.168.1.1",1234); //使用InputStream读取硬盘上的文件,做为输入流 InputStreaminputStream = new FileInputStream("f://file/test.txt"); //从Socket当中得到OutputStream,做为输出流 OutputStreamoutputStream = socket.getOutputStream(); bytebuffer [] = new byte[4*1024]; int temp = 0 ; //将InputStream当中的数据取出,并写入到OutputStream当中 while((temp= inputStream.read(buffer)) != -1) { outputStream.write(buffer,0, temp); } outputStream.flush(); |
TCP协议服务器端的现实。
//声明一个ServerSocket对象 ServerSocketserverSocket = null; try { //创建一个ServerSocket对象,并让这个Socket在1234端口监听 serverSocket= new ServerSocket(1234); //调用ServerSocket的accept()方法,接受客户端所发送的请求, //如果客户端没有发送数据,那么该线程就停滞不继续 Socketsocket = serverSocket.accept(); //从Socket当中得到InputStream对象 InputStreaminputStream = socket.getInputStream(); bytebuffer [] = new byte[1024*4]; inttemp = 0; //从InputStream当中读取客户端所发送的数据 while((temp= inputStream.read(buffer)) != -1) { System.out.println(newString(buffer,0,temp)); } }catch (IOException e) { e.printStackTrace(); } serverSocket.close(); |
使用DatagramSocket类可以实现基于UDP协议的Socket编程。
DatagramSocket其实就是一个发射器,专门用来发射DatagramPacket(数据报包)。数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。
DatagramPacket自己的内部就有一个数据缓冲区,可以直接操作这个缓冲区的,向这个缓冲区中写数据,读数据等操作。
下面提供一段代码示例,实现的功能就是通过IP和PORT给自己传递一些数据。
数据的发送的代码片段。
DatagramSocketudpSocket = new DatagramSocket(); byte[]outBuf= "this is a text".getBytes(); DatagramPacketdataPacket = new DatagramPacket(outBuf,outBuf.length); dataPacket.setAddress(InetAddress.getByName("127.0.0.1")); dataPacket.setPort(2000); Log.d("SendLength",""+outBuf.length); dataPacket.setLength(outBuf.length); Log.d("","start send"); udpSocket.send(dataPacket); Log.d("","send over"); |
数据接收端的代码片段。
//作为数据接受端我们只需要监控相应的端口就行了 //host默认为本机host,手机自己里面为127.0.0.1 DatagramSocketudpSocket = new DatagramSocket(2000); DatagramPacketdataPacket = new DatagramPacket(framedata,framedata.length); Log.d("","start receiver"); //这个是使用DatagramActivity的核心 //该方法为阻塞的,会一直阻塞知道有数据过来 udpSocket.receive(dataPacket); Log.d("","receiver ok"); intiLen = dataPacket.getLength(); Log.d("receiveLength",""+iLen); Stringstr = new String(framedata,0,iLen); Log.d("receiveString",str); |
数据接收只需要对端口进行监听就行了,host自动绑定本地host。
经验分享: DatagramSocket类的receive()方法会一直阻塞直到数据过来,源码里面我是先让发送端休眠了3秒,也就是让接收端先接收,因为发送端要3秒后才会发送,所以接收端肯定会先阻塞,等待。 |