【JavaEE】网络(2)

一、网络编程套接字

1.1 基础概念

【网络编程】指网络上的主机,通过不同的进程,以编程的方式实现网络通信;当然,我们只要满足进程不同就行,所以即便是同一个主机,只要是不同进程,基于网络来传输数据,也属于网络编程
套接字其实是socket的直译,套接字就是传输层给应用层提供的网络编程API(接口)通过这个接口,应用层程序可以通过这个接口使用传输层提供的服务,而不需要知道它的具体实现

套接字分为两类:流式套接字数据报套接字

流式套接字是基于TCP协议(一个传输层协议)实现的,TCP是一种面向连接型可靠传输型面向字节流全双工的传输层协议,流式套接字利用这些特性为应用层提供了一个简单的接口,用于发送和接收数据流

数据报套接字是基于UDP协议(也是一个传输层协议)实现的,UDP是一种面向无连接型不可靠传输型面向数据报全双工的传输层协议

1.2 协议特点

接下来讲解以下上述提到的 TCP协议和UDP协议的特点

1)面向有连接型 vs 面向无连接型:通过网络发送数据分为面向有连接和面向无连接

有连接指在发送数据之前,发送端要先和接收端建立一条逻辑意义上的连接,连接建好后才能真正发送数据,数据发送完毕后要断开连接;

就好比打电话,在说话之前,对方要先同意接听,接听并说完话后再挂断电话

无连接则无需考虑建立连接和断开连接,发送端可以在任何时候发送数据,接收端不知道自己会在何时收到数据,所以要时常检查是否收到数据;

这个就像发送电子邮件,发送端可以随时发送,无需让接收端同意,接收端则要时常检查是否有收到邮件

2)可靠传输 vs 不可靠传输

可靠传输指将要传输的数据尽可能的传输给对方,在网络通信的过程中,会存在"丢包"的情况:A给B传输10个数据报,B收到了9个;

原因是A传输给B,中间可能会经历很多交换机和路由器,这些交换机和路由器不只是转发你的数据,要转发很多数据,当数据很多时,可能会超过它们自身的硬件水平,此时多出来的数据无法转发,会被直接丢弃掉。

TCP为了对抗丢包,内部实现了一些机制(重发)来实现可靠传输(机制后面会详细讲)

不可靠传输指再出现丢包后,也不负责重发,不可靠传输更注重效率,在一些注重效率,对准确性要求不高的场景使用不可靠传输,可靠传输能尽可能保证数据传给接收端,但效率上会大打折扣

3)面向字节流 vs 面向数据报

面向字节流指传输的数据以字节为单位

面向数据报指传输的数据以数据报为单位,传输数据是一个一个数据报,一次读写只能读写完整的数据报,不能读写半个

4)全双工 vs 半双工

全双工指一条链路,能够进行双向通信,后续代码创建socket对象,既可以读(接收)也可以写(发送)

半双工指一条链路,只能进行单向通信

二、UDP-数据报套接字编程

socket API 是由传输层给应用层提供的API,传输层是封装于操作系统内核态的,由操作系统内核直接管理,所以可以理解为socket api是由操作系统内核管理的,而Java对于系统这些API进行了封装,所以使得用户程序可以直接使用这些API

UDP的socket API 有两个重要的类

2.1 DatagramSocket

属于UDP Socket,创建DatagramSocket的对象就可以发送和接收UDP数据报,先来看构造方法

构造方法描述
DatagramSocket( )创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口
DatagramSocket( int port )创建一个UDP数据报套接字的Socket,绑定到本机指定的端口号

普通方法:

普通方法描述
void receive (DatagramPacket p)接收数据报,如果没有接收到,该方法就会阻塞等待
void send(DatagramPacket p)发送数据报,不会阻塞等待,直接发送(无连接)
void close( )关闭此数据报套接字

当创建一个套接字时,系统会为其分配资源绑定端口号,如果用完不关闭则会导致资源持续被占用

2.2 DatagramPacket

表示UDP Socket发送和接收的数据报,一个DatagramPacket对象就相当于一个UDP数据报

构造方法描述
DatagramPacket (byte[] buf, int length)构造⼀个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第⼀个参数buf)中,接收指定长度(第⼆个参数length)

DatagramPacket(byte[] buf, int offset, int length, 

SocketAddress address)

构造⼀个DatagramPacket以用来发送数据报,发送的数据为字节数组(第⼀个参数buf)中,从0到指定⻓ 度(第⼆个参数length)address指定⽬的主机的IP 和端⼝号

上述方法可以结合下述代码理解

2.3 模拟回显服务器

回显服务器指客户端发送一个请求给服务端,服务端将这个请求原封不动的作为相应返回给客户端,这就叫回显(请求啥相应就是啥),接下来先编写服务器程序:

public class UdpEchoServer {public DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket =  new DatagramSocket(port); //创建 UDP Socket 并绑定一个端口号}}

服务器需要在程序启动的时候,把在服务器程序的端口号确定下来,客户端发送请求时需要知道服务器的IP地址(服务器所在主机的IP)、端口号port

服务器要能够接收客户端发送的数据,socket  receive( );需要向receive传入一个UDP数据报

public class UdpEchoServer {public DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket =  new DatagramSocket(port);}public void start() throws IOException {//1) 接收请求DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);//此时创建好的requestPacket 是一个空的数据包//requestPacket包含两个部分1.报头 2.载荷//字节数组用来存储数据socket.receive(requestPacket); //客户端会send一个数据包, 就会跳转到这里//此时由requestPacket 是一个预留好空间的空数据包// 为了方便在 java 代码中处理 (尤其是后面进行打印) 可以把上述数据报中的二进制数据, 拿出来, 构造成 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength());}}

接收来自客户端的请求后,经过处理后将响应返回给客户端,那么该如何知道应该给哪个客户端返回响应,在我们receive接收到的数据包里就包含了这个数据包来自于哪个IP,来自于哪个端口号(客户端)

// 2) 根据请求计算响应
String response = this.process(request);
// 3) 把响应写回到客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length, requestPacket.getSocketAddress());
socket.send(responsePacket);

requestPacket.getSocketAddress() 这个方法返回的对象里就包含了客户端的IP地址和端口号

上述代码干的事情就是将字符串类型的二进制数据再构造会UDP数据包并发送给客户端

服务端完整代码如下:

public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {Scanner scanner = new Scanner(System.in);System.out.println("服务器启动!");while (true) { // 服务器需要7*24小时持续接收并处理请求// 1) 读取请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);//receive方法中的requestPacket是一个空的数据包,客户端程序通过send方法发送有数据的数据包后//会直接跳转到这里的receive方法,而这里的requestPacket是一个预留好空间的空数据包// 为了方便在 java 代码中处理 (尤其是后面进行打印) 可以把上述数据报中的二进制数据, 拿出来, 构造成 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength());//将字节数组构造成String类的对象// 2) 根据请求计算响应String response = this.process(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 process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

接下来写客户端代码:

首先客户端需要知道服务器的IP和端口号,端口号是我们之前就设置的9090,IP用127.0.0.1,当服务器和客户端在一个主机上,就用环回IP,这是系统提供的特殊的IP

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {socket = new DatagramSocket();// 这俩信息需要额外记录下来, 以备后续使用.this.serverIp = serverIp;this.serverPort = serverPort;}
}

上述构造socket对象没有指定端口号,这样操作系统会分配一个空闲的端口号,这个端口号每次重新启动程序都不一样

// 1. 从控制台读取用户输入
String request = scanner.next();
// 2. 构造请求并发送
// 构造请求数据报的时候, 不光要有数据, 还要有 "目标 "
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length, InetAddress.getByName(serverIp), serverPort);
socket.send(requestPacket); //发送数据包

上述InetAddress.getByName(serverIp)是将字符串格式的IP地址转成Java能识别的InetAddress对象

发送完数据包,服务器经过处理返回响应,客户端就要接收响应

// 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);

在第2步执行完send后,客户端程序紧接着到第三步的receive,由于从发送请求到返回响应需要些时间,所以这里receive会阻塞,阻塞到接收到服务器返回响应

完整的客户端代码如下:

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpEchoClient(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) {System.out.print("请输入要发送的请求: ");// 1. 从控制台读取用户输入String request = scanner.next();// 2. 构造请求并发送// 构造请求数据报的时候, 不光要有数据, 还要有 "目标"DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,InetAddress.getByName(serverIp), serverPort);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);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);// UdpEchoClient client = new UdpEchoClient("139.155.74.81", 9090);client.start();}
}

接下来启动服务器程序和客户端程序:

客户端可以不断发送请求并得到响应

服务端会不断处理客户端的请求

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

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

相关文章

RANS(Reynolds-Averaged Navier-Stokes) 湍流模型类型

RANS(Reynolds-Averaged Navier-Stokes) 湍流模型有多种不同的类型,除了标准的 kkk-ω 湍流模型,还有其他一些常用的湍流模型。RANS 模型的核心思想是对 Navier-Stokes 方程进行 雷诺平均,通过将流动场的瞬时变量分解为…

JS中this的值详细讲解以及面试指向练习

this 的值取决于它出现的上下文:函数、类或全局。 在函数内部,this 的值取决于函数如何被调用,this 是语言在函数体被执行时为你创建的绑定 对于典型的函数,this 的值是函数被访问的对象。换句话说,如果函数调用的形…

2024年河南省高等职业教育技能大赛 大数据分析与应用赛项竞赛方案

2024年河南省高等职业教育技能大赛 大数据分析与应用赛项竞赛方案 一、赛项名称 赛项名称:大数据分析与应用 赛项编号:HN033 赛项组别:专业核心基本技能赛项 专业大类:电子与信息等 竞赛形式:学生组(团体赛…

vue绕过rules自定义编写动态校验

今天犯了个低级错误,虽然走了很多弯路,但这个过程还是值得记录一下 例子如下,有两个输入框: 第一个是套餐选择下拉框,可以下拉选择三个内容 第二个要根据上面的套餐选择三个选项来决定怎么显示,使用v-if&…

数字化招聘系统如何帮助企业实现招聘效率翻倍提升?

众所周知,传统的招聘方式已经难以满足现代企业对人才的需求,而数字化招聘系统的出现,为企业提供了全新的解决方案。通过数字化招聘系统,企业可以自动化处理繁琐的招聘流程,快速筛选合适的候选人,从而大幅提…

短视频矩阵源码开发部署全流程解析

在当今的数字化时代,短视频已成为人们娱乐、学习和社交的重要方式。短视频矩阵系统的开发与部署,对于希望在这一领域脱颖而出的企业和个人而言,至关重要。本文将详细阐述短视频矩阵源码的开发与部署流程,并附上部分源代码示例&…

华为云云原生中间件DCS DMS 通过中国信通院与全球IPv6测试中心双重能力检测

近日,中国信息通信研究院(以下简称“中国信通院”)与全球IPv6测试中心相继宣布,华为云的分布式缓存服务(Distributed Cache Service,简称DCS)和分布式消息服务(Distributed Message …

关闭WPS在线功能资源和功能推荐

Kingsoft\WPS Office\12.1.0.18912\office6 选择 【高级】 点击 【确定】

Polars数据聚合与旋转实战教程

在这篇博文中,我们的目标是解决数据爱好者提出的一个常见问题:如何有效地从Polars DataFrame中创建汇总视图,以便在不同时间段或类别之间轻松进行比较。我们将使用一个实际的数据集示例来探索实现这一目标的各种方法。 Polars简介 Polars 是…

2024154读书笔记|《带着诗歌上街去》——我不长叶子,不开花,也不必要什么结果

2024154读书笔记|《带着诗歌上街去》——我不长叶子🌿,不开花🌼,也不必要什么结果 《带着诗歌上街去》作者隔花人,作者很有巧思,在拍摄的照片上做诗,诗不是很有感觉,但是在墙上、风景…

建立基于TCP的客户端和服务端

函数介绍: 1.socket() 作用:创建套接字 domain: AF_INET:IPv4 Internet 协议族。AF_INET6:IPv6 Internet 协议族。AF_UNIX:Unix 域协议族,用于在同一台主机上的进程间通信。 type: SOCK_STREAM&#xff1a…

CNCF云原生生态版图-分类指南(三)- 运行时

CNCF云原生生态版图-分类指南(三)- 运行时 CNCF云原生生态版图-分类指南三、运行时(Runtime)(一)云原生存储(Cloud Native Storage)1. 是什么?2. 解决什么问题&#xff1…

机器学习经典算法

机器学习经典算法学习和分享。 k近邻算法 线性回归 梯度下降法 PCA主成分分析法 多项式回归 逻辑回归 支撑向量机SVM 决策树 随机森林 评价分类指标

MVC基础——市场管理系统(三)Clean Architecture

文章目录 项目地址五、Clean Architecture5.1 user cage driven5.1.1创建CoreBusiness 5.2 创建UseCases5.2.1 创建CategoriesUseCases1. 创建VeiwCategoriesUseCase获取所有Cagegory 5.2.2. 实现ICategoryRepository接口3. 实现获取所有Category的方法4. 实现获取一个Cagegory…

手机上和电脑上都能观看的翻页电子书是如何制作的?

想知道手机上和电脑上都能观看的翻页电子书是都是如何制作的? 想知道这样的电子书是怎样呈现出来的? 那收藏这篇文章,我来跟大家说说该如何实现。 操作方法 一、登录FLBOOK 二、开始制作,有多种创建方式,分别是&…

ABAP时间戳与日期时间转换及时区处理

一、时间戳转换为日期时间 1. 基本转换 CONVERT TIME STAMP <fs_back>-lastchangedatetime TIME ZONE sy-zonloINTO DATE DATA(lv_date)TIME DATA(lv_time).2. 解决8小时时差问题的方案 方案1&#xff1a;直接使用UTC时区&#xff08;推荐&#xff09; CONVERT TIME …

Java 实现给pdf文件指定位置盖章功能

Java 实现给pdf文件指定位置盖章功能 开发中遇到一个需求, 需要给用户上传的的pdf文件, 指定位置上盖公章的功能, 经过调研和对比, 最终确定实现思路. 这里是使用pdf文件中的关键字进行章子的定位, 之所以这样考虑是因为如果直接写死坐标的话, 可能会出现因pdf大小, 缩放, 盖章…

ASP.NET Core API + MySql

环境 数据库&#xff1a; mysql8.0 后端&#xff1a; vs2022 ASP.NET Core API .net 8 前端&#xff1a; Hbuilderx bootstrap 5.3.0 jquery v3.7.1 bootstrap-table 1.23.5 创建项目 添加资源包 AutoMapper Microsoft.EntityFrameworkCore.Tools 8.0.0 Pomelo.EntityFramew…

RFDiffusion 计算键角函数get_ang解读

get_ang 函数&#xff08;kinematics.py包中&#xff09;计算三组原子 a,b,c 所形成的平面角&#xff08;planar angle&#xff09;&#xff0c;即 b 为顶点&#xff0c; a,b,c 所确定的角度。 源代码&#xff1a; def get_ang(a, b, c):"""calculate planar …

Bananna Pi开源社区联合矽昌通信打造开源的低成本Wifi5路由器

香蕉派 BPI-Wifi5 路由器采用矽昌SF19A2890S2芯片方案设计。它是一款高性能无线路由器&#xff0c;适用于小微企业、家庭和其他网络环境。Banana Pi开源社区提供整体解决方案。所有代码开源&#xff0c;用户可以在上面自由开发自己的应用。 Banana Pi wifi5 路由器github代码: …