Android网络通信之Socket通信

联网就需要在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可以主动接收客户端数据。

转载于:https://www.cnblogs.com/Magina-learning/p/7941563.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值