【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 方程进行 雷诺平均,通过将流动场的瞬时变量分解为…

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

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

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

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

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

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

关闭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…

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 二、开始制作,有多种创建方式,分别是&…

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

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

ASP.NET Core API + MySql

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

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

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

item2 for macos

安装Item2 brew install iterm2 查看终端类型 cat /etc/shells Mac OS X 10.15 已经将默认的shell从Bash换成了zsh,所以不用安装,10.15以前的可以使用下面的命令进行安装 brew install zsh 安装Oh My ZSH # curl sh -c "$(curl -fsSL https://ra…

Pytest-Bdd-Playwright 系列教程(14):Docstring 参数

Pytest-Bdd-Playwright 系列教程(14):Docstring 参数 前言一、什么是docstring?二、基本语法三、主要特点四、实际例子五、注意事项六、使用建议总结 前言 在自动化测试的过程中,我们经常需要处理复杂的测试数据或需要输入多行文…

手机租赁系统开发指南一站式服务流程解析

内容概要 手机租赁系统的开发是一个复杂但有趣的过程,像搭建乐高一样,只要找到合适的模块,就能打造出一个宾至如归的租赁平台。在这部分,我们将对开发流程的整体结构进行简要概述,并指出每个环节的重要性。 首先&…

OpenAI 正式赋予 ChatGPT 通过视频实时与用户互动的能力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

EasyExcel设置表头上面的那种大标题(前端传递来的大标题)

1、首先得先引用easyExcel的版本依赖&#xff0c;我那 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version> </dependency> 2、然后得弄直接的实体类&#xff0c;&…

纯血鸿蒙崛起,原生Android挑战?两大操作系统巅峰对决,智能设备未来谁主沉浮?

鸿蒙HarmonyOS和原生Android系统虽然在一些方面相似&#xff0c;但在架构、设计理念、API、开发工具等方面存在一些差异。鸿蒙系统的目标是跨设备、分布式的操作系统&#xff0c;强调多设备协同和资源共享&#xff0c;而Android则主要集中在智能手机和移动设备领域。 下面将从…