Java中UDP通信连接实现

简介: TCP与UDP的主要区别:TCP—传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。
TCP与UDP的主要区别:

TCP—传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端
UDP—用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快.

在Java数据通信中UDP编程

UDP协议(用户数据报协议)是无连接的、不可靠的、无序的,速度快
进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去

DatagramPacket类:表示数据报包
DatagramSocket类:进行端到端通信的类
服务器端实现步骤
① 创建DatagramSocket,指定端口号
② 创建DatagramPacket
③ 接受客户端发送的数据信息
④ 读取数据

public class UDPServer {
    public static void main(String[] args) throws IOException {
        /*
         * 接收客户端发送的数据
         */
        //1.创建服务器端DatagramSocket,指定端口
        DatagramSocket socket=new DatagramSocket(8800);
        //2.创建数据报,用于接收客户端发送的数据
        byte[] data =new byte[1024];//创建字节数组,指定接收的数据包的大小
        DatagramPacket packet=new DatagramPacket(data, data.length);
        //3.接收客户端发送的数据
        System.out.println("****服务器端已经启动,等待客户端发送数据");
        socket.receive(packet);//此方法在接收到数据报之前会一直阻塞
        //4.读取数据
        String info=new String(data, 0, packet.getLength());
        System.out.println("我是服务器,客户端说:"+info);

        /*
         * 向客户端响应数据
         */
        //1.定义客户端的地址、端口号、数据
        InetAddress address=packet.getAddress();
        int port=packet.getPort();
        byte[] data2="欢迎您!".getBytes();
        //2.创建数据报,包含响应的数据信息
        DatagramPacket packet2=new DatagramPacket(data2, data2.length, address, port);
        //3.响应客户端
        socket.send(packet2);
        //4.关闭资源
        socket.close();
    }
}

客户端实现步骤
① 定义发送信息
② 创建DatagramPacket,包含将要发送的信息
③ 创建DatagramSocket
④ 发送数据

public class UDPClient {
    public static void main(String[] args) throws IOException {
        /*
         * 向服务器端发送数据
         */
        //1.定义服务器的地址、端口号、数据
        InetAddress address=InetAddress.getByName("localhost");
        int port=8800;
        byte[] data="用户名:jinbin;密码:1997".getBytes();
        //2.创建数据报,包含发送的数据信息
        DatagramPacket packet=new DatagramPacket(data, data.length, address, port);
        //3.创建DatagramSocket对象
        DatagramSocket socket=new DatagramSocket();
        //4.向服务器端发送数据报
        socket.send(packet);

        /*
         * 接收服务器端响应的数据
         */
        //1.创建数据报,用于接收服务器端响应的数据
        byte[] data2=new byte[1024];
        DatagramPacket packet2=new DatagramPacket(data2, data2.length);
        //2.接收服务器响应的数据
        socket.receive(packet2);
        //3.读取数据
        String reply=new String(data2, 0, packet2.getLength());
        System.out.println("我是客户端,服务器说:"+reply);
        //4.关闭资源
        socket.close();
    }
}

下面进行测试
同样的,需要先启动服务端再启动客户端
启动完可以看到服务端控制台显示如下

image.png

下面来启动客户端
image.png

再来看看服务端
image.png

这样就实现了服务端与单个客户端的通信

下面来通过多线程实现服务端与多个客户端的通信

服务器端线程处理类UDPServerThread

public class UDPServerThread extends Thread{
    DatagramPacket packet;
    DatagramSocket socket;

    public UDPServerThread(DatagramPacket packet, DatagramSocket socket) {
        super();
        this.packet = packet;
        this.socket = socket;
    }

    @Override
    public void run(){
        try {
            //获取客户端信息
            byte[] data = packet.getData();
            String info1 = new String(data, 0, packet.getLength());
            System.out.println("我是服务器,客户端说:" + info1);
            //响应客户端
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            byte[] data1 = "欢迎您!".getBytes();
            DatagramPacket packet1 = new DatagramPacket(data1, data1.length, address, port);
            socket.send(packet1);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端代码相应改下

public class UDPServer {
    public static void main(String[] args) throws IOException {
        /*
         * 接收客户端发送的数据
         */
        //1.创建服务器端DatagramSocket,指定端口
        DatagramSocket socket=new DatagramSocket(8800);
        //2.创建数据报,用于接收客户端发送的数据
        byte[] data =new byte[1024];//创建字节数组,指定接收的数据包的大小
        System.out.println("****服务器启动,等待客户端连接****");
        int count=1;
        while(true) {
            DatagramPacket packet = new DatagramPacket(data, data.length);
            socket.receive(packet);
            UDPServerThread serverThread = new UDPServerThread(packet, socket);
            serverThread.start();
            System.out.println("客户端数量:" + count++);
        }
    }
}

这里的socket.receive()如果不写的话会产生死循环
同样客户端也是不用改

下面进行测试

1.启动服务端

image.png

2.启动一个客户端
image.png

3.服务端并没有停止,并且接收到客户端传来的信息
image.png

4.再启动下客户端,控制台显示客户端数量为2,证明可以与对个客户端通信
image.png

注意:UDP多个客户端通信的时候socket是不关闭的,我也试过关闭的话
会出异常Exception in thread "main" java.net.SocketException: socket closed
因为在UDPServer类的while是死循环,无法重新创建socket,所以这里不能关闭socket,否则无法进行下一个客户端的监听

总结:

UDP相较于TCP,不需要进行复杂的设定输入输出流,只需要设定数据报,即DatagramPacket。而TCP的发送以及接收消息,是通过socket.getInputStream()或者getOutputStream()方法,而UDP是直接设置了,DatagramSocket,通过其send()或者receive()方法来接收或发送消息。
TCP的关键组成有服务端的ServerSocket.accept()方法,这个方法是直到接收到了客户端的连接才会返回一个Socket,用于接下来的输入和输出。

所以说,TCP的数据传输是需要提前连接、三方握手,数据传输非常安全。而UDP是不需要提前连接的,无需等待对方回答,所以不保证数据不丢失。
目录
相关文章
|
5天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
20 1
[Java]线程生命周期与线程通信
|
14天前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
2天前
|
存储 Java 关系型数据库
高效连接之道:Java连接池原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。频繁创建和关闭连接会消耗大量资源,导致性能瓶颈。为此,Java连接池技术通过复用连接,实现高效、稳定的数据库连接管理。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接池的基本操作、配置和使用方法,以及在电商应用中的具体应用示例。
15 5
|
5天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
26天前
|
Java 关系型数据库 MySQL
如何用java的虚拟线程连接数据库
本文介绍了如何使用Java虚拟线程连接数据库,包括设置JDK版本、创建虚拟线程的方法和使用虚拟线程连接MySQL数据库的示例代码。
31 6
如何用java的虚拟线程连接数据库
|
6天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
8 1
|
6天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
17 1
|
6天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
14 1
|
17天前
|
Java
|
18天前
|
SQL 存储 Java
Java中使用ClickHouseDriver连接和基本操作
通过上述步骤,你可以轻松地在Java应用中集成ClickHouse数据库,执行基本的CRUD操作。需要注意的是,实际开发中应当根据实际情况调整数据库连接配置(如URL中的主机、端口、数据库名等),并根据应用需求选择合适的异常处理策略,确保代码的健壮性和资源的有效管理。此外,对于复杂查询和大批量数据处理,建议充分利用ClickHouse的特性(如分布式处理、列式存储优化等),以进一步提升性能。
15 2