Java登陆第十三天——网络编程(三)DatagramSocket

发布时间 2023-11-24 18:43:29作者: ocraft

DatagramSocket

使用DatagramSocket(数据套接字)可以进行UDP程序的开发,此类可以建立单向地、不可靠地、快速地通信。

在UDP编程中,混淆了服务端和客户端的概念。因为通信是单向的,所以身份可以随时切换。

(也有人把TCP称作服务端客户端,UDP称作发送端和接收端)

DatagramSocket类常用方法如下:

方法 类型 描述
public DatagramSocket(int port) throws SocketException 构造方法 监听指定端口
public void send(DatagramPacket p) throws IOException 普通方法 发送数据报
public synchronized void receive(DatagramPacket p) throws IOException 同步方法 等待客户端请求并接收数据报(没有会一直阻塞)

image

DatagramPacket

在Java中,使用DatagramPacket类操作数据报。

常用方法如下:

方法 类型 描述
public DatagramPacket(byte buf[], int length) 构造方法 构建数据报的数据、数据长度
public DatagramPacket(byte buf[], int length, InetAddress address, int port) 构造方法 构建数据报的数据、数据长度、目标地址和端口
public synchronized byte[] getData() 同步方法 拆开数据报,获取数据
public synchronized int getLength() 普通方法 获取数据长度

栗子:编写一个本机的接收端,端口为9999

接收端,Test25receive类:

//接收端,Test25receive类
    public static void main(String[] args) {
        try {
            DatagramSocket datagramSocket = new DatagramSocket(9999);
            byte[] bytes = new byte[1024];//创建容器,留作数据
            System.out.println("成功创建容器,监听9999端口");
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);
            //若无客户端访问9999端口,程序就会阻塞在此;若有客户端访问9999端口,程序继续向下执行。

            System.out.println("1");//若执行到此证明不会阻塞
            datagramSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

程序运行结果:

成功创建容器,监听9999端口
//阻塞中....

栗子:发送端给本机9999端口的接收端发送hello,world!

发送端,Test25send类:

//发送端,Test25send类
public class Test25send {
    public static void main(String[] args) {
        try {
            DatagramSocket datagramSocket = new DatagramSocket();//因为接收端不打算回消息,所以不监听端口
            byte[] bytes = "hello,world!".getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9999);
            //构建一个数据报,其目的地址是本机的9999端口。
            datagramSocket.send(datagramPacket);
            System.out.println("成功发送数据报");

            datagramSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

接收端,Test25receive类:

//接收端,Test25receive类
public class Test25receive {
    public static void main(String[] args) {
        try {
            DatagramSocket datagramSocket = new DatagramSocket(9999);
            byte[] bytes = new byte[1024];//创建容器,留作数据
            System.out.println("成功创建容器,监听9999端口");
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);
            //若无发送端访问9999端口,程序就会阻塞在此;若有发送端访问9999端口,程序继续向下执行。
            byte[] data = datagramPacket.getData();//拆包后的数据
            System.out.println(new String(data,0, datagramPacket.length));//长度一定是数据报获取的长度,否则带有bytes后的很多00000

            System.out.println("1");//若执行到此证明不会阻塞
            datagramSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

先运行接收端,再运行发送端,程序运行结果:
image

栗子:发送端发送信息"四大名著是哪些?"
接收端接收问题后回复""四大名著有。。。。
否则回复what?

客户端,Test25send类:

//客户端,Test25send类
public class Test25send {
    public static void main(String[] args) {
        try {
            DatagramSocket datagramSocket = new DatagramSocket(9988);//因为接收端要回消息,监听端口9988
            byte[] bytes = "四大名著11哪些?".getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9999);
            //构建数据报,其目的地址是本机的9999端口。
            datagramSocket.send(datagramPacket);
            System.out.println("成功发送数据报");

            //构建数据报,其目的地址是本机的9999端口。
            byte[] b = new byte[1024];
            DatagramPacket datagramPacket2 = new DatagramPacket(b, b.length, InetAddress.getByName("localhost"),9999);
            datagramSocket.receive(datagramPacket2);
            System.out.println(new String(datagramPacket2.getData(),0, datagramPacket2.getLength()));
            datagramSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端,Test25receive类:

//服务端,Test25receive类
public class Test25receive {
    public static void main(String[] args) {
        try {
            DatagramSocket datagramSocket = new DatagramSocket(9999);
            byte[] bytes = new byte[1024];//创建容器,留作数据
            System.out.println("成功创建容器,监听9999端口");
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);
            //若无客户端访问9999端口,程序就会阻塞在此;若有客户端访问9999端口,程序继续向下执行。
            String s = new String(datagramPacket.getData(), 0, datagramPacket.getLength());//拆包后的数据

            DatagramPacket datagramPacket2;
            byte[] b;
            if("四大名著是哪些?".equals(s)) {
                b = "四大名著有。。。。".getBytes();
            } else {
                b = "what?".getBytes();
            }
            datagramPacket2 = new DatagramPacket(b, b.length, InetAddress.getByName("localhost"), 9988);
            datagramSocket.send(datagramPacket2);


            datagramSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

程序运行结果:
image