android的学习:UDP编程

一、代入

UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的

二、UDP协议的特点

  • 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
  • UDP传输数据时是有大小的限制的,每个被传输的数据报必须限定在64KB之内。
  • UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
  • 日常应用:远程连接、文件传输、视频会议等

三、DatagramSocket

DatagramSocket本身只是码头,不维护状态,不能产生IO流,其唯一的功能是接收和发送数据报。Java语言使用DatagramPacket代表数据报,DatagramSocket的接收和发送数据功能都是通过DatagramPacket对象实现的。
在DatagramSocket中有3个构造器:

  • DatagramSocket() : 负责创建一个DatagramSocket实例,并将对象绑定到本机默认IP地址,本机所有可用端口中随机选择的某个端口

  • DatagramSocket( int port ) : 负责创建一个DatagramSocket实例,并将对象绑定到本机默认IP地址、指定端口号。

  • DatagramSocket( int port, InetAddress laddr ) : 负责创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。

    在java程序中,通过上述任意一个构造器即可创建一个DatagramSocket实例。在创建服务器时必须创建指定端口的DatagramSocket实例,目的是保证其他客户端可以将数据发送到该服务器。一旦得到了DatagramSocket实例,可以通过下面两个方法接收和发送数据报:

  • Receive( DatagramPacket p ) : 从该DatagramSocket中接收数据报。

  • Send( DatagramPacket p ) ; 以该DatagramSocket对象向外发送数据报。

    在使用DatagramPacket发送数据报时,DatagramSocket并不知道将该数据报发送到哪里,而是由DatagramPacket自身决定数据数据报的目的。就像码头并不知道每个集装箱的目的地,码头只是将这些集装箱发送出去,而集装箱本身包含了该集装箱的目的地。

    当Client/Server程序中使用UDP协议,实际上并没有明显的服务器和客户端,因为两方都需要先建立一个DatagramSocket对象,用来接收或发送数据报,然后使用DatagramPacket对象作为传输数据的载体。通常固定IP、固定端口的DatagramSocket对象所在的程序被成为服务器,因为该DatagramSocket可以主动接收客户端数据。

四、DatagramPacket

DatagramPacket :用于处理宝文,将byte数组、目标地址、目标端口等数据包装成报文将报文拆卸成byte数组。

  • DatagramPacket( byte [ ] buf , int length ) : 以一个空数组来创建DatagramPacket对象,该对象的作用是接收DatagramSocket中的数据。

  • DatagramPacket( byte [ ] buf , int length ,InetAddress addr ,int port ) : 以一个包含数据的数组来创建DatagramPacket对象,创建该DatagramPacktet时还指定了一个IP地址和端口。这就决定看该数据报的目的。

  • DatagramPacket( byte [ ] buf , int offet , int length ): 以一个空数组来创建DatagramPacket对象,并指定接收到的数据放入buf数组中从offet开始,最多放length个字节。

  • DatagramPacket( byte [ ] buf ,int offet , int length , InetAddress adrress ,int port): 创建一个用于发送的DatagramPacket对象,也多指定了一个offset参数。

    在接收数据前,应该采用上面的第一个或第三个构造器生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用DatagramSocket中的receive()方法等待数据报的到来,此方法将一直等待(也就是说会阻塞调用该方法的线程),直到收到一个数据报为止。例如下面的代码 :

    //创建接收数据的DatagramPacket对象
    DatagranPacket packet = new DatagramPacket( buf ,256);
    //接收数据
    socket.receive( packet );
    

    在发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的方法send()实现的,方法send()根据数据报的目的地址来寻径以传递数据报。例如下面的代码 :

    //创建一个发送数据的DatagramPacket对象
    DatagramPacket packet = new DatagramPacket( buf , length,address , port );
    //发送数据报
    socket.send(packer);
    

    接着DatagramPacket为我们提供了方法getData() , 此方法可以返回DatagramPacket对象中封装的字节数组。
    当服务器(也可以客户端)接收到一个DatagramPacket对象后,如果想向该数据报的发送者“反馈”一些信息,但由于UDP是面向非连接的,所以接受者并不知道每个数据报由谁发送过来,但程序可以调用DatagramPacket的如下3个方法来获取发送者的IP和端口信息。

  • InetAddress getAddress() : 返回某台机器的IP地址,当程序准备发送此数据时,该方法返回数据报的发送主机的IP地址。

  • int getPort( ) : 返回某台机器的端口,当程序准备发送此数据报时,该方法返回此数据报的目标机器的端口,该方法返回数据报是源SocketAddress.

  • SocketAddress getSocketAddress( ) : 返回完整SocketAddress,通常由IP地址和端口号组成。当程序准备发送此数据报时,该方法返回此数据报的目标SocketAddress;当程序刚刚接收到一个数据报时,该方法返回该数据报是源SocketAddress.

    上述SocketAddress方法的返回值是一个SocketAddress对象,该对象实际上就是一个IP地址和一个端口号,也就是说SocketAddress对象封装了一个InetAddress对象和一个代表端口的整数,所以使用SocketAddress对象可以同时代表IP地址和端口。

五、实例

UDPServer.java 服务器端

public class UDPServer {
    public static void main(String []args){
        try {
            //1、创建服务器端,指定端口号
            DatagramSocket socket = new DatagramSocket(9809);
            //2、创建一个数据报,用来接收客户端发送的数据
            byte[] data = new byte[1024];
            DatagramPacket packet = new DatagramPacket(data,data.length);
            System.out.println("***我是服务器端,等待客户端的请求***");
            socket.receive(packet);//此时服务器处于阻塞状态,等待客户端的请求

            //3、读取数据
            String info = new String(data,0,packet.getLength());
            System.out.println("我是服务器端,客户端说"+info);
 			//向客户端发送数据
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            byte[] data2 = "欢迎您!".getBytes();
            //2、创建数据报,包含响应的数据信息
            DatagramPacket packet1 = new DatagramPacket(data2,data2.length,address,port);
            socket.send(packet1);
            socket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

UDPClient.java 客户端

public class UDPClient {
    public static void main(String [] args){
        try {
            //1、定义服务器端的地址、端口号、数据
            InetAddress address = InetAddress.getByName("localhost");
            int port = 9809;
            byte[] data = "用户名:***;密码:12345".getBytes();//将字符型常量转换成字节型数组
            //2、创建要发送的数据报
            DatagramPacket packet = new DatagramPacket(data,data.length,address,port);
            //3、向服务器发送数据
            DatagramSocket socket = new DatagramSocket();
            socket.send(packet);
            //接收服务器的数据
            byte[] data1 = new byte[1024];
            DatagramPacket packet1 = new DatagramPacket(data1,data1.length);
            socket.receive(packet1);
            String reply = new String(data1,0,packet1.getLength());
            System.out.println("我是客户端,服务器端说:"+reply);
        } catch (UnknownHostException | SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果
在这里插入图片描述
在这里插入图片描述

参考书籍

《精通Android网络开发》—王东华*编著

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值