java网络编程(四)----通信协议之UDP

前言

在了解了TCP协议中java代码TCP协议中java代码的相关编写后,今天我们继续了解UDP协议

1.UDP: 发短信

[1] 不连接,不稳定
[2] 客户端与服务端没有明确界限
[3] 不管有没有准备好,都可以发送给你
(就好比导弹攻击;DDOS,洪水攻击)

1.1 我们下面先来模拟一个单方面的接收和单方面发送的例子
发送端

package com.gs.lesson03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

//不需要连接服务器
public class UdpClientDemo01 {
    public static void main(String[] args) throws Exception {
        // 1.建立一个Socket
        DatagramSocket socket = new DatagramSocket();
        // 2.建个包
        String msg = "你好啊,服务器!";
        //2.1发送给谁(IP地址+端口号)
        InetAddress localhost = InetAddress.getByName("localhost");
        int port = 9090;
        //数据 数据的起始位置 数据的结束位置 IP地址 端口号
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
        //3. 发送包
        socket.send(packet);
        //4.关闭流
        socket.close();
    }
}

接收端

package gs.lesson03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

//还是要等待客户端连接
public class UdpServerDemo01 {
    public static void main(String[] args) throws Exception {
        //1.开放端口
        DatagramSocket socket = new DatagramSocket(9090);
        //2.接收数据包
        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);

        //阻塞(就是等待接收)
        socket.receive(packet);
        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(new String(packet.getData(),0,packet.getLength()));
        //3.关闭连接
        socket.close();

    }
}

1.2 上面的例子显然只是一个入门,因为他只能接收一条信息;那么我们如何实现接收多条信息,并在适当的时候断开连接呢?
下面我们模拟一个接收方可以接收多条信息,并在接收到bye这个命令后就断开连接。

发送方

package gs.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class UdpSenderDemo01 {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8888);

        //准备数据,控制台取 System.in
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        while(true){
            String data = reader.readLine();
            byte[] datas = data.getBytes();
            DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
            //发送数据包
            socket.send(packet);
            //当接收到 bye时退出
            if(data.startsWith("bye")){
                break;
            }

        }


        socket.close();

    }
}

接收方

package gs.chat;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpReceiverDemo01 {

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(6666);

        while (true){
            // 准备接收包裹
            byte[] container = new byte[1024];
            DatagramPacket packet = new DatagramPacket(container,0,container.length);
            // 阻塞式接收包裹
            socket.receive(packet);

            // 当收到 bye时断开连接
            byte[] data = packet.getData();
            String receiveData = new String(data,0,data.length);
            System.out.println(receiveData);
            if(receiveData.startsWith("bye")){
                break;
            }

        }

        socket.close();
    }
}

1.3 上面的例子还是显然不足的,我们还是没有实现真正的通信,也就是你说一句,我能回一句的那种。那我们该如何实现呢?
这里我们可以开启两个线程进行模拟,这两个线程分别代表接收方和发送方。也就是每个人都是接受信息的人,也是发送信息的人。
[1] 编写接受方线程

package gs.chat;

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

public class TalkReceiver implements Runnable {

    DatagramSocket socket = null;
    //接收方的端口
    private int port;
    //信息来自谁
    private String msgFrom;

    public TalkReceiver(int port,String msgFrom) {
        this.port = port;
        this.msgFrom = msgFrom;
        try {
            //新建数据报连接
            socket = new DatagramSocket(port);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {


        while (true){
            try {
                // 准备接收包裹
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container,0,container.length);
                // 阻塞式接收包裹
                socket.receive(packet);

                // 当收到 bye时断开连接
                byte[] data = packet.getData();
                String receiveData = new String(data,0,data.length);
                System.out.println(msgFrom+":"+receiveData);
                if(receiveData.startsWith("bye")){
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        socket.close();
    }
}


[2] 编写发送方的线程

package gs.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class TalkSend implements Runnable {
    DatagramSocket socket = null;
    BufferedReader reader = null;

    //发送者的端口
    private int fromPort;
    //接收者的IP
    private String toIp;
    //接收者的端口
    private int toPort;

    public TalkSend(int fromPort, String toIp, int toPort) {
        this.fromPort = fromPort;
        this.toIp = toIp;
        this.toPort = toPort;

        try {
            //新建一个数据报连接
            socket = new DatagramSocket(fromPort);
            //获取我们键盘上的输入
            reader = new BufferedReader(new InputStreamReader(System.in));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {

        while(true){

            try {
                //读取相应的数据形成数据源包
                String data = reader.readLine();
                byte[] datas = data.getBytes();
                DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIp,this.toPort));
                //发送数据包
                socket.send(packet);
                //当接收到 bye时退出
                if(data.startsWith("bye")){
                    break;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        socket.close();
    }
}

[3] 模拟通信的双方,一个为Teacher,需要开启一个接收线程和发送线程
假设老师要发送给学生的地址是localhost 8888,则学生接收的地址就是localhost 8888
学生要发送给老师的地址是localhost 9999, 则老师接收的地址就是localhost 9999。
(看起来描述很愚蠢,只要你不被代码绕进去就好)

package gs.chat;

public class TalkTeacher {
    public static void main(String[] args) {
        new Thread(new TalkSend(5555,"localhost",8888)).start();
        new Thread(new TalkReceiver(9999,"student")).start();
    }
}

[4] 一个为Student

package gs.chat;

public class TalkStudent {
    public static void main(String[] args) {
        //开启两个线程
        new Thread(new TalkSend(7777,"localhost",9999)).start();
        new Thread(new TalkReceiver(8888,"teacher")).start();
    }
}

运行后就是一个mini的聊天室了
在这里插入图片描述
在这里插入图片描述

总结

以上这些网络编程的学习笔记都是在B站看狂神时所写的。如果有任何疑惑,可以下方留言,也请多关注这个UP主。

发布了82 篇原创文章 · 获赞 6 · 访问量 6873

猜你喜欢

转载自blog.csdn.net/TheWindOfSon/article/details/105368852