Android网络通讯简介
网络通信应该包含三部分的内容:发送方、接收方、协议栈。发送方和接收方是参与通信的主体,协议栈是发送方和接收方进行通信的契约。按照服务类型,网络通信可分为面向连接和无连接的方式。面向连接是在通信前建立通信链路,而通信结束后释放该链路。无连接的方式则不需要在通信前建立通信连接,这种方式不保证传输的质量。
Android提供了多种网络通信的方式,如Java中提供的网络编程,在Android中都提供了支持。Android中常用的网络编程方式如下:
- 针对TCP/IP协议的Socket和ServerSocket;
- 针对HTTP协议的网络编程,如HttpURLConnection和HttpClient;
- 直接使用WebKit访问网络。
Socket通信
Socket通信是指双方采用Socket机制交换数据。Socket是比较低层的网络编程方式,其他的高级协议(如HTTP)都是建立在此基础之上的,而且Socket是跨平台的编程方式,可以在异构语言之间进行通信,所以掌握Socket网络编程是掌握其他网络编程方式的基础。
Socket和ServerSocket
Socket通常称为“套接字”,这个套接字用来描述通信链的句柄:IP地址和端口。通过套接字,应用程序之间可以传输信息。常见的网络协议有TCP和UDP两种,TCP协议是可靠的、面向连接的协议,这种方式需要在通信前建立通信双方的连接链路,而通信结束后又释放该链路。而UDP数据报协议是不可靠的、无连接的协议,这种协议不需要在通信前建立通信双方的连接。因而UDP牺牲可靠性来降低传输开销,其传输开销比TCP小。
java.net包中提供了一下两个Socket类。
- java.net.Socket是客户端的Socket对应的类;
- java.net.ServerSocket是服务器端的Socket对应的类,这个类表示一个等待客户端连接的服务器端套接字。
Socket类:
Socket类常用的方法如下表所示
方法 | 功能描述 |
Socket(String host,int port) | Socket提供7个构造函数。该构造函数带两个参数,用于创建一个到主机位host、端口号为port的套接字,并连接到远程主机 |
bind(SocketAdderss localAddr) | 将该Socket同参数localAddr指定的地址和端口绑定 |
InetAddress getInetAddress() | 获取该Socket连接的目标主机的IP地址 |
synchronized int getReceiveBufferSize() | 获取该Socket的接收缓冲区的尺寸 |
synchronized void close() | 关闭Socket |
InputStream getInputStream() | 获取该Socket的输入流,这个输入流用来读取数据 |
boolean isConnected() | 判断该Socket是否连接 |
boolean isOutputShutdown() | 判断该Socket的输出管道是否关闭 |
boolean isInputShutdown() | 判断该Socket的输入管道是否关闭 |
SocketAddress getLocalSocketAddress() | 获取此Socket的本地地址和端口 |
int getPort() | 获取端口号 |
一般情况下,Socket的工作步骤如下:
- 根据指定地址和端口号创建一个Socket对象
- 调用getInputStream()方法或getOutputStream()方法打开连接到Socket的输入/出流。
- 客户端与服务器根据一定的协议交互,知道关闭连接。
- 关闭客户端的Socket。
下面代码是一个Socket客户端
1 public class TCPClient{ 2 public static void main(String args[]){ 3 try{ 4 //创建一个Socket对象,指定服务器端的IP地址和端口号 5 Socket socket=new Socket("192.168.1.88",4700); 6 //使用InputStream读取硬盘上的文件 7 InputStream inputStream=new FileInputStream("f://file/words.txt"); 8 //从Socket当中得到OutputStream 9 OutputStream outputStream=socket.getOutputStream(); 10 byte buffer[]=new byte[4*1024]; 11 int temp=0; 12 //将InputStream当中的数据取出,并写入到OutputStream当中 13 while((temp=inputStream.read(buffer))!=-1){ 14 outputStream.write(buffer,0,temp); 15 } 16 outputStream.flush(); 17 }catch(Exception e){ 18 e.printStackTrace(); 19 } 20 } 21 } 22 /* UDP客户端 23 * public class UDPClient{ 24 public static void main(String args[]){ 25 try{ 26 //首先创建一个DatagramSocket对象 27 DatagramSocket socket=new DatagramSocket(4567); 28 //创建一个InetAddress 29 InetAddress serverAddress=InetAddress.getByName("192.168.1.88"); 30 String str="hello"; 31 byte data[]=str.getBytes(); 32 //创建一个DatagramPacket对象,并指定要将这个数据包发送到网络当中的哪个地址以及端口号 33 DatagramPacket packet=new DatagramPacket(data,data.length,serverAddress,4567); 34 //调用socket对象的send方法,发送数据 35 socket.send(packet); 36 }catch(Exception e){ 37 e.printStackTrace(); 38 } 39 } 40 }
ServerSocket类:
ServerSocket用于监听在特定端口的TCP连接、当客户端的Socket试图与服务器指定端口建立连接时,服务器被激活,判定客户程序的连接,一旦客户端与服务器建立了连接,则两者之间就可以相互传送数据、ServerSocket常用的方法如下表
方法 | 功能描述 |
ServerSocket(int Port) | ServerSocket构造函数 |
Socket accept() | 等待客户端的连接,当客户端请求连接时,返回一个Socket |
void close() | 关闭服务器Socket |
SocketAddress getLocalSocketAddress() | 获取此Socket的本地地址和端口 |
int getLocalPort() | 获取端口号 |
InetAddress getInetAddress() | 获取该Socket的IP地址 |
boolean isClosed() | 判断连接是否关闭 |
void setSo Timeout(int timeout) | 设置accept的超时时间 |
一般情况下,ServerSocket的工作步骤如下:
- 根据指定端口创建一个新的ServerSocket对象
- 调用ServerSocket的accept()方法,在指定的端口监听到来的连接。accept()一直处于阻塞状态,直到有客户端试图建立连接。这时accept()方法返回连接客户端与服务器的Socket对象。
- 调用getInputStream()方法或getOutputStream()方法建立与客户端交互的输入/输出流。
- 服务器与客户端根据一定的协议交互,直到关闭连接。
- 关闭服务器端的Socket。
- 回到第2步,继续监听下一次的连接。
下面代码片段是一个服务器端ServerSocket的线程。
1 new Thread() 2 { 3 public void run(){ 4 //声明一个ServerSocket对象 5 ServerSocket serverSocket=null; 6 try{ 7 //创建一个ServerSocket对象在端口4700监听客户请求 8 serverSocket=new ServerSocket(4700); 9 //调用ServerSocket的accept()方法,接收客户端所发来的请求 10 Socket socket=serverSocket.accept(); 11 //从Socket当中得到InputStream对象 12 InputStream inputStream=socket.getInputStream(); 13 byte[] buffer[]=new byte[1024*4]; 14 int temp=0; 15 //从InputStream当中读取客户端所发送的数据 16 while((temp=inputStream.read(buffer))!=-1){ 17 System.out.println(new String(buffer,0,temp)); 18 } 19 }catch(IOException e){ 20 e.printStackTrace(); 21 } 22 finally{ 23 try{ 24 serverSocket.close(); 25 }catch(IOException e){ 26 e.printStackTrace(); 27 } 28 } 29 } 30 } 31 /*使用UDP协议的服务端 32 *public void run(){ 33 try{ 34 //创建一个DatagramSocket对象,并指定监听的端口号 35 DatagramSocket socket=new DatagramSocket(4567); 36 byte data[]=new byte[1024]; 37 //创建一个空的DatagramPacket对象 38 DatagramSocket packet=new DatagramPacket(data,data.length); 39 //使用receive方法接收客户端所发送的数据 40 socket.receive(packet); 41 String result=new String(packet.getData(),packet.getOffset(),packet.getLength()); 42 System.out.println(result); 43 }catch(Exception e){ 44 e.printStackTrace(); 45 } 46 } 47 } 48 }*/