zoukankan      html  css  js  c++  java
  • 基于UDP协议的网络编程

    UDP协议是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket,但这两个Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据报的对象。

    Java使用DatagramSocket代表基于UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报。Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送数据都是通过DatagramPacket对象完成的。

    DatagramSocket有4个构造器:

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

    2.DatagramSocket(int port):创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、指定端口

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

    4.DatagramSocket(SocketAddress bindaddr):创建一个DatagramSocket实例,并绑定一个SocketAddress实例

    使用DatagramSocket对象的send(DatagramPacket p)方法来发送数据,使用DatagramSocket对象的receive(DatagramPacket p)方法来接收数据,如果没有接受到数据,则会一直阻塞线程,直接接受到数据。

    DatagramPacket构造器分为两类:

    参数列表有InetAddress实例或者SocketAddress实例的,常用的是DatagramPacket(byte buf[], int length, InetAddress address, int port)。这类构造器指定目的IP和目的端口,创建出的DatagramPacket实例用来包装待发送的数据,并当做参数传到DatagramSocket实例的send方法中。

    参数列表没有InetAddress实例和SocketAddress实例的,常用的是DatagramPacket(byte buf[], int length)。用这类构造器创建出来的DatagramPacket实例用来接收数据,被当做参数传到DatagramSocket实例的receive方法中。

    发送方代码示例:

    public class UDPSend {
        public static void main(String args[]) {
            try {
                // 创建DatagramSocket实例
                DatagramSocket socket = new DatagramSocket(9999);
                String text = "hello world";
                byte[] bytes = text.getBytes();
                // 发送方的数据报实例包装待发送的数据,并指定目的IP和目的端口
                DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 10000);
                // 发送数据报
                socket.send(packet);
                // 关闭socket资源
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    发送方代码中涉及到了两个端口,一个是本身发送数据的端口,另一个是指定了向目标主机目标端口发送数据。

    接收方代码示例:

    public class UDPReceive {
        public static void main(String[] args) {
            try {
                // 创建DatagramSocket实例,指定用来接收数据的端口是10000
                DatagramSocket socket = new DatagramSocket(10000);
                // 创建一个空的字节数组,字节数组的长度决定了
                byte[] buf = new byte[1024];
                // 创建接收方数据报实例时传入一个空的字节数组,该数据的长度决定了数据报实例最多能接受多少数据
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                // 接收数据
                socket.receive(packet);
                // 把字节数据封装成字符串。packet.getLength()返回接收数据的实际长度
                String msg = new String(packet.getData(), 0, packet.getLength());
                System.out.println(msg);
                // 关闭socket资源
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    接收方中的DatagramSocket对象的receive(DatagramPacket p)方法会阻塞线程,等待数据的来临,一旦接收到数据,线程结束。

    以上,不管先运行发送方还是先运行接收方都不会报错。其实UDP传输就好像对讲机一样,没有打开接收,除了别人说的话听不到以外,不会有任何异常,那边说话的人该说说,只是信息丢了。只有打开了接收,才能听得到别人说话。类似的,如果先运行发送方的话,发送方朝目的主机、目的端口发送了一条消息后结束,但是由于目的主机没有在指定端口接收数据的程序,所以消息丢了。如果这时候再运行接收方代码,则会阻塞,直到在指定端口接收到了数据,也就是说又有数据被发送到了指定端口上。

    DatagramPacket对象还有几个额外的方法比较实用:

    1.InetAddress getAddress():发送方的DatagramPacket对象调用时,该方法返回数据报的目的IP;接收方的DatagramPacket对象调用时,该方法返回发送方的IP地址

    2.getPort():发送方的调用时,返回目的端口;接收方调用时,返回发送方的端口

  • 相关阅读:
    ObjectiveC分类
    显示时间格式
    js模拟签名
    安装卸载homebrew
    NSFastEnumeration
    拼接音频
    在Orchard模块中访问模块本地的AppSettings
    重装证书
    msysgit中文问题
    Apple Push Notification service
  • 原文地址:https://www.cnblogs.com/koushr/p/5873448.html
Copyright © 2011-2022 走看看