【Java 网络编程】UDP 服务器 客户端 通信 ( DatagramSocket | DatagramPacket | UDP 发送数据包 | UDP 接收数据包 | 端口号分配使用机制 )[通俗易懂]

【Java 网络编程】UDP 服务器 客户端 通信 ( DatagramSocket | DatagramPacket | UDP 发送数据包 | UDP 接收数据包 | 端口号分配使用机制 )[通俗易懂]IUDP信息发送接收原理IIUDP发送和接收端口相同IIIUDP发送信息代码示例IVUDP接收信息代码示例VUDP服务器端代码示例VIUDP客户端代码示例VII客户端服务器端通信

大家好,又见面了,我是你们的朋友全栈君。

I UDP 信息发送接收原理


1. UDP 既有客户端的功能 , 也有服务器端的功能 ;

2. UDP 发送和接收 : 计算机 A 向 计算机 B 的 X 端口发送消息 , B 不一定能接收到 , B 能收到并处理该消息的前提是 , B 当前正在监听 X 端口 ;

3. 发送设备个数 : B 监听 X 端口 , 并接收数据 , 向 B 发送信息的设备可以是多个 , B 可以接收到任何设备向其 X 端口发送的数据 ;

4. 端口号说明 : UDP 报文头 64 位 , 其中有发送源端口号 , 和接收的目标端口号 , 这个目标端口号是 X 端口号 , 发送源端口号是随机的动态端口号 ;

5. 相互通信 : B 收到消息时 , 才知道 A 设备发送消息的端口号 ; 如果 B 收到消息 , 然后马上向 A 的发送源端口号回送一条消息 , 如果 A 计算机正在监听这个端口号 , 就可以收到 B 计算机发送的消息 ; 如果 A 没有监听 , 那么收不到这个消息 ;

II UDP 发送和接收端口相同


UDP 发送和接收使用的是同一个端口 ;
UDP 发送和接收使用的是同一个端口 ;
UDP 发送和接收使用的是同一个端口 ;

重要的事情说三遍

III UDP 发送信息代码示例


1. 创建 DatagramSocket 对象 : 发送 UDP 数据包 , 首先要创建 DatagramSocket 对象 , 该对象可用于 UDP 数据包的发送和接收 , 创建时如果需要监听数据的接收 , 可以指定监听的端口 , 也可以等待系统自动分配一个端口 , 使用该端口进行数据的发送和接收 ;

2. 创建并设置 DatagramPacket 对象 : 发送的数据包实体是 DatagramPacket 对象 , 将目标设备的 IP 地址 , 端口号 , 发送的 byte[] 数组数据 , 设置到该数据包实体中 , 调用 DatagramSocket 对象的 send 方法 , 将该数据包发送出去 ;

3. 动态端口号自动分配 : 这里注意 , 发送的同时 , 系统自动分配了 一个动态端口号 , 该发送端口号就是接受端口号 , UDP 开始监听该端口号 , 意味着可以从该端口号接受数据包 , 服务器端就是接收到信息后 , 将反馈数据发送到该动态分配的端口中 ;

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


            //1. UDP 数据包套接字 , 客户端 ,
            // 无需指定端口 , 让系统直接分配一个端口 , 使用该端口发送和接收数据
            DatagramSocket datagramSocket = new DatagramSocket();


            //II. 发送 UDP 数据包


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

            //5. 将数据包发送出去
            datagramSocket.send(sendPacket);

IV UDP 接收信息代码示例


1. 创建 DatagramSocket 对象 : 接收 UDP 数据包 , 首先要创建 DatagramSocket 对象 , 注意必须设置一个监听的端口号 , 才能接收数据包 ;

客户端没有设置监听端口号 , 接收到了数据 , 是因为其先发送的数据 , 发送数据的同时 , 系统自动为其分配了一个动态端口号 , UDP 中发送和接收使用的是同一个端口号 , 在分配完该动态端口号之后 , 客户端就开始监听该端口号了 ;

2. 创建并设置 DatagramPacket 对象 : 接收的数据包实体是 DatagramPacket 对象 , 需要为其设置一个接收数据的缓冲区 , 接收到数据包后 , 系统会自动将发送信息的设备的 IP 地址 , 端口号 , 发送的 byte[] 数组数据 , 设置到该数据包实体中 , 调用 DatagramSocket 对象的 receive 方法 , 会阻塞等待数据包到来 ;

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


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


            //II. 接收 UDP 数据包


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

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

V UDP 服务器端代码示例


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

public class UDPServer { 
   

    public static void main(String[] args){ 
   

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

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


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


            //II. 接收 UDP 数据包


            //2. 接收数据包使用的缓冲区
            byte[] receiveBuffer = new byte[1024];
            //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);

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

}

VI UDP 客户端代码示例


import java.io.IOException;
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 数据包套接字 , 客户端 ,
            // 无需指定端口 , 让系统直接分配一个端口 , 使用该端口发送数据
            DatagramSocket datagramSocket = new DatagramSocket();


            //II. 发送 UDP 数据包


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

            //5. 将数据包发送出去
            datagramSocket.send(sendPacket);

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

            //III. 接收 UDP 数据包


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

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

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

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

}

VII 客户端服务器端通信


1. 服务器运行 : 先运行服务器 , 此时服务器开始监听 8888 端口 ,

2. 客户端发送信息 : 再运行客户端 , 客户端向服务器端的 8888 端口发送数据 , 客户端的发送端口是随机的 , 本次是 57660 端口 , 这是个动态分配端口 , UDP 的发送和接收端口是同一个端口 , 此时 UDP 开始监听该端口 ;

3. 服务器端反馈信息 : 服务器端收到客户端发送的数据 , 处理后将反馈数据再次发送回去 , 这里发送给客户端的 57660 端口 , 服务器端的发送端口就是 8888 端口 ;

UDP 发送和接收端口是同一个端口 ;

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/142721.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Python 判断文件是否存在的三种方法

    Python 判断文件是否存在的三种方法这里将介绍三种判断文件或文件夹是否存在的方法,分别使用os模块、Try语句、pathlib模块。1.使用os模块os模块中的os.path.exists()方法用于检验文件是否存在。判断文件是否存在import osos.path.exists(test_file.txt)#True

  • 决策树:什么是基尼系数(“杂质 增益 指数 系数”辨析)「建议收藏」

    决策树:什么是基尼系数(“杂质 增益 指数 系数”辨析)「建议收藏」决策树:什么是基尼系数在我翻译学习这篇RandomForestsforCompleteBeginners的时候,对基尼系数和它相关的一些中文表达充满了疑问,查了一些资料以后,完成了这篇文章。其中基尼杂质系数的计算和解释参考了ASimpleExplanationofGiniImpurity。如果你查看scikit-learn中DecisionTreeClassifier的文…

  • 照片无缝滚动

    照片无缝滚动

  • poj 1142_poj是什么意思

    poj 1142_poj是什么意思http://poj.org/problem?id=1142题意:找一个比n大的数字,这个数字要可以分解(这点很重要)成,分解的因子和,和这个数字的各位数字和,相等的话,输出这个数字思路:因为这个数字要可以分解,所以首先判断这个数是否是质数,这个很重要,因为质数不符合题意。然后对这个数字进行分解。递归分解。递归的时候也注意,有可能某个因子是质数,如果这个因子是质数,比如11,也要…

  • 徐 氏 介 绍_徐氏的起源

    徐 氏 介 绍_徐氏的起源一、姓氏源流徐氏的姓氏来源比较纯正,主要出自嬴姓。是先帝玄孙伯益之子若木的后裔。相传陷帝有一个孙女叫女修,因食燕子蛋而怀有大业。大业娶少典氏女子女华为妻,生下了皋陶,皋陶生三子(另一说是六子)长子伯益,又叫…

  • html 下拉导航栏源码,html导航栏下拉菜单怎么制作?这里有详细的代码实例「建议收藏」

    html 下拉导航栏源码,html导航栏下拉菜单怎么制作?这里有详细的代码实例「建议收藏」元素来包裹这些元素,并使用CSS来设置下拉内容的样式。html导航栏菜单的CSS部分:.dropdown类使用position:relative,这将设置下拉菜单的内容放置在下拉按钮(使用position:absolute)的右下角位置。.dropdown-content类中是实际的下拉菜单。默认是隐藏的,在鼠标移动到指定元素后会显示。注意min-width的值设置为160px。你可以随意修改它…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号