联网就需要在AndroidManifest.xml文件中添加访问网络的权限,代码如下
<uses-permission android: name="android.permission.INTERNET" />
Android与服务器的通信方式主要有两种,一是HTTP通信,一个Socket通信。两者的最大差异在于,HTTP连接使用的是“请求——响应方式”,即在请求时建立连接通道,当客户端想服务器发送请求后,服务器端才能想客户端返回数据。而Socket通信则是在双发建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端向服务器发送请求。
Socket有两种传输模式:面向连接和无连接。面向连接模式使用TCP协议,在通信两端建立通信链路,一次发送和接收数据。无连接模式使用UDP协议,将数据进行打包发送,与面向连接模式不同的是,接收端接收数据包的顺序和发送端发送的顺序是不一样的,而且数据安全性欠佳。如果希望确保数据能按预期有序地、正确地发送,那么建议采用面向连接模式,但相对来说,内存消耗要比无连接模式大;如果要实现快速、高效的传输数据,那么可以采用无连接模式。
使用基于TCP协议的Socket通信:
当Java建立了两个Socket对象是,分别代表链路两端实体的通信接口,通过Socket产生I/O流进行网络通信,此时这两个通信实体并没有服务器端和客户端的区分。在虚拟链路尚未建立起来之前,需要有一个通信实体先做出“主动”姿态,主动接收来自其他通信实体的连接请求。Java提供了ServerSocket类,用于监听来自客户端的Socket连接,如果没有连接请求,则一直处于等待状态。
基于TCP的Socket通信步骤如下。
1.创建TCP服务器端
利用ServerSocket创建TCP服务器端,创建ServerSocket对象可通过以下构造器。
ServerSocket(int port): 指定端口号(port)来创建ServerSocket对象。
ServerSocket(int port, int backlog):在上一个构造器的基础上增加了改变连接队列的参数backlog。
ServerSocket(int port,int backlog,InetAddress localAddr):在上一个构造器的基础上增加了IP地址参数localAddr,用来指定将ServerSocket绑定到指定的IP地址
2.等待客户端的请求
一个服务器应该可以接收多个客户端请求,即循环调用accept()方法不断接收客户端请求,代码如下:
ServerSocket server=new ServerSocket(50000); while(true){ Socket socket= server.accept() }
3.服务器端接收请求,返回响应
accept()方法在没有数据进行接收时处于堵塞状态。一旦接收到数据,就可以通过InputStream读取接收的数据,通过OutputStream返回响应数据。
4.客户端发送请求,获取返回信息
服务器端通过创建ServerSocket对象来等待客户端请求,而客户端创建一个指定服务器IP地址和端口号的Socket对象,通过InputStream读取数据、OutputStream写入数据,即可实现使用TCP协议进行Socket数据传输。
客户端:
// 步骤1:创建客户端 & 服务器的连接 // 创建Socket对象 & 指定服务端的IP及端口号 Socket socket = new Socket("192.168.1.32", 1989); // 判断客户端和服务器是否连接成功 socket.isConnected()); // 步骤2:客户端 & 服务器 通信 // 通信包括:客户端 接收服务器的数据 & 发送数据 到 服务器 <-- 操作1:接收服务器的数据 --> // 步骤1:创建输入流对象InputStream InputStream is = socket.getInputStream() // 步骤2:创建输入流读取器对象 并传入输入流对象 // 该对象作用:获取服务器返回的数据 InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); // 步骤3:通过输入流读取器对象 接收服务器发送过来的数据 br.readLine(); <-- 操作2:发送数据 到 服务器 --> // 步骤1:从Socket 获得输出流对象OutputStream // 该对象作用:发送数据 OutputStream outputStream = socket.getOutputStream(); // 步骤2:写入需要发送的数据到输出流对象中 outputStream.write(("Carson_Ho"+"\n").getBytes("utf-8")); // 特别注意:数据的结尾加上换行符才可让服务器端的readline()停止阻塞 // 步骤3:发送数据到服务端 outputStream.flush(); // 步骤3:断开客户端 & 服务器 连接 os.close(); // 断开 客户端发送到服务器 的连接,即关闭输出流对象OutputStream br.close(); // 断开 服务器发送到客户端 的连接,即关闭输入流读取器对象BufferedReader socket.close(); // 最终关闭整个Socket连接
服务器端:
ServerSocket serverSocket= null; serverSocket=new ServerSocket(3509); while(true){ //最好加try Socket socket=serverSocket.accept(); OutputStream output=socket.getOutputStream(); output.write(str.getBytes("UTF-8")); //str就是要发送的信息。 output.flush();
socket.close();
}
//获得客户端发来的数据 try { BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); while(true){ System.out.println("Receive from client : " + reader.readLine()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
书上的一个返回响应的信息的例子:
Socket socket=serverSocket.accept(); File file=new File("2://a.txt"); BUfferedReader read =new BufferedReader(new FileReader(file)); String inputline=nell; inputline=read.readLine(); OutputStream out =socket.getOutputStream(); PrintWriter print=new PrintWriter(out); print.print(inputline); print.flush(); print.close(); out.close(); read.close(); socket.close();
使用基于UDP的Socket通信:
UDP存在未提供数据包分组、组装和无法对数据包排序的缺点,也就是说,UDP缺乏可靠性。由于UDP在传输数据包前不用在客户端和服务器之间建立一个连接,且没有超时重发等机制,因此传输速度很快,因此UDP通常适用于哪些需要在计算机之间传输数据的网络应用。
Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据包。Java使用DatagramPacket来代表数据包,DatagramSocket接收和发送的数据都是通过DatagramSocket对象完成的。
使用DatagramSocket创建UDP服务器端步骤如下。
1.创建DatagramSocket对象
创建DatagramSocket对象可通过如下构造器。
DatagramSocket():创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、从本机所有可用端口中随机选择的某个端口
DatagramSocket(int port):创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、指定端口。
DatagramSocket(int port,InetAddress laddr):创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。
2.创建DatagramPacket对象
DatagramPacket是数据包的载体,该对象的实例化需要两个参数,用于描述接收的数据包及其长度,代码如下。
byte data[] =new byte[1024]; DatagramPacket packet = new DatagramPacket(data, data.length);
3.接收数据
使用DatagramSocket的receive方法可以接收客户端发送的数据,receive()与serversocket的accept()类似,在没有数据进行接收时处于堵塞状态。接收到的数据封装在DatagramPacket中,通过调用相应的方法可以将数据读取出来,getData()方法用来获取数据缓冲区,getOffset()方法用来获取数据起始位置,getLength()方法用来获取数据长度,代码如下。
DatagramSocket socket=new DatagramSocket(10000); byte data[]=new byte[4*1024]; DatagramPacket packet= new DatagramPacket(data,data.length); socket.receive(packet); String result= new String(packet.getData(),packet.getOffset(),packet.getLength());
使用DatagramSocket创建UDP客户端的步骤如下。
1.客户端需要创建指定监听端口的DatagramSocket对象
创建方式与服务器端创建DatagramSocket对象相同,需要指定端口号,代码如下。
DatagramSocket socket= new DatagramSocket(10000);
2.创建InetAddress对象
创建InetAddress对象,通过该对象的getByName()方法将IP地址字符转化为要发送请求的网络地址。代码如下
InetAddress serverAddress=InetAddress.getName("192.168.101");
3.创建DatagramPacket对象
首先定义一个字符串表示要发送的信息,并将其存储在字节数组中。然后创建一个DatagramPacket对象,与服务器端创建的DatagramPacket不同,发送数据时,创建DatagramPacket对象需要四个参数,分别是数据包、数据包长度、要发送的地址以及端口号。代码如下
DatagramSocket socket =new DatagramSocket(10000); InetAddress serverAddress = InetAddress.getByName("192.168.1.101"); String str="[send messge]"; byte data[]=str.getBytes(); DatagramPacket packet = new DatagramPacket(data,data.length,serverAddress,10000);
4.发送数据
调用DatagramSocket对象的send()方法以发送数据,代码如下
socket.send(packet);
网上摘的一段代码:
// 读取Socket中的数据,读到的数据放入inPacket封装的数组里 socket.receive(inPacket); // 判断inPacket.getData()和inBuff是否是同一个数组 System.out.println(inBuff == inPacket.getData()); // 将接收到的内容转换成字符串后输出 System.out.println(new String(inBuff , 0 , inPacket.getLength())); // 从字符串数组中取出一个元素作为发送数据 byte[] sendData = books[i % 4].getBytes(); // 以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的 // 源SocketAddress作为目标SocketAddress创建DatagramPacket outPacket = new DatagramPacket(sendData , sendData.length , inPacket.getSocketAddress()); // 发送数据 socket.send(outPacket);
当Client/Server程序使用UDP协议时,实际上并没有明显的服务器端和客户端,因为两方都需要先建立一个DatagramSocket对象,用来接收或发送数据报,然后使用DatagramPacket对象作为传输数据的载体。通常固定IP地址、固定端口的DatagramSocket对象所在的程序被称为服务器,因为该DatagramSocket可以主动接收客户端数据。