【JavaEE初阶系列】——网络编程 UDP客户端/服务器 程序实现

目录

🚩UDP和TCP之间的区别

🎈TCP是有连接的 UDP是无连接的

🎈TCP是可靠传输 UDP是不可靠传输

🎈TCP是面向字节流 UDP是面向数据报

 🎈TCP和UDP是全双工

👩🏻‍💻UDP的socket api使用

💻DatagramSocket API

💻DatagramSocket 方法

💻DatagramPacket API

💻InetSocketAddress API

🎓UDP客户端/服务器 通信程序实现

🔴服务器

📝接收客户端发来的请求,并且解析

📝根据请求返回响应

📝创建一个DatagramPacket类, 存入数据,并发送给客户端

📝打印日志

🔴客户端 


通过网络,让俩个主机之间进行通信,基于这样的通信来完成一定的功能。

进行网络编程的时候,需要操作系统给咱们提供一组api,通过这种api才能完成编程。

api可以认为是应用层和传输层之间交互的路径。socket api就相当于插座一样,通过这一套socket api可以完成不同软件之间,不同操作系统之间的通信。


传输层,提供的协议,主要有2个,TCP和UDP这俩个。TCP和UDP这俩个协议的特性(工作原理) 差异很大,导致,使用俩种协议进行网络编程,也存在一定差别,系统就分别提供俩种api。


🚩UDP和TCP之间的区别

🎈TCP是有连接的 UDP是无连接的

TCP是有连接的,UDP是无连接的。什么是有连接和无连接呢?此处的连接本质上就是建立连接的双方,各自保存对方的信息,俩台计算机建立连接,就是双方彼此保存了对方的关键信息。TCP要想通信,就需要先建立连接(所谓连接就是保存对方的信息),做完之后,才能后续通信。(如果A和B建立连接,但是B拒绝了,通信就无法完成了),UDP想要通信,就直接发送数据就行了,不需要建立连接,也就是不需要保存对方的信息。虽然UDP本身是不保存的,但是你调用的UDP的socket api的时候要把对方的位置啥的给传过去。后面再 实现TCP就需要在类里初始化IP地址和端口号传入构造方法中,而UDP不用。


🎈TCP是可靠传输 UDP是不可靠传输

TCP里面内置了可靠传输的机制,UDP没有。网络上进行通信,A发送给B消息,这个消息不可能做到100%发送到的,所以什么是可靠传输呢?可靠传输就是A发送给B发信息,消息是不是到达B这一方,A自己能感知到(A心里有数)进一步的,就可以再发送失败的时候采取一定的措施(尝试重传之类的)。而从不可靠传输到可靠传输都是需要付出一些代价的,比如可靠传输的机制比较复杂,传输效率低。

就像一个老中医生有资历给病人看病,看了一下就知道他有什么毛病,只是不说出来,老中医心里有数,然后就去拿药配方进行医治。


🎈TCP是面向字节流 UDP是面向数据报

字节流和文件操作里面的字节流是一个意思,所以我们再实现TCP客户端和服务器之间的通信的时候,就需要用到文件操作里面字节输入流和输出流。

  • TCP是和文件操作一样,以字节为单位来进行传输
  • UDP是按照数据报为单位,来进行传输的。UDP数据报是有严格的格式的。

 🎈TCP和UDP是全双工

  • 一个信道,允许双向通信,就是全双工
  • 一个信道,只能单向通信,就是半双工

代码中使用一个Socket对象,就可以发送数据也能接收数据。

半双工——单向通信

一个管子,只能一边吹气。

但是B 不能给A吹气 ,这就是所谓的单向通信——半双工

全双工——双向通信

一根网线,电流不是只能从一边流向另一边,咋能双向通信呢?

就比如一个道路,我们中间划一道黄线,双向行驶


👩🏻‍💻UDP的socket api使用

💻DatagramSocket API

DatagramSocket UDP Socket ,用于发送和接收 UDP 数据报。
DatagramSocket 构造方法:
方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务器)

为什么服务器要指定端口呢?而客户端不同?

因为服务器是程序员决定的,知道哪些端口是可以用的,这是可控的,客户端是不可控的,每个用户电脑程序不一样,占用的端口也不一样,如果手动指定端口,会产生冲突。所以 客户端交给系统自动分配的。

 socket其实也是操作系统一个概念,本质上是一种特殊的文件,Socket就属于是把"网卡"这个设备,抽象成了文件了,往socket文件中写数据,就相当于通过网卡发送数据,从socket文件读数据,就相当于通过网卡接收数据。这就是网络通信和文件操作统一了。


💻DatagramSocket 方法

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法就会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

receive()和send()方法里面的参数其实是输出型参数,数据报是空的,然后进行填充,并返回。 


💻DatagramPacket API

DatagramPacket UDP Socket 发送和接收的数据报。
DatagramPacket 构造方法:
方法签名方法说明
DatagramPacket(byte[] buf,int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[] buf,int offset,int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

 DatagramPacket 方法:

方法签名方法说明
InetAddress. getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号

byte[] getData() 获取数据报中的数据

构造UDP发送的数据报时,需要传入socketAddress,该对象可以使用InetSocketAddress来创建。


💻InetSocketAddress API

InetSocketAddress SocketAddress 的子类 )构造方法:
方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

🎓UDP客户端/服务器 通信程序实现

这个程序是没有什么业务逻辑,只是单纯的调用socket api .让客户端给服务器发送一个请求,请求就是一个从控制台输入的字符串,服务器收到字符串之后,也就会把这个字符串原封不动的返回客户端,客户端再显出来。——回显服务器(echo server)


🔴服务器

📝接收客户端发来的请求,并且解析

 public UdpEchoServer(int port) throws SocketException {socket=new DatagramSocket(port);//服务器需要指定端口}

服务器和客户端都需要创建Socket对象。

  • 服务器的socket一般要显示的指定一个端口号
  • 客户端的socket一般不能显式指定(不显示指定,此时系统会自动分配一个随机的端口)

//接收请求之前,我们需要开辟一个空间存储要求DatagramPacket requestSocket=new DatagramPacket(new byte[4096],4096);socket.receive(requestSocket);

DatagramPacket这个对象用来承载从网卡这边读到的数据,收到数据的时候,需要搞一个内存空间来保存这个数据,DatagramPacket内部不能自行分配内存空间,因此就需要程序员手动把孔吉纳创建好,交给DatagramPacket进行处理。

服务器一旦启动,就会立即执行到这里的receive方法,此时客户端的请求还没来,这种情况也是没有关系的,receive就会直接阻塞,就会一直阻塞到真正客户端把请求发过来为止。


 //由于接收到的请求是二进制,我们需要转换成字符串String request=new String(requestSocket.getData(),0,requestSocket.getLength());

这个getLength 得到的结果是否是上述的4096?这个结果是收到的数据的真实长度(取决于发送方这一次到底发送了多少数据。取这个区间内的字节,构成一个Stirng。


📝根据请求返回响应

 //2.根据请求返回响应String response=new String(request);
 public String  process(String request){return request;}

 这个步骤是一个服务器程序,最核心的步骤!咱们当时是echo server不涉及这些流程,也不必考虑响应怎么计算,只要请求过来,就把请求当作响应。


📝创建一个DatagramPacket类, 存入数据,并发送给客户端

 UDP是无连接的,UDP自身不会保存数据要发给谁,就需要每次发送的时候,重新指定,数据要发到哪里去。上述创建数据报是存入发来的请求。

    //3.创建一个DatagramPacket类, 存入数据,并发送给客户端//requestSocket.getSocketAddress() requestSocket里面包含客户端的IP地址和端口号DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestSocket.getSocketAddress());socket.send(responsePacket);

 构造这个数据报,需要指定数据内容,也指定一下数据报要发给谁。再网络传输的时候,肯定是要使用字节的。

  • 可以让response.getBytes().length改成response.length()嘛?不行的,本质上也是和字符集有关系的。如果你这个字符串里内容都是英文字符,此时字节和字符个数是一样的,如果包含中文就不一样的。
  • requestSocket.getSocketAddress()指定一下请求中的地址(数据从哪里来,我们就要到哪里去)包含IP地址和端口号

📝打印日志

//打印一个日志 打印 客户端IP 客户端端口 客户端内容  服务器内容System.out.printf("[%s:%d] %s,%s",responsePacket.getAddress(),responsePacket.getPort(),request,response);

package UDP;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {DatagramSocket socket=null;public UdpEchoServer(int port) throws SocketException {socket=new DatagramSocket(port);//服务器需要指定端口}public void start() throws IOException {System.out.println("服务器开始启动->");while (true){//1.接收客户端发来的请求,并且解析//接收请求之前,我们需要开辟一个空间存储要求DatagramPacket requestSocket=new DatagramPacket(new byte[4096],4096);//然后接收请求(如果客户端还没发来请求,就阻塞等待)socket.receive(requestSocket);//由于接收到的请求是二进制,我们需要转换成字符串String request=new String(requestSocket.getData(),0,requestSocket.getLength());//2.根据请求返回响应String response=new String(request);//3.创建一个DatagramPacket类, 存入数据,并发送给客户端//requestSocket.getSocketAddress() requestSocket里面包含客户端的IP地址和端口号DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestSocket.getSocketAddress());socket.send(responsePacket);//打印一个日志 打印 客户端IP 客户端端口 客户端内容  服务器内容System.out.printf("[IP地址:%s 端口号:%d] request=%s response=%s",responsePacket.getAddress(),responsePacket.getPort(),request,response);}}public String  process(String request){return request;}public static void main(String[] args) throws IOException {UdpEchoServer udpEchoServer=new UdpEchoServer(9090);udpEchoServer.start();}
}

🔴客户端

客户端做的事情就是 发出请求,尝试得到服务器返回的响应

  • 1.将输入的字符串转换成请求,并发送给服务器
  • 2.发出请求之后,我们就要创建一个数据报,存储由服务器返回的请求,尝试返回请求
  • 3.将响应转换成字符串,并响应出来
package UDP;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UDPClient {DatagramSocket socket=null;String serverIp="";int serverPort=0;public UDPClient(String serverIp, int serverPort) throws SocketException {socket = new DatagramSocket();this.serverIp = serverIp;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("客户端开始启动");Scanner scanner=new Scanner(System.in);while (true){//1.将输入的字符串转换成请求,并发送给服务器String request=scanner.next();DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort);socket.send(requestPacket);//2.尝试返回服务器的响应DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);//3.将响应转换成字符串,并响应出来String response=new String(responsePacket.getData(),0,responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UDPClient udpClient=new UDPClient( "10.41.90.105",9090);udpClient.start();}
}

我们写完UDP的服务器和客户端的代码之后,为什么不close?就是关闭数据报套接字

socket也是文件,不关闭就会出问题了,就会出现文件资源泄漏嘛?(资源泄漏就是代码中频繁的打卡文件,但是不关闭,在一个进程的运行过程中,不断积累打开的文件,逐渐消耗掉文件描述符表里的内容,最终就消耗没了,如果进程的生命周期很短,打开一下没多久就关闭了,谈不上泄漏)

socket是文件描述符表中的一个表项,每次打开一个文件,就要占用一个位置。文件描述符,是在pdb上的。(跟随进程的)

这个socket在整个程序运行过程中都是需要使用的(不能提前关闭)当socket不需要使用的时候,意味着程序就要结束了,进程结束,此时随之文件描述符就会销毁了(pcb都销毁了)。随着销毁的过程,被系统自动回收了。

先启动服务器,再启动客户端

 

 


只要跑得足够久,所有的雨都是阵雨。 

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

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

相关文章

共享IP和独享IP如何选择,两者有何区别?

有跨境用户在选择共享IP和独享IP时会有疑问,不知道该如何进行选择,共享IP和独享IP各有其特点和应用场景,选择哪种方式主要取决于具体需求和预算。以下是对两者的详细比较: 首先两者的主要区别在于使用方式和安全性:共…

使用c语言libexpat开源库解析XML数据

1 libexpat简介 Expat 是一个用 C 语言编写的开源 XML 解析库,以其高性能和小巧的体积著称。Expat 兼容多种操作系统平台,包括但不限于 Windows、Linux、macOS 等。由于其跨平台特性和简单易用的API,Expat 成为了许多C/C程序员解析XML文档的…

git安装配置教程(小白保姆教程2024最新版)

目录 一、Git是什么?二、安装Git1.下载git2.安装git3.检测git 三、配置Git1.配置本地信息2.配置SSH1)SSH与SSH Key是什么?2)生成SSH Key3)获取ssh key公钥内容(id_rsa.pub)4)Github账号上添加公…

【java数据结构-二叉树(上)】

java数据结构-二叉树(上) 二叉树的概念二叉树的节点介绍 二叉树构造如何使用兄弟表示法构造二叉树两种特别的二叉树二叉树的基本性质: 二叉树的存储二叉树的遍历:前序遍历:中序遍历:后序遍历:层…

【随笔】Git 基础篇 -- 远程仓库 git clone(二十五)

💌 所属专栏:【Git】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! 💖 欢迎大…

如何本地搭建开源导航页配置服务Dashy并发布到公网分享好友使用

文章目录 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默,忍不住分享一下给大家。[点击跳转到网站] 简介 Dashy 是…

学习C++有没有必要学习boost库?

在深入学习C这一强大且灵活的编程语言的过程中,是否有必要学习Boost库是许多开发者会面临的一个重要问题。Boost库,被誉为C的“瑞士军刀”,以其丰富的工具集和强大的功能性深受广大C程序员的喜爱。本文将就此问题进行详细的探讨。 一、Boost…

前端开发基础(HTML5 + CSS3)【第一篇】:HTML标签之文字排版、图片、链接、音频、视频 涵盖了两个综合案例 做到了基础学得会,实战写的出

点击前往前端开发基础专栏: 文章目录 HTML5 CSS3 开发一、开发环境搭建下载 VS Code1. 2 插件的下载1.3 项目和文件的下载 二、 什么是 HTML2.1 标签的语法2.2 代码演示:2.3 小结 三 、HTML基本骨架3.1 快捷键生成HTML骨架3.2 代码展示3.3 小结 四、标…

阿里淘天一面凉经

电话面,秒挂。 由于答的依托。导致面试官一开始就准备要挂我了。后面问的参考性不大。 总结: 1.自我介绍 2.项目里自己体会比较多的,遇到困难比较大的技术实现。(没复习) 3.项目中什么场景下用到分布式锁&#xf…

【Vit】Vision Transformer 入门与理解

在学习VIT之前,建议先把 Transformer 搞明白了:【transformer】入门与理解 做了那些改进? 看图就比较明白了,VIT只用了Encoder的部分,把每一个图片裁剪成若干子图,然后把一个子图flatten一下,…

【MATLAB源码-第12期】基于matlab的4FSK(4CPFSK)的误码率BER理论值与实际值仿真。

1、算法描述 4FSK在频移键控(FSK)编码的基础上有所扩展。FSK是一种调制技术,它通过在不同频率上切换来表示不同的数字或符号。而4FSK则是FSK的一种变种,表示使用了4个不同的频率来传输信息。 在4FSK中,每个数字或符号…

基于Java的图书借阅网站, java+springboot+vue开发的图书借阅管理系统 - 毕业设计 - 课程设计

基于Java的图书借阅网站, javaspringbootvue开发的图书借阅管理系统 - 毕业设计 - 课程设计 文章目录 基于Java的图书借阅网站, javaspringbootvue开发的图书借阅管理系统 - 毕业设计 - 课程设计一、功能介绍二、代码结构三、部署运行1、后端运行步骤2、…

PaddleDetection 项目使用说明

PaddleDetection 项目使用说明 PaddleDetection 项目使用说明数据集处理相关模块环境搭建 PaddleDetection 项目使用说明 https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.7/configs/ppyoloe/README_cn.md 自己项目: https://download.csdn.net/d…

Cheat Engine ceserver 连接手机记录

按照流程 电脑端的 cheat engine 7.5不显示任何内容 换一个 cheatengine 就好了 真神奇 链接:https://pan.baidu.com/s/14nMRHPEJ7enygI2nQf86YQ?pwdkxma 提取码:kxma

C++ stl容器vector的底层模拟实现

目录 前言: 1.成员变量,容量与大小 2.构造函数 无参构造: 带参的使用值进行构造: 使用迭代器区间进行构造: 3.交换 4.拷贝构造 5.赋值重载 6.迭代器 7.扩容 reserve: resize: 8.…

通过pre标签进行json格式化展示,并实现搜索高亮和通过鼠标进行逐个定位的功能

功能说明 实现一个对json进行格式化的功能添加搜索框,回车进行关键词搜索,并对关键词高亮显示搜索到的多个关键词,回车逐一匹配监听json框,如果发生了编辑,需要在退出时提示,在得到用户确认的情况下再退出…

30天精通Linux系统编程-----第一天:底层文件I/O (建议收藏)

目录 1.什么是底层文件I/O 2.底层文件I/O常用库函数 2.1 write函数 2.2 read函数 2.3 open函数 2.4 close函数 2.5 lseek函数 2.6 ioctl函数 2.7 fcntl()函数 2.8 pread()函数 2.9 pwrite()函数 1.什么是底层文件I/O 底层I/O指的是与硬件设备之间的直接输入输出操作…

Pytest精通指南(04)前后置和测试用例执行优先级

文章目录 Pytest 固件核心概念Pytest 固件原理Pytest 固件分类方法级函数级类级模块级夹具优先级测试用例执行优先级固件不仅如此后续大有文章 Pytest 固件核心概念 在 pytest 测试框架中,固件是一个核心概念; 它是一种特殊的函数,用于在测试…

蓝桥杯物联网竞赛_STM32L071KBU6_全部工程及国赛省赛真题及代码

包含stm32L071kbu6全部实验工程、源码、原理图、官方提供参考代码及国、省赛真题及代码 链接:https://pan.baidu.com/s/1pXnsMHE0t4RLCeluFhFpAg?pwdq497 提取码:q497

【Python】报错ModuleNotFoundError: No module named fileName解决办法

1.前言 当我们导入一个模块时: import xxx ,默认情况下python解释器会搜索当前目录、已安装的内置模块和第三方模块。 搜索路径存放在sys模块的path中。【即默认搜索路径可以通过sys.path打印查看】 2.sys.path.append() sys.path是一个列表 list ,它里…