zoukankan      html  css  js  c++  java
  • Java模拟UDP通信

    Java基础:模拟UDP通信

    1、一次发送,一次接收

    1.1、发送方

    // 发送端,不需要连接服务器
    public class UdpClientDemo {
        public static void main(String[] args) throws Exception {
            // 1. 发送数据包需要一个Socket
            DatagramSocket socket = new DatagramSocket();
            // 1.2 建立一个包
            String msg = "你好";
            InetAddress localhost = InetAddress.getByName("localhost");
            System.out.println(localhost);
            int port = 8080;
    
            /*
    		通过UDP发送消息,需要通过 包 来发送,--> DatagramPacket(),该方法有多种重载形式,以下使用参数列表最多的那个
    		参数:
    		- 要发送的 消息 的字节数组 
    		- 从字节数组的哪个位置开始发送
    		- 发送的长度
    		- 对方的 IP地址
    		- 对方的端口号
             */
    
            DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
            // 2. 发送数据包
            socket.send(packet);
            socket.close();
        }
    }
    
    

    1.2、接收方

    // 接收端,接收端需要保证存在,否则接收不到,所以需要提前开启
    public class UdpServerDemo {
    
        public static void main(String[] args) throws Exception {
    
            // 1. 接收也需要一个Socket,并且要开启接收的端口
            DatagramSocket socket = new DatagramSocket(8080);
            // 需要一个字节数组来接收数据
            byte[] buffer = new byte[1024];
            // 1.2 封装数据包
            DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
            // 2. 接收数据,阻塞式接收:一直处于监听状态
            socket.receive(packet);
            // 关闭套接字
            socket.close();
            // 输出一下
            System.out.println(packet.getAddress().getHostAddress());
            // trim():为了去除多余的空格
            System.out.println(new String(packet.getData()).trim());
    
        }
    
    }
    
    

    2、多次发送,多次接收

    一方多次发送,一方多次接收,加上一个 while(true) {} 死循环,并规定在什么情况下退出即可。

    2.1、发送方

    public class ChatSenderDemo {
        public static void main(String[] args) throws Exception {
            // 使用Socket来接收
            DatagramSocket socket = new DatagramSocket();
            while (true) {
                // 准备发送包裹,从键盘接收数据
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                // 读取一行
                String data = reader.readLine();
                byte[] dataBytes = data.getBytes();
                DatagramPacket packet = new DatagramPacket(dataBytes, dataBytes.length, new InetSocketAddress("127.0.0.1", 6666));
                // 发送
                socket.send(packet);
                // 什么时候退出
                if ("bye".equals(data)) {
                    break;
                }
            }
            // 关闭
            socket.close();
        }
    }
    

    2.2、接收方

    public class ChatReceiveDemo {
    
        public static void main(String[] args) throws Exception {
            DatagramSocket socket = new DatagramSocket(6666);
            while (true) {
                // 准备接收数据包裹
                byte[] buffer = new byte[1024];
                // 用来接收数据
                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                // 接收包裹,阻塞时接收
                socket.receive(packet);
                // 接收到的数据
                String receiveData = new String(packet.getData()).trim();
                // 打印到控制台
                System.out.println(receiveData);
                // 什么时候退出
                if ("bye".equals(receiveData)) {
                    break;
                }
            }
    
            // 关闭
            socket.close();
        }
    }
    
    

    3、模拟双方通信

    模拟双方使用UDP通信,需要开启两个线程,并对以上代码进行【共性提取】,进一步进行抽象。
    由此,双方可以通过指定的端口来互相发送消息。

    3.1、发送方的线程

    // 开启多线程需要实现 Runnable 接口,实现 run()方法
    public class TalkSender implements Runnable {
        // 网络套接字,发送需要
        DatagramSocket socket = null;
        // 缓冲读取流
        BufferedReader reader = null;
        // 开启哪个端口接收
        private int fromPort;
        // 对方的 IP
        private String toIP;
        // 对方的端口
        private int toPort;
        // 通过构造方法进行初始化
        public TalkSender(int fromPort, String toIP, int toPort) {
            this.fromPort = fromPort;
            this.toIP = toIP;
            this.toPort = toPort;
            try {
                socket = new DatagramSocket(fromPort);
            } catch (SocketException e) {
                e.printStackTrace();
            }
        }
    
        // 重写 run()方法,设置线程任务
        @Override
        public void run() {
            while (true) {
                String data = null;
                try {
                    // 准备发送包裹,从键盘接收数据
                    reader = new BufferedReader(new InputStreamReader(System.in));
                    // 读取一行
                    data = reader.readLine();
                    byte[] dataBytes = data.getBytes();
                    DatagramPacket packet = new DatagramPacket(dataBytes, dataBytes.length, new InetSocketAddress(toIP, toPort));
                    socket.send(packet);
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                // 什么时候退出
                if ("bye".equals(data)) {
                    break;
                }
            }
            // 关闭
            socket.close();
        }
    }
    
    

    3.2、接收方的线程

    public class TalkReveicer implements Runnable {
    
        DatagramSocket socket = null;
        // 从哪个端口接收
        private int formPort;
        // 发送方是谁
        private String who;
        public TalkReveicer(int formPort, String who) {
            this.formPort = formPort;
            this.who = who;
            try {
                socket = new DatagramSocket(formPort);
            } catch (SocketException e) {
                e.printStackTrace();
            }
    
        }
    
        @Override
        public void run() {
            while (true) {
                String receiveData = null;
                try {
                    // 准备接收数据包裹
                    byte[] buffer = new byte[1024];
                    // 接收数据
                    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                    // 接收数据,阻塞式
                    socket.receive(packet);
                    // 接收到的数据
                    receiveData = new String(packet.getData());
                    System.out.println(who + ":" + receiveData.trim());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 什么时候退出
                if ("bye".equals(receiveData)) {
                    break;
                }
            }
    
            // 关闭
            socket.close();
        }
    }
    
    

    3.3、模拟学生

    // 学生端
    public class TalkStudent {
        public static void main(String[] args) {
            // 开启 5555端口,发送到本机的 6666端口
            new Thread(new TalkSender(5555, "localhost", 6666)).start();
            // 规定使用 7777 端口接收老师发送的消息
            new Thread(new TalkReveicer(7777, "老师")).start();
        }
    }
    
    

    3.4、模拟老师

    // 教师端
    public class TalkTeacher {
        public static void main(String[] args) {
            // 开启 8888端口,发送到本机的 7777端口
            new Thread(new TalkSender(8888, "localhost", 7777)).start();
            // 规定使用 6666 端口接收学生发送的消息
            new Thread(new TalkReveicer(6666, "学生")).start();
    
        }
    
    }
    

    总结:

    使用UDP通信,其实主要的步骤分为三步:

    • 用 DatagramSocket() 来开启端口,通过开启端口聊天。
    • 用DatagramPacket() 来发送或者接收数据。
    • 关闭 DatagramSocket,释放资源。
  • 相关阅读:
    LA 3882
    Codeforces 161D
    spoj PARTIT
    uva 10496 Collecting Beepers
    uva 10130 SuperSale
    spoj 3885
    NWERC 2012 Problem I Idol
    NWERC 2012 Problem E Edge Case
    【USACO 1.3.2】修理牛棚
    【USACO 1.3.1】混合牛奶
  • 原文地址:https://www.cnblogs.com/rainszj/p/12795899.html
Copyright © 2011-2022 走看看