【Java 网络编程】UDP 服务器 与 客户端持续交互 案例

举报
韩曙亮 发表于 2022/01/11 01:39:45 2022/01/11
【摘要】 文章目录 I UDP 交互原理II UDP 服务器端代码示例III UDP 客户端代码示例IV 服务器 客户端 运行结果 I UDP 交互原理 1. UD...



I UDP 交互原理



1. UDP 单播传输流程 : A 给 B 发送数据包 , B 设备一定要处于监听 X 端口状态 , A 向 B 的 X 端口发送数据包 , B 才能收到 ; B 收到 A 的数据包后 , B 就知道了 A 的端口号 Z 的信息了 , 此时 B 可以向 A 的 Z 端口号发送数据包 ;

2. 局域网设备交互 : A 设备给局域网其它设备发送信息 , 并能接收到其它设备回送给 A 的信息 ;

3. 接收信息设备监听 X 端口 : 此时 A 作为客户端时 , 服务器需要接收 A 发送的数据包 , 服务器需要监听一个指定的接口 X , 那么如果 A 发送广播消息 , 监听 X 端口的服务器就会收到 A 发送的消息 ;

4. A 提前监听端口 Z : 如果服务器在收到消息后立刻向 A 的 Z 端口回送一个反馈信息 , 设备 A 需要在发送消息之前就监听 Z 端口 , 才能实现上述功能 ;

5. 持续交互 : A 不断向其它设备的 X 端口发送信息 , 其它设备可以不断反馈信息给设备 A 的 Z 端口 , 这样就实现了客户端与服务器端数据交互的功能 ;



II UDP 服务器端代码示例



import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;

public class UDPServer {

    public static void main(String[] args){

        System.out.println("服务器 开始运行");

        //开启接收数据的线程
        ReceiveThread receiveThread = new ReceiveThread();
        receiveThread.start();
    }



    /**
     * 服务器端监听客户端发送的信息
     */
    private static class ReceiveThread extends Thread{

        /**
         * 是否继续监听 , 循环控制变量
         */
        boolean isReceive = true;

        /**
         * 存储发送数据的客户端信息
         */
        ArrayList<Client> clients = new ArrayList<>();

        @Override
        public void run() {
            super.run();

            try {
                //I. 创建 DatagramSocket 对象 , 用于 UDP 数据包的发送和接收


                //1. UDP 数据包接收者 , 监听 8888 端口
                //      该 DatagramSocket 既可以接收数据包 , 也可以发送数据包
                DatagramSocket datagramSocket = new DatagramSocket(8888);


                //II. 接收 UDP 数据包 , 无限循环接收来自客户端的信息 , 并根据不同的信息进行不同处理


                while (isReceive){

                    //2. 接收数据包使用的缓冲区
                    byte[] receiveBuffer = new byte[256];
                    //3. 接收 UDP 数据包使用的 DatagramPacket 对象
                    DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);

                    //4. 接收 UDP 数据包
                    datagramSocket.receive(receivePacket);

                    //5. 获取发送端的 IP 地址
                    String sendIP = receivePacket.getAddress().getHostAddress();
                    //6. 获取发送端的端口号
                    int sendPort = receivePacket.getPort();
                    //7. 获取接收到的数据的长度
                    int receiveLen = receivePacket.getLength();
                    //8. 获取接收到的数据 , 并转为字符串
                    String receiveData = new String(receivePacket.getData(), 0, receiveLen);
                    //9. 打印接收到的数据包信息
                    System.out.println("服务器 接收到 " + sendIP + " : " + sendPort + " 发送的数据 : " + receiveData);

                    //将客户端信息发送到



                    //III. 发送 UDP 数据包


                    //10. 将接收到的数据长度回送给发送者
                    String response = "服务器端 收到客户端发送的 " + receiveLen + " Byte 数据";
                    //11. 将字符串转为 byte[] 数组
                    byte[] responseData = response.getBytes();
                    //12. 创建发送数据包 , 需要传入的参数 1> 数据 2> 数据长度 3> 接收者的地址 4> 接收者的端口号
                    DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length,
                            receivePacket.getAddress(), receivePacket.getPort());

                    //13. 将数据包发送出去
                    datagramSocket.send(responsePacket);

                    System.out.println("服务器 向客户端 " + sendIP + " : " + sendPort + " 发送的数据 : " + response);

                    //退出服务器循环
                    if("exit".equals(receiveData)){
                        isReceive = false;
                    }

                }


            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                System.out.println("服务器 运行结束");
            }
        }
    }

    /**
     * 封装向服务器端发送数据的客户端信息
     * 主要是保存客户端的 IP 地址和端口号
     */
    private static class Client{
        String ClientIP;
        String ClientPort;

        public Client(String clientIP, String clientPort) {
            ClientIP = clientIP;
            ClientPort = clientPort;
        }
    }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125


III UDP 客户端代码示例



import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UDPClient {

    public static void main(String[] args){

        try {
            System.out.println("客户端 开始运行");


            //I. 创建 DatagramSocket 对象 , 用于 UDP 数据包的发送和接收


            //1. UDP 数据包套接字 , 客户端 ,
            //      监听 8889 端口 , 发送和接收数据包都使用该端口
            DatagramSocket datagramSocket = new DatagramSocket(8889);


            //II. 人机交互控制台阻塞获取用户输入


            //1. 获取控制台输入流
            InputStream is = System.in;
            //2. 该输入流会阻塞 , 等待用户控制台输入
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            // 循环控制变量 , 循环发送和接收 UDP 数据包
            boolean flag = true;
            while(flag){

                //3. 阻塞命令行 , 等待用户输入一行数据, 并存入 string 对象中
                String string = br.readLine();


                //III. 向服务器发送 UDP 数据包


                //1. 将字符串转为 byte[] 数组
                byte[] sendData = string.getBytes();
                //2. 创建发送数据包 , 需要传入的参数 1> 数据 2> 数据长度 3> 接收者的地址 4> 接收者的端口号
                //      向服务器端发送数据 , 发送的端口是自动分配的
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
                        InetAddress.getLocalHost(), 8888);
                //3. 将数据包发送出去
                datagramSocket.send(sendPacket);

                System.out.println("客户端 向服务器 : " +
                        InetAddress.getLocalHost() + " : " + 8888 + " 发送的数据 : " + string);

                //4. 退出
                if("exit".equals(string)){
                    flag = false;
                }


                //IV. 接收服务器反馈的 UDP 数据包


                //1. 接收数据包使用的缓冲区
                byte[] receiveBuffer = new byte[1024];
                //2. 接收 UDP 数据包使用的 DatagramPacket 对象
                DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);

                //3. 接收 UDP 数据包
                datagramSocket.receive(receivePacket);

                //4. 获取发送端的 IP 地址
                String sendIP = receivePacket.getAddress().getHostAddress();
                //5. 获取发送端的端口号
                int sendPort = receivePacket.getPort();
                //6. 获取接收到的数据的长度
                int receiveLen = receivePacket.getLength();
                //7. 获取接收到的数据 , 并转为字符串
                String receiveData = new String(receivePacket.getData(), 0, receiveLen);
                //8. 打印接收到的数据包信息
                System.out.println("客户端 接收到服务器端反馈信息 : " +
                        sendIP + " : " + sendPort + " 发送的数据 : " + receiveData);

            }

        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("客户端 运行结束");
        }
    }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98


IV 服务器 客户端 运行结果



先运行服务器端 , 再运行客户端 ;

在这里插入图片描述

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/100175768

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。