网络编程(二)——UDP通信

                                              UDP通信

一、DatagramPacket

       前面介绍了UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。UDP通信的过程就像是货运公司在两个码头间发送货物一样。在码头发送和接收货物时都需要使用集装箱来装载货物,UDP通信也是一样,发送和接收的数据也需要使用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。

1 、构造方法       

       想要创建一个DatagramPacket对象,首先需要了解一下它的构造方法。在创建发送端和接收端的DatagramPacket对象时,使用的构造方法有所不同,接收端的构造方法只需要接收一个字节数组来存放接收到的数据,而发送端的构造方法不但要接收存放了发送数据的字节数组,还需要指定发送端IP地址和端口号。

1) 接收端构造

public DatagramPacket(byte buf[], int length)
           // 构造数据包,用来接收长度为length的数据包

该构造方法在创建DatagramPacket对象时,指定了封装数据的字节数组和数据的大小,没有指定IP地址和端口号。很明显,这样的对象只能用于接收端,不能用于发送端。因为发送端一定要明确指出数据的目的地(ip地址和端口号),而接收端不需要明确知道数据的来源,只需要接收到数据即可。

2) 发送端构造

public DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port)
           // 构造数据包,用来将长度为length的数据包发送到指定主机的指定端口号

该构造方法,不仅指定了封装数据的字节数组和数据的大小,还指定了数据包的目标IP地址(addr)和端口号(port)。通常用于发送端,因为在发送数据时必须指定接收端的IP地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址一样。

2、常用方法

1) 地址

  • getAddress() InetAddress       返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
  • getPort()  int             返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
  • getSocketAddress() SocketAddress    获取要将此包发送到的或发出此数据报的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。
  • setAddress(InetAddress iaddr) void    设置要将此数据报发往的那台机器的 IP 地址。
  • setPort(int iport)  void           设置要将此数据报发往的远程主机上的端口号。
  • setSocketAddress(SocketAddress address)  void   设置要将此数据报发往的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。

2)数据

  •  
  • getData()  byte[]                                                  返回数据缓冲区。
  • getLength()  int                                                   返回将要发送或接收到的数据的长度。
  • getOffset()  int                                                     返回将要发送或接收到的数据的偏移量。
  • setAddress(InetAddress iaddr) void                        设置要将此数据报发往的那台机器的 IP 地址。
  • setData(byte[] buf)  void                                       为此包设置数据缓冲区。
  • setData(byte[] buf, int offset, int length)  void          为此包设置数据缓冲区。
  • setLength(int length)   void                                     为此包设置长度。

二、DatagramSocket

       DatagramPacket数据包的作用就如同是“集装箱”,可以将发送端或者接收端的数据封装起来。然而运输货物只有“集装箱”是不够的,还需要有码头。在程序中需要实现通信只有DatagramPacket数据包也同样不行,为此JDK中提供的一个DatagramSocket类。DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包,发送数据的过程如下图所示。

                                                             

1 、构造方法       

1) 接收端构造

DatagramSocket(int port)            创建数据报套接字并将其绑定到本地主机上的指定端口。

DatagramSocket(int port, InetAddress laddr)  创建数据报套接字,将其绑定到指定的本地地址。

DatagramSocket(SocketAddress bindaddr)    创建数据报套接字,将其绑定到指定的本地套接字地址。

该构造方法既可用于创建接收端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口。

2) 发送端构造

DatagramSocket()                  构造数据报套接字并将其绑定到本地主机上任何可用的端口。

该构造方法用于创建发送端的DatagramSocket对象,在创建DatagramSocket对象时,并没有指定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。

 

2 、方法       

(1)绑定地址

  • bind(SocketAddress addr)  void            将此 DatagramSocket 绑定到特定的地址和端口。
  • connect(InetAddress address, int port) void   将套接字连接到此套接字的远程地址。
  • connect(SocketAddress addr)  void      将此套接字连接到远程套接字地址(IP 地址 + 端口号)。
  • disconnect()  void              断开套接字的连接。
  • isBound()  boolean                     返回套接字的绑定状态。 
  • isConnected()  boolean              返回套接字的连接状态。

(2)获取IP地址

  • getInetAddress()   InetAddress          返回套接字连接的地址。 
  • getLocalAddress()   InetAddress        获取套接字绑定的本地地址。
  • getPort()            int                                  返回此套接字连接到的远程端口。
  • getLocalPort()      int                                     返回此套接字绑定到的本地端口。
  • getLocalSocketAddress()  SocketAddress          返回此套接字绑定的端点的地址,如果尚未绑定则返回 null。 
  • getRemoteSocketAddress()   SocketAddress     返回此套接字连接的端点的地址,如果未连接则返回 null。

(3)设置缓冲区

  • setReceiveBufferSize(int size) void            将此 Socket 的 SO_RCVBUF 选项设置为指定的值。 
  • setSendBufferSize(int size) void         将此 Socket 的 SO_SNDBUF 选项设置为指定的值。

(4)重用端口

  • setReuseAddress(boolean on) void      启用/禁用 SO_REUSEADDR 套接字选项。 
  • getReuseAddress()   boolean               测试是否启用 SO_REUSEADDR。

(5)发送接收数据

  • receive(DatagramPacket p)   void       从此套接字接收数据报包。
  • send(DatagramPacket p)    void    从此套接字发送数据报包。 
  • getChannel()  DatagramChannel       返回与此数据报套接字关联的唯一 DatagramChannel 对象(如果有)。

(6)关闭

  • close()  void                    关闭此套接字。
  • isClosed()  boolean       返回套接字的关闭状态。

三、UDP网络程序案例

UDP发送端与接收端交互图解

要实现UDP通信需要创建一个发送端程序和一个接收端程序,很明显,在通信时只有接收端程序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。

接收端程序

package com.sxb.socket.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @Description UDP协议 服务端
 *          1,创建DatagramSocket对象
 *          2,创建DatagramPacket对象
 *          3,接收数据存储到DatagramPacket对象中
 *          4,获取DatagramPacket对象的内容
 *          5,释放流资源
 *
 * @Author ShiXinbing
 * @Date 2018/7/26 0026 09:39
 * @Version 1.0
 **/
public class UDPReceive {
    public static void main(String[] args) throws IOException{

        // 1,创建DatagramSocket对象,并指定端口号
        DatagramSocket socket = new DatagramSocket(55535);

        // 2,创建DatagramPacket对象, 创建一个空的仓库
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, 1024);

        // 3,接收数据存储到DatagramPacket对象中
        socket.receive(packet);

        // 4,获取DatagramPacket对象的内容
        // 谁发来的数据  getAddress()
        InetAddress inetAddress = packet.getAddress();
        // 获取到了IP地址
        String ip = inetAddress.getHostAddress();
        // 发来了什么数据  getData()
        byte[] data = packet.getData();
        // 发来了多少数据 getLenth()
        int length = packet.getLength();

        //显示收到的数据
        String dataStr = new String(data, 0, length);
        System.out.println("IP地址:"+ip+ "  数据是: "+ dataStr);

        // 5,释放流资源
        socket.close();
    }
}

发送端程序

package com.sxb.socket.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @Description UDP协议  发送端(客户端)
 *      1, 创建DatagramSocket对象
 *      2, 创建DatagramPacket对象,并封装数据
 *      3, 发送数据
 *      4, 释放流资源
 * @Author ShiXinbing
 * @Date 2018/7/26 0026 09:38
 * @Version 1.0
 **/
public class UDPSend {
    public static void main(String[] args) throws IOException {
        // 1, 创建DatagramSocket对象
        DatagramSocket socket = new DatagramSocket();

        // 2, 创建DatagramPacket对象,并封装数据
        // 1) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
        byte[] bytes = "你好 upd-socket !!".getBytes("UTF-8");
        // 2) public DatagramPacket(byte[] buf, int length, InetAddress address,  int port)
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 55535);

        // 3, 发送数据
        // public void send(DatagramPacket p) 从此套接字发送数据报包
        socket.send(packet);

        // 4, 释放流资源
        socket.close();
    }
}

猜你喜欢

转载自blog.csdn.net/shixinbing/article/details/81214140