【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.rhkb.cn/news/490047.html

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

相关文章

《操作系统 - 清华大学》7 -1:全局页面置换算法:局部页替换算法的问题、工作集模型

文章目录 1. 局部页替换算法的问题2. 全局置换算法的工作原理3. 工作集模式3.1 工作集3.2 工作集的变化 4 常驻集 1. 局部页替换算法的问题 局部页面置换算法 OPT,FIFO,LRU,Clock 等等,这些算法都是针对一个正在运行的程序来讲的…

SpringCloud和Nacos的基础知识和使用

1.什么是SpringCloud ​   什么是微服务? ​   假如我们需要搭建一个网上购物系统,那么我们需要哪些功能呢?商品中心、订单中心和客户中心等。 ​   当业务功能较少时,我们可以把这些功能塞到一个SpringBoot项目中来进行…

LLMs之APE:基于Claude的Prompt Improver的简介、使用方法、案例应用之详细攻略

LLMs之APE:基于Claude的Prompt Improver的简介、使用方法、案例应用之详细攻略 目录 Prompt Improver的简介 0、背景痛点 1、优势 2、实现思路 Prompt优化 示例管理 提示词评估 Prompt Improver的使用方法 1、使用方法 Prompt Improver的案例应用 1、Kap…

CMake简单使用(二)

目录 五、scope 作用域5.1 作用域的类型5.1.1 全局作用域5.1.2 目录作用域5.1.3 函数作用域 六、宏6.1 基本语法6.2 演示代码 七、CMake构建项目7.1 全局变量7.2 写入源码路径7.3 调用子目录cmake脚本7.4 CMakeLists 嵌套(最常用) 八、CMake 与库8.1 CMake生成动静态库8.1.1 动…

ASP.NET |日常开发中读写XML详解

ASP.NET |日常开发中读写XML详解 前言一、XML 概述1.1 定义和结构1.2 应用场景 二、读取 XML 文件2.1 使用XmlDocument类(DOM 方式)2.2 使用XmlReader类(流方式) 三、写入 XML 文件3.1 使用XmlDocument类3.2 使用XmlWr…

自动化测试之单元测试框架

单元测试框架 一、单元测试的定义 1:什么是单元测试? 还记不记得我们软件测试学习的时候,按照定义:单元测试就是对单个模块或者是单个函数进行测试,一般是开发做的,按照阶段来分,一般就是单元…

JAVA爬虫获取1688关键词接口

以下是使用Java爬虫获取1688关键词接口的详细步骤和示例代码: 一、获取API接口访问权限 要使用1688关键词接口,首先需要获取API的使用权限,并了解接口规范。以下是获取API接口的详细步骤: 注册账号:在1688平台注册一…

【游戏设计原理】8 - 霍华德的隐匿性游戏设计法则

1. 霍华德的隐匿性游戏设计法则 霍华德的隐匿性游戏设计法则的核心思想是:“秘密的重要性与其表面上的无辜性和完整度成正比”。这意味着,当游戏开始时,设计上越是简洁、无害、直观的元素,隐藏的深层意义和转折就会显得更加震撼和…

k8s中用filebeat文件如何收集不同service的日志

以下是一个详细的从在 Kubernetes 集群中部署 Filebeat,到实现按web-oper、web-api微服务分离日志并存储到不同索引的完整方案: 理解需求:按服务分离日志索引 在 Kubernetes 集群中,有web-oper和web-api两种微服务,希…

前端退出对话框也就是点击右上角的叉,显示灰色界面,已经解决

文章目录 遇到一个前端bug,点击生成邀请码 打开对话框 然后我再点击叉号,退出对话框,虽然退出了对话框,但是显示灰色界面。如下图: 导致界面就会失效,点击任何地方都没有反应。 发现是如下代码的问题&am…

一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测

一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测 目录 一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现INFO-CNN-SVM向量加权算法优化卷积神经网络结…

【Stable Diffusion】SD安装、常用模型(checkpoint、embedding、LORA)、提示词具、常用插件

Stable Diffusion,一款强大的AI模型,让我们能够创造出惊人的艺术作品。本文将为您介绍如何安装Stable Diffusion以及深入使用的学习教程。 1. 安装Stable Diffusion (需要的小伙伴可以文末自行扫描获取) Stable Diffusion的安装可能是第一步&#xff0…

【工具变量】上市公司企业资本支出数据(1990-2022年)

一、计算方式:资本支出的公式为:经营租赁所支付的现金购建固定资产、无影资产和其他长期资产所支付的现金-处置固定资产、无形资产和其它长期资产而收回的现金净额。 二、数据范围:包括原始数据详细来源和最终数据结果 三、参考文献:[1]杨兴…

洛谷 P10483 小猫爬山 完整题解

一、题目查看 P10483 小猫爬山 - 洛谷 二、解题思路 我们将采取递归 剪枝的思想&#xff1a; sum数组存放每辆车当前载重。 每次新考虑一只小猫时&#xff0c;我们尝试把它放进每个可以放进的缆车中&#xff08;需要回溯&#xff09; for (int i 0; i < k; i) {if (sum[i]…

Leetcode二叉树部分笔记

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Leetcode二叉树部分笔记 1.二叉树的最大深度2.同样的树3.翻转二叉树4.对称二叉树**5. **填充每个节点的下一个右侧节点指针 II**6. 二叉树展开为链表7. 路经总和8.完全二叉树…

如何用状态图进行设计06

独立的控制线程 扩展状态图也提供了获取无序的输入事件的方法。这意味着一个状态开始时&#xff0c;它可能位于一个或多个控制线程的交叉点。控制行为的每个独立线程都类似一个状态机&#xff0c;独自运行&#xff0c;互不干扰。因此&#xff0c;这些控制线程可能会同时发生状…

【多模态】MiniCPM-V多模态大模型使用学习

MiniCPM-V模型使用 前言1. 模型文件下载和选择2. 环境安装配置3. 模型微调3.1 qlora微调minicpm-v-int43.2 lora微调minicpm-v3.3 merge_lora3.4 lora微调后量化int4 4. 模型推理4.1 huggingface API4.2 swift API(A) swift&#xff08;不支持batch inference&#xff09;(B) s…

快速上手Neo4j图关系数据库

参考视频&#xff1a; 【IT老齐589】快速上手Neo4j网状关系图库 1 Neo4j简介 Neo4j是一个图数据库&#xff0c;是知识图谱的基础 在Neo4j中&#xff0c;数据的基本构建块包括&#xff1a; 节点(Nodes)关系(Relationships)属性(Properties)标签(Labels) 1.1 节点(Nodes) 节点…

Transformer: Attention Is All You Need (2017) 翻译

论文&#xff1a;Attention Is All You Need 下载地址如下: download: Transformer Attention Is All you need Attention Is All You Need 中文 《Attention Is All You Need》是《Transformer》模型的开创性论文&#xff0c;提出了一种全新的基于注意力机制的架构&#xf…

可视化报表如何制作?一文详解如何用报表工具开发可视化报表

在如今这个数据驱动的商业时代&#xff0c;众多企业正如火如荼地推进数字化转型&#xff0c;力求在激烈的市场竞争中占据先机。然而&#xff0c;随着业务规模的扩大和运营复杂度的提升&#xff0c;企业的数据量爆炸式增长&#xff0c;传统报表格式单一、信息呈现密集且不易解读…