网络编程入门之UDP编程

欢迎各位帅哥美女来捧场,本文是介绍UDP网络编程。在这里,你会见到最详细的教程;细致到每一行代码,每一个api的由来和使用它的目的等。

目录

1.UDP相关API

1.1.两个类

1.2.两个类中的方法

2.UDP编程

2.1.大体框架

2.2.内容构造

2.3.方法总结


1.UDP相关API

想要实现UDP编程,肯定要掌握一些用来操作udp的api,主要两个类,多个方法。

1.1.两个类

这两个类包括:DatagramSocket和DatagramPacket,至于这两个类里面的方法,下一个小标题介绍。

(1)DatagramSocket类

这个类,是用来操作网卡的,也就是用来创造服务器/客户端。可以获取到操作网卡的一个流对象,用来发送数据、接收数据、关闭流对象

(2)DatagramPacket类

这个类用来表示udp数据报,也就是用来保存数据的。DatagramPacket对象可以保存请求、响应、ip/端口号等信息。

1.2.两个类中的方法

(1)DatagramSocket类

  • 构造方法
方法签名解释
DatagramSocket()无参构造。创造一个UDP数据报套接字的Socket,绑定到本机任意一个端口(一般用于客户端,系统会分配一个空闲的端口号)
DatagramSocket(int port)创造一个UDP数据报套接字的Socket,并且绑定到本机指定端口号上(一般用于服务器)

(1)无参构造方法一般用在客户端,不需要指定端口号,这种就是由系统随机分配空闲的端口号。(2)带参的构造方法,一般用在服务器,给服务器指定一个端口号;服务器需要在启动时就有端口号,方便客户端寻找。 

  • 普通方法
方法签名说明
void receive(DatagramPacket p)从这个套接字接收数据报,存到p中(如果没接收到,会阻塞等待)
void send(DatagramPacket p)从这个套接字发送数据报p(不会阻塞,都是直接发送)
void close()关闭这个数据报套接字(类似关闭流)

上面三个就是udp通信的三部曲:接收请求、(解析请求)、发送响应(服务器);发送请求、接收响应(客户端);最后都需要关闭流(一般socket流对象和客户端服务器的声明周期一样,就不需要我们去主动关闭)

(2)DatagramPacket类

这是一个描述数据报的类,用来保存数据报。

  • 构造方法
方法签名说明
DatagramPacket(byte[] bf,int length)构造一个数据报,并且使用字节数组接收数据,接受指定的长度
DatagramPacket(byte[] bf,int offset,int length,SocketAddress address,(port))用来发送数据报。发送的数据在字节数组中,从offset到length长度。address包含目的主机的IP和端口号

 (1)第一个构造方法:一般用于接收信息,像服务器接收请求和客户端接收响应;构造一个空的udp数据报对象,参数是指定一块存放数据的空间,后面的长度表示这一块空间的可用部分。(2)第二个构造方法:一般用于发送信息,像服务器发送响应和客户端发送请求;构造一个带有信息的udp数据报。具体信息存在第一个参数(请求或者响应),第二、三个参数表示信息的有效长度范围,第四个参数里面存放的是ip地址(也可以同时包含端口号),第五个参数表示端口号(当前面一个参数没有包含端口号时)。

  • 普通方法 
方法名解释
InetAddress getAddress()从接收/发送的数据报中,获取发送端的主机IP或者接收端的主机IP
int getPort()从接收的数据报中,获取发送端主机的端口号;或者获取发送端主机的端口号
byte[] getData()获取数据报中的数据

这些方法,就是用来获取udp数据报中的一些信息的,比如第一个获取ip地址,第二个获取端口号等,不过想要完成udp通信,掌握这几个方法还不够,但是现在先不介绍完,等到介绍完udp通信我们就一起介绍。

2.UDP编程

前置常识:接下来就是要编写一个关于udp的网络程序,就需要有服务器和客户端(两个不同的程序/进程),服务器是可以24*7h的处理请求的(我们写成死循环即可),客户端随意(我们也写成死循环,表示可以不断发送请求)。

而且我们这里的服务器暂时作为一个回响服务器,也就是不解析请求,发送什么再发送回去即可。接下来就开始编程我们的第一个简单网络程序吧。

2.1.大体框架

(1)服务器

//各种包,这里先不写
//回显服务器
public class UdpEchoService {private  DatagramSocket socket = null;public UdpEchoService(int port) throws SocketException {socket = new DatagramSocket(port);//给服务器指定端口号}public void start() throws IOException {System.out.println("服务器启动!");while(true) {//写成死循环,用于不断处理客户端发来的请求//1.接收请求//2.解析请求//3.发送响应(解析好的请求)  }}public String service(String request) {//这个方法用来解析请求return request;}public static void main(String[] args) throws IOException {UdpEchoService service = new UdpEchoService(1314);service.start();}
}

main方法用来启动服务器,会先调用构造方法,构造好一个服务器,然后里面会自动调用start方法,表示服务器真正的启动了(可以处理请求)

(2)客户端

//各种包,这里也暂时不写
public class UdpEchoClient {private DatagramSocket socket = null;private String Ip;private int port;public UdpEchoClient(String Ip,int port) throws SocketException {socket = new DatagramSocket();//系统随机分配端口号this.Ip = Ip;//记录服务器的ip地址this.port = port;//记录服务器的端口号}public void start() throws IOException {System.out.println("客户端启动!");Scanner in = new Scanner(System.in);while (true) {//1.输入请求//2.发送请求//3.接收响应(服务器处理好请求后返回)//4.打印响应  }}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1",1314);//绑定本主机的服务器client.start();}
}

这里的客户端同理,构造方法只是做好了准备工作,等到start方法后,才能真正的开始发送请求(客户端启动)

2.2.内容构造

(1)服务器

接下来,我们分别完善服务器的三步曲:接收请求、解析请求、返回响应。

  • 接收请求

udp客户端发送过来的请求,是一个二进制/字节流数据,所以我们需要使用一个udp数据报对象来接收,也就是构造一个udp数据报对象

DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);

udp数据报对象中的参数相当于是一个“空盘子”,用来接收客户端发送过来的请求(udp数据报对象中没有实现,就需要我们自己指定一块空间)

当udp数据报对象构造完成后,就可以开始接收请求了

socket.receive(requestPacket);//接收请求,存放在requestPacket中

此时,我们就已经拿到客户端的请求了,但是此时是二进制信息,为了我们方便解析请求,所以我们打算将其转换成一个字符串请求

String request = new String(requestPacket.getData(),0,requestPacket.getLength());

这里就是需要使用到一些DatagramPacket类的方法了。

(1)第一个参数:前面介绍过多的,用来获取udp中的数据;(2)第二、三个参数,就是表示要获取udp中信息的范围,表示从0到二进制信息结尾(getLength()求的是什么长度?)(3)最后,String有提供相关的构造方法,用于将二进制数据转化成字符串数据

完整的接收请求代码:

//1.接收请求
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);String request = new String(requestPacket.getData(),0,requestPacket.getLength());
  • 解析请求

这一步就比较简单了,因为是回显服务器,只需要发送什么就返回什么即可;但是还是要做做样子,假装经过方法解析,然后得到一个响应。

//2.计算响应
String response = service(request);

计算请求的方法:

public String service(String request) {return request;
}

这一步很简单

  • 返回响应

我们现在拿到的响应是一个string,返回时需要的是一个udp,所以也需要转化一下才行,我们这里需要使用到上面的udp数据报构造方法

socket.send(responsePacket);
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestPacket.getSocketAddress());

这里有四个参数,需要解释一下:

(1)第一个参数:获取到字符串response中的数据;(2)第二、三个参数就是表示需要转化成的udp数据范围;(3)第四个参数:从前面接收的请求中获取客户端的ip地址(用来服务器确定响应是发给谁的)

通过上述的操作,此时responsePacket中就包含了响应和信息,接下来就可以返回响应了。

socket.send(responsePacket);

服务器的响应代码:

 public void start() throws IOException {System.out.println("服务器启动!");while(true) {//1.接收请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);//构造udp数据报socket.receive(requestPacket);//接收客户端的请求String request = new String(requestPacket.getData(),0,requestPacket.getLength());//将二进制请求(udp数据报)转化成字符串(字符流)//2.计算响应String response = service(request);//3.返回响应DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf("[%s:%d] req=%s,resp=%s\n",requestPacket.getAddress(),requestPacket.getPort(),request,response);//                                                客户端请求     返回的响应                  客户端ip     端口}}public String service(String request) {return request;}

最下面有一个打印客户端信息的代码:前面两个就是获取ip地址和端口号的方法

回响服务器完整代码:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;//回显服务器
public class UdpEchoService {private  DatagramSocket socket = null;public UdpEchoService(int port) throws SocketException {socket = new DatagramSocket(port);//给服务器指定端口号}public void start() throws IOException {System.out.println("服务器启动!");while(true) {//1.接收请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);//构造udp数据报socket.receive(requestPacket);//接收客户端的请求String request = new String(requestPacket.getData(),0,requestPacket.getLength());//将二进制请求(udp数据报)转化成字符串(字符流)//2.计算响应String response = service(request);//3.返回响应DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf("[%s:%d] req=%s,resp=%s\n",requestPacket.getAddress(),requestPacket.getPort(),request,response);//                                                 客户端ip          客户端端口号                  客户端请求     返回的响应}}public String service(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoService service = new UdpEchoService(1314);System.out.println("我是父类服务器");service.start();}
}

(2)客户端

现在只需要完成客户端的四部曲即可:输入请求、发送请求、接收响应、打印响应

  • 输入请求

我们这里直接使用字符串来接收请求即可

System.out.print("请输入你的请求:");
//1.输入请求
String request = in.nextLine();
  • 发送请求

因为我们输入的请求是一个字符串类型,而发送udp数据报是字节类型,也可以说是需要将字符串请求打包成一个udp数据报才能发送

打包请求:

DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,InetAddress.getByName(Ip),port);

这里同理,打包成一个DatagramPacket数据报,里面需要包含:请求和服务器的ip和端口号;前面三个参数就不多介绍,第四个参数是一个新的方法:InetAddress.getByName(int port),用来……

发送请求:

socket.send(requestPacket);

发送请求完整代码:

//2.发送请求
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,InetAddress.getByName(Ip),port);
socket.send(requestPacket);
  • 接收响应

当向服务器发送完请求后,就需要接收服务器返回回来的响应,类型是一个DatagramPacket数据报。

DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);

这里需要提前构造一个DatagramPacket数据报,然后再去接收。

  • 打印响应
//4.打印请求
String response = new String(responsePacket.getData(),0,responsePacket.getLength());System.out.println("响应为:"+response);

客户端完整代码:

//客户端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String Ip;private int port;public UdpEchoClient(String Ip,int port) throws SocketException {socket = new DatagramSocket();this.Ip = Ip;this.port = port;}public void start() throws IOException {System.out.println("客户端启动!");Scanner in = new Scanner(System.in);while (true) {System.out.print("请输入你的请求:");//1.输入请求String request = in.nextLine();//2.发送请求DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,InetAddress.getByName(Ip),port);socket.send(requestPacket);//3.接收响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);//4.打印请求String response = new String(responsePacket.getData(),0,responsePacket.getLength());//System.out.println("中文翻译为:"+response);System.out.println("响应为:"+response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1",1314);//绑定本主机的服务器client.start();}
}

客户端服务器也就都写好了,接下来实验一下。

先启动服务器:

在启动客户端:

客户端发送请求:

服务器日志:

至此,UDP服务器-客户端编码完成。

 执行流程图:

2.3.方法总结

在前面,我已经介绍过一次方法了,现在又准备介绍一次,是为了水字数吗?那当然不是,前面两个类中的一些方法,只是为了让你认识到这些类,和实例化了对象后该怎么去做。

接下来,我们再进一步结合代码来介绍方法,而且主要是和DatagramPacket有关的方法。

(1)获取ip地址和端口号

  • 直接调用方法分别获得
方法解释
InetAddress getAddress()获取ip地址
int getPort()获取端口号

在代码中的体现

(2)求数据长度

这里是什么意思呢?你一定看过这些代码

这些求数据长度的有什么区别?该怎么使用?为什么要这样写?就是我们接下来要介绍的

  • 字符和字节的区别

首先,字符>字节,一个字符可能包含多个字节。一个字符串,如果都是数字或者英文字母,那么它的字符数和字节数大概率是一样的;但是如果一个字符串中包含汉字等重量字符,那么字符数>字节数。

  • 求长度的区别

如果本身是一个字节类型的字符串数据,那么我们直接取长度就好;但是如果是一个String类型的字符串,要将它转化成udp数据报,就需要先转化成字节类型,再求其长度。

如果本身是字节类型,就不需要转换;如果是字符串类型,就需要。原因:只要转化成最小单位,就不会遗漏数据

(3)字符串ip地址转成点分十进制格式

在客户端程序里面,有这么一个方法:

所以通过InetAddress.getByName(String ip)方法就可以将String类型的ip转换成一个java可以识别的ip对象(也就是InetAddress对象)

InetAddress.getByName(String ip)将字符串类型的ip地址转成java可识别的

(4)同时获得ip地址和端口号

服务器中的一段代码

目的是:现在服务器需要将响应发回客户端,就需要知道客户端的ip地址和客户端。

getSocketAddress()获取ip和端口号

返回一个InetSocketAddress对象,里面就包含ip地址和端口号

(5)获取数据

  • 获取udp数据报中的数据
byte[] getData()将udp中的数据存入一个字节数组中

代码体现:

  • 获取字符串中的数据
byte[] getBytes()将字符串中的数据存入一个字节数组中

代码体现:

以上就是udp客户端-服务器编程中使用到的方法了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/8506.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【项目学习01_2024.05.08_Day06】

学习笔记 5 新增课程5.1 需求分析5.1.1 业务流程5.1.2 数据模型 5.2 接口定义5.3 接口开发5.3.1 保存课程基本信息5.3.2 保存营销信息 5.4 接口测试 5 新增课程 5.1 需求分析 5.1.1 业务流程 5.1.2 数据模型 5.2 接口定义 5.3 接口开发 根据需求分析,新增课程表…

【智能楼宇秘籍】一网关多协议无缝对接BACnet+OPC+MQTT

在繁华的都市中心,一座崭新的大型商业综合体拔地而起,集购物、餐饮、娱乐、办公于一体,是现代城市生活的缩影。然而,这座综合体的幕后英雄——一套高度集成的楼宇自动化系统,正是依靠多功能协议网关,实现了…

韩国站群服务器提供高级安全防护以确保数据和网站的安全性

韩国站群服务器提供高级安全防护以确保数据和网站的安全性 在当今数字化时代,网站的安全性和数据保护已成为企业和个人不可忽视的重要议题。韩国站群服务器作为一个拥有发达科技和互联网基础设施的国家,通过提供高级安全防护措施,为用户的数…

Web服务器和Tomcat

Web介绍 对于http协议操作进行封装、简化web程序开发 部署web项目,对外提供上网信息浏览 Tomcat介绍 一个轻量级的web服务器 也称为web容器 Tomcat的文件夹介绍 下载地址:Apache Tomcat - Apache Tomcat 9 Software Downloads 安装:直…

十个数据安全最佳实践:保护数据的简单方法

在德迅云安全将介绍数据安全的主要原则,并了解适用于大多数行业的 10 种数据安全最佳实践,以及云端安全检测的重要性。 数据威胁和维护数据安全的好处 什么是数据安全? 数据安全是旨在保护组织敏感资产的流程和工具的组合。有价值的数据在…

JavaScript快速入门系列-1(JavaScript简介)

第一章:JavaScript简介 1. JavaScript简介1.1 什么是JavaScript1.2 JavaScript的历史与应用1.3 环境搭建:浏览器与Node.js2. JavaScript语言基础2.1 变量声明:let, const, var2.2 数据类型:字符串、数字、布尔值、对象、数组、null与undefined2.3 运算符:算术、比较、逻辑…

二叉树的前序、中序、后序遍历的C++实现

二叉树的前序、中序、后序 遍历属于深度优先搜索方式&#xff0c;本文使用递归法实现前序、中序、后序的遍历方法&#xff0c;代码如下&#xff1a; #include <iostream> #include <vector>struct TreeNode{int val;TreeNode* left;TreeNode* right;TreeNode(int …

初识C++ · 模板初阶

目录 1 泛型编程 2 函数模板 3 类模板 1 泛型编程 模板是泛型编程的基础&#xff0c;泛型我们碰到过多次了&#xff0c;比如malloc函数返回的就是泛型指针&#xff0c;需要我们强转。 既然是泛型编程&#xff0c;也就是说我们可以通过一个样例来解决类似的问题&#xff0c…

Java基础之《mybatis-plus多数据源配置》

1、pom文件引入依赖 引入MyBatis-Plus之后请不要再次引入MyBatis以及mybatis-spring-boot-starter和MyBatis-Spring&#xff0c;以避免因版本差异导致的问题 <!--引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 mybatis-spring-boot-starter和MyBatis-Spring&#xff0…

【C++】STL_ string的使用 + 模拟实现

前言 目录 1. STL简介&#xff08;1&#xff09;什么是STL&#xff08;2&#xff09;STL的版本&#xff08;3&#xff09;STL的六大组件 2. string的使用2.1 npos2.2 遍历字符串string的每一个字符2.3 迭代器&#xff1a;2.4 string的内存管理2.5 string模拟实现2.5.1 深拷贝&a…

Redis(主从复制搭建)

文章目录 1.主从复制示意图2.搭建一主多从1.搭建规划三台机器&#xff08;一主二从&#xff09;2.将两台从Redis服务都按照同样的方式配置&#xff08;可以理解为Redis初始化&#xff09;1.安装Redis1.yum安装gcc2.查看gcc版本3.将redis6.2.6上传到/opt目录下4.进入/opt目录下然…

iptables---防火墙

防火墙介绍 防火墙的作用可以理解为是一堵墙&#xff0c;是一个门&#xff0c;用于保护服务器安全的。 防火墙可以保护服务器的安全&#xff0c;还可以定义各种流量匹配的规则。 防火墙的作用 防火墙具有对服务器很好的保护作用&#xff0c;入侵者必须穿透防火墙的安全防护…

Leetcode—1991. 找到数组的中间位置【简单】

2024每日刷题&#xff08;129&#xff09; Leetcode—1991. 找到数组的中间位置 实现代码 class Solution { public:int findMiddleIndex(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);int prefix 0;for(int i 0; i < nums.size();…

考情分析 | 2025年西北工业大学计算机考研考情分析!

西北工业简称西工大&#xff08;英文缩写NPU&#xff09;&#xff0c;大学坐落于古都西安&#xff0c;是我国唯一一所以同时发展航空、航天、航海工程教育和科学研究为特色&#xff0c;以工理为主&#xff0c;管、文、经、法协调发展的研究型、多科性和开放式的科学技术大学。十…

怎么制作好玩的gif?试试这个工具轻松制作

视频之所以受大众的喜爱是因为有声音、画面的搭配&#xff0c;让观者深入其中体验感会更强。但是视频的体积较大、时长也比较长&#xff0c;给我们的传播和保存造成了一定的影响。那么&#xff0c;我们可以将视频制作成gif图片来使用&#xff0c;不需要下载软件&#xff0c;使用…

最大数字——蓝桥杯十三届2022国赛大学B组真题

问题分析 这道题属于贪心加回溯。所有操作如果能使得高位的数字变大必定优先用在高位&#xff0c;因为对高位的影响永远大于对低位的影响。然后我们再来分析一下&#xff0c;如何使用这两种操作&#xff1f;对于加操作&#xff0c;如果能使这一位的数字加到9则变成9&#xff0…

UE5自动生成地形一:地形制作

UE5自动生成地形一&#xff1a;地形制作 常规地形制作地形编辑器地形管理添加植被手动修改部分地形的植被 置换贴图全局一致纹理制作地貌裸露岩石地形实例 常规地形制作 地形制作入门 地形导入部分 选择模式&#xff1a;地形模式。选择地形子菜单&#xff1a;管理->导入 …

STC8增强型单片机开发——C51版本Keil环境搭建

一、目标 了解C51版本Keil开发环境的概念和用途掌握C51版本Keil环境的安装和配置方法熟悉C51版本Keil开发环境的使用 二、准备工作 Windows 操作系统Keil C51 安装包&#xff08;可以从Keil官网下载&#xff09;一款8051单片机开发板 三、搭建流程 环境搭建的基本流程&#xf…

思维导图网页版哪个好?2024年值得推荐的8个在线思维导图软件!

思维导图如今已成为一种常用的工具&#xff0c;帮助我们清晰地组织和整理信息。随着科技的发展&#xff0c;思维导图的产品形态也经过多轮迭代&#xff0c;从最初的本地客户端过渡到基于云的 Web 端&#xff0c;各类网页版思维导图软件应运而生&#xff0c;它们方便快捷&#x…

【Linux】gcc/g++的使用

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解Linux中gcc/g使用的相关内容。 如果看到最后您觉得这篇文章写得不错…