您的位置:首页 > 理论基础 > 计算机网络

Android连网详解——android.net、org.apache.http联网实现

2016-10-18 09:56 417 查看
1.连网相关包介绍 

今天我们将深入介绍了Android SDK 中一些与网络有关的package,如下: 

包描述 

java.net提供与联网有关的类,包括流和数据包(datagram)sockets、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.net.wifi包含在 Android 平台上管理有关 WiFi(802.11 无线 Ethernet)所有方面的类。并不是所有设备都配备了 WiFi 功能,特别是 Android 在 Motorola 和 LG 等手机制造商的 “翻盖手机” 领域获得了成功。
android.telephony.gsm包含用于管理和发送 SMS(文本)消息的类。一段时间后,可能会引入额外的包来来为非 GSM 网络提供类似的功能,比如 CDMA 或 android.telephony.cdma 等网络。
上表并没有列出所有包,但是可以让我们清楚地意识到Android的强大功能。 

介绍一个简单的网络示例 

在EditView中输入URL后,单击“go!”按钮,界面显示如下 


 

界面部分的代码简要明了,就不此额外说明了,下面详细解析核心代码,如下: 

Java代码 

  




final Button button = (Button) findViewById(R.id.ButtonGo);   
button.setOnClickListener(new Button.OnClickListener() {   
public void onClick(View v) {
  
try{   
tView.setText(”");   
// 获取输入的URL地址   
URL url = new URL(eText.getText().toString());   
URLConnection conn = url.openConnection();   
//获取网页数据流   
BufferedReader rd =   
new BufferedReader(new InputStreamReader(conn.getInputStream()));
  
String line = “”;   
//读取数据   
while ((line = rd.readLine()) != null) {
  
Message lmsg;   
lmsg = new Message();   
lmsg.obj = line;   
lmsg.what = 0;   
//将数据显示在界面上   
h.sendMessage(lmsg);   
}   
}   
catch (Exception e)   
{   
//输出异常信息   
Log.v(”Browse”, e.toString());   
}   
}   
});  

简要解析如下:URL 和 URLConnection 类共同提供与用户所选的 Web 站点的连接。BufferedReader 的一个实例负责从 Web 站点连接中读取传入的数据。每读取一行代码,文本就被附加到一个 TextView。数据并没有直接指定给 TextView,而是引入了一种设计模式,即创建一个消息对象并将该对象发送到一个处理程序的实例。这是更新 UI 的一种比较可取的方法,对可能需要同时运行多个线程的应用程序而言尤其如此。 A Handler allows you to send and process
Message and Runnable objects associated with a thread’s MessageQueue,这句话简单明了,相信大家一看就完全明白了。 

补充说明 

以上程序,在实际运行中可能会导致异常,catch (Exception e) 输出异常信息: 

java.net.SocketException: Permission denied(maybe missing INTERNET permission) 

需要在AndroidManifest.xml中定义相应的权限,如下: 

<uses-permission android:name=”android.permission.INTERNET” /> 

注意在<application>也可以定义INTERNET权限,如下: 

<application android:permission=”android.permission.INTERNET”> 

这种权限似乎还是会导致异常,看来两种权限除了作用的范围有所不同,具体的作用也是有些不同的,以后开发中需要注意两者的区别。 

2、org.apache.http联网实现 

Android使用HttpClient完成Post和Get方式的联网请求 

Android联网可以采用HttpPost,HttpGet封装post请求和get请求,再使用HttpClient的excute方法发送post或者get请求并返回服务器的响应数据。 

      1、设置连接和读取超时时间,并新建HttpClient对象: 

            // 设置连接超时时间和数据读取超时时间 

            HttpParams httpParams = new BasicHttpParams(); 

            HttpConnectionParams.setConnectionTimeout(httpParams, 

                    KeySource.CONNECTION_TIMEOUT_INT); 

            HttpConnectionParams.setSoTimeout(httpParams, 

                    KeySource.SO_TIMEOUT_INT); 

            //新建HttpClient对象 

            HttpClient httpClient = new DefaultHttpClient(httpParams) 

2、Get请求: 

       // generate get request 

        HttpGet get = new HttpGet(url); 

        // set HTTP head parameters 

        //Map<String, String> headers 

        if (headers != null) 

        { 

            Set<String> setHead = headers.keySet(); 

            Iterator<String> iteratorHead = setHead.iterator(); 

            while (iteratorHead.hasNext()) 

            { 

                String headerName = iteratorHead.next(); 

                String headerValue = (String) headers.get(headerName); 

                MyLog.d(headerName, headerValue); 

                get.setHeader(headerName, headerValue); 

            } 

        } 

            // connect 

            //need try catch 

            response = httpClient.execute(get); 

   3、Post请求: 

           HttpPost post = new HttpPost(KeySource.HOST_URL_STR); 

            // set HTTP head parameters 

            Map<String, String> headers = heads; 

            Set<String> setHead = headers.keySet(); 

            Iterator<String> iteratorHead = setHead.iterator(); 

            while (iteratorHead.hasNext()) 

            { 

                String headName = iteratorHead.next(); 

                String headValue = (String) headers.get(headName); 

                post.setHeader(headName, headValue); 

            } 

          /** 

                 * 通常的HTTP实体需要在执行上下文的时候动态生成的。 

                 * HttpClient的提供使用EntityTemplate实体类和ContentProducer接口支持动态实体。 

                 * 内容制作是通过写需求的内容到一个输出流,每次请求的时候都会产生。 

                 * 因此,通过EntityTemplate创建实体通常是独立的,重复性好。 

                 */ 

          ContentProducer cp = new ContentProducer() 

                { 

                    public void writeTo(OutputStream outstream) 

                            throws IOException 

                    { 

                        Writer writer = new OutputStreamWriter(outstream, 

                                "UTF-8"); 

                        writer.write(requestBody); 

                        writer.flush(); 

                        writer.close(); 

                    } 

                }; 

                HttpEntity entity = new EntityTemplate(cp); 

                post.setEntity(entity); 

            } 

            //connect ,need try catch 

            response = httpClient.execute(post);  

     4、请求Response响应处理: 

if (response.getStatusLine().getStatusCode() == 200) 

            { 

                // get response xml. 

                /** 

                 * 因为直接调用toString可能会导致某些中文字符出现乱码的情况。所以此处使用toByteArray 

                 * 如果需要转成String对象,可以先调用EntityUtils.toByteArray()方法将消息实体转成byte数组, 

                 * 在由new String(byte[] bArray)转换成字符串。 

                 */ 

                byte[] bResultXml = EntityUtils.toByteArray(response 

                        .getEntity()); 

                if (bResultXml != null) 

                { 

                        String  strXml = new String(bResultXml, "utf-8"); 

                } 

           } 

         //Todo xmlAnalysis.. 

3.java.net 联网详解 

本篇幅我们漫游java.net包,按照网络方面的知识来逐步学习java网络编程,并给大家介绍一些小例子,边学习边写代码。 

首先,IP地址 

IP地址估计大家都明白,我们就直接来看java.net中的类吧。 


 

详细介绍就不多说了,看2个简单的小例子如下: 

Java代码 

  




String GetHostAddress (String strHostName)   
{   
InetAddress address = null;   
try  
{   
address = InetAddress.getByName (strHostName);   
}   
catch(UnknownHostException e)   
{   
System.out.println(e.getMessage());   
}   
return InetAddress.getHostAddress () ;   
}   
  
void GetAllIP (String strHostName)   
{   
InetAddress[] add = null;   
try  
{   
add = InetAddress.getAllByName (strHostName);   
for(int i=0;i<addr.lenth;i++)
  
System.out.println(addr[i]);   
}   
catch(UnknownHostException e)   
{   
System.out.println(e.getMessage());   
}   
}  

上面2个小例子很简单,但是有一点必须说明的,在写网络编程方面的,必须注意异常的捕获,网络异常是比较正常的现象,比如说当前网络繁忙,网络连接 超时,更是“家常便饭”。因此在写网络编程的时候,必须养成捕获异常的好习惯,查看完函数说明后,必须要注意网络异常的说明。例如下图中的说明: 

  public static InetAddress   getByAddress  (byte[] ipAddress) 

Since: API Level 1 

Returns the InetAddress corresponding to the array of bytes. In the case of an IPv4 address there must be exactly 4 bytes and for IPv6 exactly 16 bytes. If not, an UnknownHostException is thrown. 

The IP address is not validated by a name service. 

The high order byte is ipAddress[0]. 

Parameters 

ipAddress is either a 4 (IPv4) or 16 (IPv6) byte long array. 

Returns 

    * an InetAddress instance representing the given IP address ipAddress. 

Throws 

UnknownHostException if the given byte array has no valid length. 

在使用getByAddress ()函数的时候就必须捕获UnknownHostException这个异常。 

然后,URL地址 


 

看到这个类,不仅让我想起来MFC在网络编程方面的复杂,一个 

BOOL AFXAPI AfxParseURL(LPCTSTR pstrURL, DWORD& dwServiceType,CString& strServer, CString& strObject, INTERNET_PORT& nPort); 

函数,让人看起来就感觉不知道在说明,在编写MFC网络编程方面的时候一般都会自己写个URL类,而在JAVA中的直接提供了这个类,让初学者看起 来明白多了。一个简单的例子如下: 

Java代码 

  




Void EasyURL (String strURL)   
{   
URL url = new URL(strURL);   
try  
{   
InputStream html = url.openStream ();   
int c;   
do{   
c= html.read();   
cf(c!=-1) System.out.println((char)c);
  
}while(c!=-1)   
}   
catch(IOException e)   
{   
System.out.println(e.getMessage());   
}   
}  

其次,套接字socket类 


 

套接字通信的基本思想比较简单,客户端建立一个到服务器的链接,一旦连接建立了,客户端就可以往套接字里写入数据,并向服务器发送数据;反过来,服 务器读取客户端写入套接字里的数据。几乎就那样简单,也许细节会复杂些,但是基本思想就这么简单。举个简单的例子如下: 

Java代码 

  




void WebPing (String strURL)   
{   
try  
{   
InetAddress addr;   
Socket sock = new Socket(strURL,80);
  
Addr = sock.getInetAddress ();   
System.out.println(“Connceted to”+addr);   
Sock.close();   
}   
catch(IOException e)   
{   
System.out.println(e.getMessage());   
}   
}  

如果使用本地主机(localhost)来测试这个程序,输出结果如下: 

Connceted to localhost/127.0.0.1 

InetAddress.toString()的隐含调用(println调用)自动输出主机名和IP地址。 

至于其他套接字:DatagramSocket (通过UDP通信的套接字),MulticastSocket (一 种用于多点传送的套接字)以及ServerSocket (一种用于监听来自客户端的连接的套接字),在这里就不一一说 明。 

最后,URLConncetion类 

在一般情况下,URL这个类就可以满足我们的需求,但是在一些特殊情况下,比如HTTP数据头的传递,这个时候我们就得使用 URLConncetion,如下图所示: 


 

使用URLConncetion,我们对网络的控制就增加了很多,举个例子如下: 

Java代码 

  




void SendRequest (String strURL)   
{   
URL url = URL(strURL);   
HttpURLConnection conn = (HttpURLConnection)url.openConnection ();   
conn.setDoInput (true);   
conn.setDoOutput (true);   
conn.setRequestProperty (“Content-type”,”application/xxx”);   
conn.connect ();   
System.out.println(Conn.getResponseMessage ());   
InputMessage is = Conn.getIputStream();   
int c;   
do{   
c = is.read();   
if(c!=-1) System.out.println((char)c);
  
}while(c!=-1)   
}  

关于HTTP数据头方面的知识,前段时间在编写流媒体下载的时候学习了下HTTP数据头的结构,下面列举一个HTTP request/response的一个完整流程如下,有兴趣的可以看下: 


  
https://my.oschina.net/javagg/blog/16240
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐