java之网络编程
文章目录
- 网络编程概述
- 什么是网络编程
- 基本的通信架构
- CS架构
- BS架构
- Java提供了哪些网络编程解决方案?
- 网络编程三要素
- IP
- IP地址
- IP域名(Domain Name)
- DNS域名解析(Domain Name System)
- 公网IP、内网IP
- 本机IP
- InetAddress类
- InetAddress的常用方法
- IP总结
- 端口
- 端口定义
- 端口分类
- 协议
- 通信协议
- 开放式网络互联标准:OSI网络参考模型
- 传输层的通信协议
- 分类
- UDP协议
- TCP协议
- java实现UDP通信
- 快速入门
- 多发多收
- java实现TCP通信
- 快速入门
- TCP通信的实现一发一收-客户端开发
- TCP通信的实现一发一收-服务端开发
- 多发多收
- 同时接收多个客户端的消息
- 同一程序打开多个控制台
- 代码实现
- 其他应用:B/S架构的原理
- 综合案例
- 项目介绍,前置知识讲解
- 完成局域网内沟通软件的开发
- 时间相关的获取方案
- 字符串的高效操作方案
- StringBuilder
- BigDecimal
- 项目实现思路分析
网络编程概述
什么是网络编程
可以让设备中的程序与网络上其他设备中的程序进行数据交互的技术(实现网络通信)。
基本的通信架构
基本的通信架构有2种形式:
- CS架构( Client客户端/Server服务端 )
- BS架构(Browser浏览器/Server服务端)。
CS架构
BS架构
无论是CS架构,还是BS架构的软件都必须依赖网络编程!
Java提供了哪些网络编程解决方案?
java.net.*包下提供了网络编程的解决方案!
网络编程三要素
- IP地址:设备在网络中的地址,是设备在网络中的唯一标识
- 端口:应用程序在设备中的唯一标识
- 协议:连接和数据在网络中传输的规则。
上图的运行流程是先去找IP地址(IP地址2),然后(IP地址2)再根据端口号找对应的程序(微信),传输协议是建立通信之间的协议(规则)。包括文本通过什么格式传输,图片是什么格式,视频是什么格式。
IP
IP地址
IP(Internet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标识。
目前,被广泛采用的IP地址形式有两种:IPv4、IPv6。
IPv4:
IPv4是Internet Protocol version 4的缩写,它使用32位地址,通常以点分十进制表示。
IPv6
IPv6是Internet Protocol version 6的缩写,它使用128位地址,号称可以为地球上的每一粒沙子编号。
IPv6分成8段,每段每四位编码成一个十六进制位表示, 每段之间用冒号(:)分开,将这种方式称为冒分十六进制。
IP域名(Domain Name)
用于在互联网上识别和定位网站的人类可读的名称。
例如:
www.baidu.com
www.itheima.com
DNS域名解析(Domain Name System)
是互联网中用于将域名转换为对应IP地址的分布式命名系统。它充当了互联网的“电话簿”,将易记的域名映射到数字化的IP地址,使得用户可以通过域名来访问网站和其他网络资源。
我们的新电脑不认识我们的域名,因为我们的新电脑肯定有宽带(电信,移动),宽带去找我们的运营商的解析器,记录了全球的IP和域名。
公网IP、内网IP
公网IP:是可以连接到互联网的IP地址;
内网IP:也叫局域网IP,是只能组织机构内部使用的IP地址;例如,192.168. 开头的就是常见的局域网地址,范围为192.168.0.0–192.168.255.255,专门为组织机构内部使用。
内网IP的目的
- 节省地址:192.168.0.0–192.168.255.255的每个公司够可用。
- 效率更高:内部使用,不用再去互联网上绕一大圈在去获取数据。
本机IP
127.0.0.1、localhost:代表本机IP,只会寻找当前程序所在的主机。
IP常用命令
ipconfig
:查看本机IP地址。
ipconfig /all
: 查看本机物理地址。
ping IP地址
:检查网络是否连通。
InetAddress类
InetAddress是java中的类,代表IP地址。
InetAddress的常用方法
InetAddress类的常用方法 | 说明 |
---|---|
public static InetAddress getLocalHost() throws UnknownHostException | 获取本机IP,返回一个InetAddress对象 |
public String getHostName() | 获取该ip地址对象对应的主机名。 |
public String getHostAddress() | 获取该ip地址对象中的ip地址信息。 |
public static InetAddress getByName(String host) throws UnknownHostException | 根据ip地址或者域名,返回一个inetAddress对象 |
public boolean isReachable(int timeout) throws IOException | 判断主机在指定毫秒内与该ip对应的主机是否能连通 |
import java.net.InetAddress;
public class InetAddressDemo1 {public static void main(String[] args) {// 目标:认识InetAddress获取本机IP对象和对方IP对象。try {// 1.获取本机IP对象InetAddress ip1 = InetAddress.getLocalHost();System.out.println(ip1.getHostName());// dleiSystem.out.println(ip1.getHostAddress());// 192.168.**.**// 2、获取对方IP对象InetAddress ip2 = InetAddress.getByName("www.baidu.com");System.out.println(ip2.getHostName());// www.baidu.comSystem.out.println(ip2.getHostAddress());// 110.242.69.21// 3、判断本机与对方主机是否互通System.out.println(ip2.isReachable(5000)); // false 相当于ping命令}catch (Exception e){e.printStackTrace();}}
}
IP总结
说说网络通信至少需要几个要素?
IP、端口、协议
IP地址是做什么的,具体有几种?
定位网络上的设备的,有IPv4 , IPv6
如何查看本机IP地址,如何看是否与对方互通?
ipconfig
ping 192.168.10.23
本机IP是谁?
127.0.0.1或者是localhost
Java中,哪个类代表IP地址?
InetAddress
怎样获得本机IP对象?
InetAddress ip1 = InetAddress.getLocalHost();
端口
端口定义
用来标记标记正在计算机设备上运行的应用程序,被规定为一个 16 位的二进制,范围是 0~65535。
端口号的作用是什么?
唯一标识正在计算机设备上运行的进程(程序)
端口分类
周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21) ,就比如报警电话110,你自己的手机号不可能是110。
注册端口:1024~49151,分配给用户进程或某些应用程序。
动态端口:49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则报错。
一个设备中,能否出现2个应用程序的端口号一样,为什么?
不可以,如果一样会出现端口冲突错误。
协议
通信协议
网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
为了让全球所有上网设备都能互联互通,需要指定一套统一的标准
开放式网络互联标准:OSI网络参考模型
OSI网络参考模型:全球网络互联标准。 (因为这个理论太过于理论没被采用)
TCP/IP网络模型:事实上的国际标准。(这个是实践)硬件商设计网卡就是使用这个模型。
上面这个图就是,我们这个电脑比如微信,
- 应用层定义比如传网页的数据格式(http),交给传输层
- 传输层使用UDP协议或者TCP协议
- 包装自己的IP信息
- 把上面的全部数据打包成bit流(101000110像这种)在网络中传输。
另一台电脑收到这个信息,然后从物理层到应用层一点一点的拆开。
传输层的通信协议
通信协议是什么?
计算机网络中,连接和通信数据的规则被称为网络通信协议。
这一层是网络工程师干的活。
分类
UDP(User Datagram Protocol):用户数据报协议。
TCP(Transmission Control Protocol) :传输控制协议。
UDP协议
用户数据报协议(User Datagram Protocol)协议有什么特点?
- UDP是面向无连接,不可靠传输的通信协议。
- 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据。
解释:不事先建立连接,数据按照包发,一包数据包含:自己的IP、端口、目的地IP、端口和数据(限制在64KB内)等。
发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的 。
主要应用于:通信效率高,视频直播,语音通话。因为画面模糊一点卡一点无所谓,语音有些字听不清也没关系。
TCP协议
特点:面向连接、可靠通信。
TCP的最终目的:要保证在不可靠的信道上实现可靠的数据传输。
TCP主要有三个步骤实现可靠传输:传输前 三次握手建立连接,传输数据进行确认,传输后 四次挥手断开连接。
传输前 三次握手建立可靠连接
可靠连接:确保通信的双方收发消息都是没问题的(全双工)
A --> B B确定A发消息没问题
A确定B收发消息和收消息都没问题 A <-- B A --> B B确定A收消息没问题
传输后 四次挥手断开连接
目的:确保通信的双方收发消息都已经完成
特点:面向连接、可靠通信。
1.A发送断开连接 A --> B
3.A不会再发消息了,等待B接收完发送的消息 A <-- B 2.B给A发消息说你发的消息我收到了,你不需要重复发了。(只要B不回信息A就认为你没收到会重复发)A <-- B 4.我已经接受完你发的所有消息了,断开吧,收到请回答
5.A知道B发完了,发送收到我要断开了 A --> B 5.收到
TCP协议有哪些特点?
- TCP是一种面向连接的可靠通信协议
- 传输前,采用“三次握手”方式建立连接,点对点的通信。
- 在连接中可进行大数据量的传输。
- 传输后,采用“四次挥手”方式断开连接,确保消息全部收发完毕。
- 通信效率相对较低,可靠性相对较高。
java实现UDP通信
快速入门
UDP通信的实现
特点:无连接、不可靠通信。
不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发出去就不管了。
Java提供了一个java.net.DatagramSocket类来实现UDP通信。
DatagramSocket: 用于创建客户端、服务端
构造器 | 说明 |
---|---|
public DatagramSocket() | 创建客户端的Socket对象, 系统会随机分配一个端口号。 |
public DatagramSocket(int port) | 创建服务端的Socket对象, 并指定端口号 |
方法 | 说明 |
---|---|
public void send(DatagramPacket dp) | 发送数据包 |
public void receive(DatagramPacket p) | 使用数据包接收数据 |
DatagramPacket:创建数据包
构造器 | 说明 |
---|---|
public DatagramPacket(byte[] buf, int length, InetAddress address, int port) | 创建发出去的数据包对象 |
public DatagramPacket(byte[] buf, int length) | 创建用来接收数据的数据包 |
方法 | 说明 |
---|---|
public int getLength() | 获取数据包,实际接收到的字节个数 |
客户端实现步骤
- 创建DatagramSocket对象(客户端对象)--------> 扔韭菜的人
- 创建DatagramPacket对象封装需要发送的数据(数据包对象)--------> 韭菜盘子
- 使用DatagramSocket对象的send方法,传入DatagramPacket对象 -------->开始抛出韭菜
- 释放资源
服务端实现步骤
- 创建DatagramSocket对象并指定端口(服务端对象)--------> 接韭菜的人
- 创建DatagramPacket对象接收数据(数据包对象) --------> 韭菜盘子
- 使用DatagramSocket对象的receive方法,传入DatagramPacket对象 --------> 开始接收韭菜
- 释放资源
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UDPServerDemo2 {public static void main(String[] args) throws Exception {// 目标:完成UDP通信一发一收:服务端开发。System.out.println("==服务端启动了===");// 1、创建接收端对象,注册端口。(接韭菜的人)DatagramSocket socket = new DatagramSocket(8080);// 2、创建一个数据包对象负责接收数据。(韭菜盘子)byte[] buf = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buf, buf.length);// 3、接收数据,将数据封装到数据包对象的字节数组中去socket.receive(packet);// 4、看看数据是否收到了int len = packet.getLength(); // 获取当前收到的数据长度。String data = new String(buf, 0 , len);System.out.println("服务端收到了:" + data);// 获取对方的ip对象和程序端口String ip = packet.getAddress().getHostAddress();int port = packet.getPort();System.out.println("对方ip:" + ip + " 对方端口:" + port);// ==服务端启动了===// 服务端收到了:我是客户端,约你今晚啤酒、龙虾、小烧烤// 对方ip:192.168.1.10 对方端口:61807socket.close();}
}
客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UDPClientDemo1 {public static void main(String[] args) throws Exception {// 目标:完成UDP通信一发一收:客户端开发System.out.println("===客户端启动==");// 1、创建发送端对象(代表抛韭菜的人)DatagramSocket socket = new DatagramSocket(); // 随机端口// 2、创建数据包对象封装要发送的数据。(韭菜盘子)byte[] bytes = "我是客户端,约你今晚啤酒、龙虾、小烧烤".getBytes();/*** public DatagramPacket(byte[] buf, int length,* InetAddress address, int port)* 参数一:发送的数据,字节数组(韭菜)* 参数二:发送的字节长度。* 参数三:目的地的IP地址。* 参数四:服务端程序的端口号*/DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 8080);// 3、让发送端对象发送数据包的数据socket.send(packet);// ===客户端启动==socket.close();}
}
总结
实现UDP通信,如何创建客户端、服务端对象?
public DatagramSocket():创建发送端的Socket对象
public DatagramSocket(int port):创建接收端的Socket对象
数据包对象是哪个?
DatagramPacket
如何发送、接收数据?
使用DatagramSocket的如下方法:
public void send(DatagramPacket dp):发送数据包
public void receive(DatagramPacket dp) :接收数据包
多发多收
客户端可以反复发送数据
客户端实现步骤
- 创建DatagramSocket对象(发送端对象
- 使用while死循环不断的接收用户的数据输入,如果用户输入的exit则退出程序
- 如果用户输入的不是exit, 把数据封装成DatagramPacket
- 使用DatagramSocket对象的send方法将数据包对象进行发送
- 释放资源
接收端可以反复接收数据
接收端实现步骤
- 创建DatagramSocket对象并指定端口(接收端对象)--------> 接韭菜的人
- 创建DatagramPacket对象接收数据(数据包对象)--------> 韭菜盘子
- 使用DatagramSocket对象的receive方法传入DatagramPacket对象-------->开始接收韭菜
- 使用while死循环不断的进行第3步
UDP的接收端为什么可以接收很多发送端的消息?
接收端只负责接收数据包,无所谓是哪个发送端的数据包。
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UDPServerDemo2 {public static void main(String[] args) throws Exception {// 目标:完成UDP通信多发多收:服务端开发。System.out.println("==服务端启动了===");// 1、创建接收端对象,注册端口。(接韭菜的人)DatagramSocket socket = new DatagramSocket(8080);// 2、创建一个数据包对象负责接收数据。(韭菜盘子)byte[] buf = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buf, buf.length);while (true) {// 3、接收数据,将数据封装到数据包对象的字节数组中去socket.receive(packet); // 等待式接收数据。// 4、看看数据是否收到了int len = packet.getLength(); // 获取当前收到的数据长度。String data = new String(buf, 0 , len);System.out.println("服务端收到了:" + data);// 获取对方的ip对象和程序端口String ip = packet.getAddress().getHostAddress();int port = packet.getPort();System.out.println("对方ip:" + ip + " 对方端口:" + port);System.out.println("----------------------------------------------");}}
}
==服务端启动了===
服务端收到了:你好
对方ip:192.168.1.10 对方端口:56056
----------------------------------------------
服务端收到了:你好呀
对方ip:192.168.1.10 对方端口:56056
----------------------------------------------
客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
// 都听的懂,但是记不住!
public class UDPClientDemo1 {public static void main(String[] args) throws Exception {// 目标:完成UDP通信多发多收:客户端开发System.out.println("===客户端启动==");// 1、创建发送端对象(代表抛韭菜的人)DatagramSocket socket = new DatagramSocket(); // 随机端口Scanner sc = new Scanner(System.in);while (true) {// 2、创建数据包对象封装要发送的数据。(韭菜盘子)System.out.println("请说:");String msg = sc.nextLine();// 如果用户输入的是 exit,则退出if ("exit".equals(msg)) {System.out.println("===客户端退出==");socket.close();break;}byte[] bytes = msg.getBytes();DatagramPacket packet = new DatagramPacket(bytes, bytes.length,InetAddress.getLocalHost(), 8080);// 3、让发送端对象发送数据包的数据socket.send(packet);}}
}
===客户端启动==
请说:
你好
请说:
你好呀
java实现TCP通信
快速入门
TCP通信的实现
特点:面向连接、可靠通信。
通信双方事先会采用“三次握手”方式建立可靠连接,实现端到端的通信;底层能保证数据成功传给服务端。
Java提供了一个java.net.Socket类来实现TCP通信。
TCP通信的实现一发一收-客户端开发
客户端程序就是通过java.net包下的Socket类来实现的。
构造器 | 说明 |
---|---|
public Socket(String host , int port) | 根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket |
方法 | 说明 |
---|---|
public OutputStream getOutputStream() | 获得字节输出流对象 |
public InputStream getInputStream() | 获得字节输入流对象 |
TCP通信的实现一发一收-客户端开发步骤
- 创建客户端的Socket对象,请求与服务端的连接。
- 使用socket对象调用getOutputStream()方法得到字节输出流。
- 使用字节输出流完成数据的发送。
- 释放资源:关闭socket管道。
TCP通信的实现一发一收-服务端开发
服务端是通过java.net包下的ServerSocket类来实现的。
ServerSocket
构造器 | 说明 |
---|---|
public ServerSocket(int port) | 为服务端程序注册端口 |
方法 | 说明 |
---|---|
public Socket accept() | 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象。 |
TCP通信的实现一发一收-服务端开发步骤
- 创建ServerSocket对象,注册服务端端口。
- 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
- 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
- 释放资源:关闭socket管道
服务端
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServerDemo2 {public static void main(String[] args) throws Exception {// 目标:实现TCP通信下一发一收:服务端开发。System.out.println("服务端启动了...");// 1、创建服务端ServerSocket对象,绑定端口号,监听客户端连接ServerSocket ss = new ServerSocket(9999);// 2、调用accept方法,阻塞等待客户端连接,一旦有客户端链接会返回一个Socket对象Socket socket = ss.accept();// 3、获取输入流,读取客户端发送的数据InputStream is = socket.getInputStream();// 4、把字节输入流包装成特殊数据输入流DataInputStream dis = new DataInputStream(is);// 5、读取数据int id = dis.readInt();String msg = dis.readUTF();System.out.println("id=" + id + ",收到的客户端msg=" + msg);// 6、客户端的ip和端口(谁给我发的)System.out.println("客户端的ip=" + socket.getInetAddress().getHostAddress());System.out.println("客户端的端口=" + socket.getPort());}
}
服务端启动了...
id=1,收到的客户端msg=我想你了,你在哪儿?
客户端的ip=127.0.0.1
客户端的端口=4391
客户端
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;public class ClientDemo1 {public static void main(String[] args) throws Exception {// 目标:实现TCP通信下一发一收:客户端开发。System.out.println("客户端启动....");// 1、常见Socket管道对象,请求与服务端的Socket链接。可靠链接Socket socket = new Socket("127.0.0.1", 9999);// 2、从socket通信管道中得到一个字节输出流。OutputStream os = socket.getOutputStream();// 3、特殊数据流。DataOutputStream dos = new DataOutputStream(os);dos.writeInt(1);dos.writeUTF("我想你了,你在哪儿?");// 4、关闭资源。socket.close();}
}
客户端启动....
总结
TCP通信,客户端的代表类是谁?
Socket类
public Socket(String host , int port)
TCP通信,如何使用Socket管道发送、接收数据 ?
OutputStream getOutputStream():获得字节输出流对象(发)
InputStream getInputStream():获得字节输入流对象(收)
TCP通信服务端用的类是谁?
ServerSocket类,注册端口。
调用accept()方法阻塞等待接收客户端连接。得到Socket对象。
多发多收
案例:使用TCP通信实现:多发多收消息
客户端使用死循环,让用户不断输入消息。
服务端也使用死循环,控制服务端程序收完消息后,继续去接收下一个消息。
总结
本次多发多收是如何实现的?
客户端使用循环反复地发送消息。
服务端使用循环反复地接收消息。
服务端
package com.itheima.demo5tcp2;import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServerDemo2 {public static void main(String[] args) throws Exception {// 目标:实现TCP通信下多发多收:服务端开发。System.out.println("服务端启动了...");// 1、创建服务端ServerSocket对象,绑定端口号,监听客户端连接ServerSocket ss = new ServerSocket(9999);// 2、调用accept方法,阻塞等待客户端连接,一旦有客户端链接会返回一个Socket对象Socket socket = ss.accept();// 3、获取输入流,读取客户端发送的数据InputStream is = socket.getInputStream();// 4、把字节输入流包装成特殊数据输入流DataInputStream dis = new DataInputStream(is);while (true) {// 5、读取数据String msg = dis.readUTF(); // 等待读取客户端发送的数据System.out.println("收到的客户端msg=" + msg);// 6、客户端的ip和端口(谁给我发的)System.out.println("客户端的ip=" + socket.getInetAddress().getHostAddress());System.out.println("客户端的端口=" + socket.getPort());System.out.println("--------------------------------------------------");}}
}
服务端启动了...
收到的客户端msg=你好
客户端的ip=127.0.0.1
客户端的端口=5694
--------------------------------------------------
收到的客户端msg=去吃饭
客户端的ip=127.0.0.1
客户端的端口=5694
--------------------------------------------------
客户端
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class ClientDemo1 {public static void main(String[] args) throws Exception {// 目标:实现TCP通信下多发多收:客户端开发。System.out.println("客户端启动....");// 1、常见Socket管道对象,请求与服务端的Socket链接。可靠链接Socket socket = new Socket("127.0.0.1", 9999);// 2、从socket通信管道中得到一个字节输出流。OutputStream os = socket.getOutputStream();// 3、特殊数据流。DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {System.out.println("请说:");String msg = sc.nextLine();if ("exit".equals(msg)) {System.out.println("退出成功!");dos.close(); // 关闭输出流socket.close(); // 关闭socketbreak;}dos.writeUTF(msg); // 发送数据dos.flush();}}
}
客户端启动....
请说:
你好
请说:
去吃饭
同时接收多个客户端的消息
目前我们开发的服务端程序,是否可以支持同时与多个客户端通信 ?
不可以
因为服务端现在只有一个主线程,只能处理一个客户端的消息。
总结
本次是如何实现服务端同时接收多个客户端的消息的?
主线程定义了循环负责接收客户端Socket管道连接
每接收到一个Socket通信管道后分配一个独立的线程负责处理它。
同一程序打开多个控制台
运行服务层
服务端启动了...
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
收到的客户端msg=我是第一条线程
客户端的ip=127.0.0.1
客户端的端口=6187
--------------------------------------------------
收到的客户端msg=我是第二条线程
客户端的ip=127.0.0.1
客户端的端口=7067
--------------------------------------------------
运行一次客户端
客户端启动....
请说:
我是第一条线程
运行两次客户端
客户端启动....
请说:
我是第二条线程
代码实现
服务端
import java.net.ServerSocket;
import java.net.Socket;public class ServerDemo2 {public static void main(String[] args) throws Exception {// 目标:实现TCP通信下多发多收:服务端开发。支持多个客户端开发。System.out.println("服务端启动了...");// 1、创建服务端ServerSocket对象,绑定端口号,监听客户端连接ServerSocket ss = new ServerSocket(9999);while (true) {// 2、调用accept方法,阻塞等待客户端连接,一旦有客户端链接会返回一个Socket对象Socket socket = ss.accept();System.out.println("一个客户端上线了:" + socket.getInetAddress().getHostAddress());// 3、把这个客户端管道交给一个独立的子线程专门负责接收这个管道的消息。new ServerReader(socket).start();}}
}
调用线程
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;public class ServerReader extends Thread{private Socket socket;public ServerReader(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {// 读取管道的消息// 3、获取输入流,读取客户端发送的数据InputStream is = socket.getInputStream();// 4、把字节输入流包装成特殊数据输入流DataInputStream dis = new DataInputStream(is);while (true) {// 5、读取数据String msg = dis.readUTF(); // 等待读取客户端发送的数据System.out.println("收到的客户端msg=" + msg);// 6、客户端的ip和端口(谁给我发的)System.out.println("客户端的ip=" + socket.getInetAddress().getHostAddress());System.out.println("客户端的端口=" + socket.getPort());System.out.println("--------------------------------------------------");}} catch (Exception e) {System.out.println("客户端下线了:"+ socket.getInetAddress().getHostAddress());}}
}
客户端(设置同一程序打开多个控制台)
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class ClientDemo1 {public static void main(String[] args) throws Exception {// 目标:实现TCP通信下多发多收:支持多个客户端开发。System.out.println("客户端启动....");// 1、常见Socket管道对象,请求与服务端的Socket链接。可靠链接Socket socket = new Socket("127.0.0.1", 9999);// 2、从socket通信管道中得到一个字节输出流。OutputStream os = socket.getOutputStream();// 3、特殊数据流。DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {System.out.println("请说:");String msg = sc.nextLine();if ("exit".equals(msg)) {System.out.println("退出成功!");dos.close(); // 关闭输出流socket.close(); // 关闭socketbreak;}dos.writeUTF(msg); // 发送数据dos.flush();}}
}
其他应用:B/S架构的原理
要求从浏览器中访问服务器
并立即让服务器响应一个很简单的网页给浏览器展示
网页内容就是“听黑马磊哥讲Java”
拓展知识
每次请求都开一个新线程,到底好不好?
高并发时,容易宕机!
使用线程池进行优化
总结
1、BS架构的基本原理是什么?
客户端使用浏览器发起请求(不需要开发客户端)
服务端必须按照HTTP协议响应数据。
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;public class ServerDemo {public static void main(String[] args) throws Exception {// 目标:BS架构的原理理解System.out.println("服务端启动了...");// 1、创建服务端ServerSocket对象,绑定端口号,监听客户端连接ServerSocket ss = new ServerSocket(8080);// 创建线程池ExecutorService pool = new ThreadPoolExecutor(3, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());while (true) {// 2、调用accept方法,阻塞等待客户端连接,一旦有客户端链接会返回一个Socket对象Socket socket = ss.accept();System.out.println("一个客户端上线了:" + socket.getInetAddress().getHostAddress());// 3、把这个客户端管道包装成一个任务交给线程池处理pool.execute(new ServerReaderRunnable(socket));}}
}ServerReaderRunnable.java
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;public class ServerReaderRunnable implements Runnable{private Socket socket;public ServerReaderRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {// 给当前对应的浏览器管道响应一个网页数据回去。OutputStream os = socket.getOutputStream();// 通过字节输出流包装写出去数据给浏览器// 把字节输出流包装成打印流。PrintStream ps = new PrintStream(os);// 写响应的网页数据出去ps.println("HTTP/1.1 200 OK");ps.println("Content-Type:text/html;charset=utf-8");ps.println(); // 必须换一行ps.println("<html>");ps.println("<head>");ps.println("<meta charset='utf-8'>");ps.println("<title>");ps.println("黑马Java磊哥的视频");ps.println("</title>");ps.println("</head>");ps.println("<body>");ps.println("<h1 style='color:red;font-size=20px'>听黑马Java磊哥的视频</h1>");// 响应一个黑马程序员的log展示ps.println("<img src='https://www.itheima.com/images/logo.png'>");ps.println("</body>");ps.println("</html>");ps.close();socket.close();} catch (Exception e) {System.out.println("客户端下线了:"+ socket.getInetAddress().getHostAddress());}}
}
服务端启动了...
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
一个客户端上线了:127.0.0.1
综合案例
项目介绍,前置知识讲解
完成局域网内沟通软件的开发
时间相关的获取方案
LocalDate:代表本地日期(年、月、日、星期)
LocalTime:代表本地时间(时、分、秒、纳秒)
LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)
它们获取对象的方案
方法名 | 示例 |
---|---|
public static Xxxx now(): 获取系统当前时间对应的该对象 | LocaDate ld = LocalDate.now(); LocalTime lt = LocalTime.now(); LocalDateTime ldt = LocalDateTime.now(); |
LocalDateTime的常用API(可以处理年、月、日、星期、时、分、秒、纳秒等信息)
方法名 | 说明 |
---|---|
getYear、getMonthValue、getDayOfMonth、getDayOfYeargetDayOfWeek、getHour、getMinute、getSecond、getNano | 获取年月日、时分秒、纳秒等 |
withYear、withMonth、withDayOfMonth、withDayOfYearwithHour、withMinute、withSecond、withNano | 修改某个信息,返回新日期时间对象 |
plusYears、plusMonths、plusDays、plusWeeksplusHours、plusMinutes、plusSeconds、plusNanos | 把某个信息加多少,返回新日期时间对象 |
minusYears、minusMonths、minusDays、minusWeeksminusHours、minusMinutes、minusSeconds、minusNanos | 把某个信息减多少,返回新日期时间对象 |
equals isBefore isAfter | 判断2个时间对象,是否相等,在前还是在后 |
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;public class Test1 {public static void main(String[] args) {// 目标:掌握java提供的获取时间的方案。// JDK 8之前的方案: Date 获取此刻日期时间 老项目还有。Date d = new Date();System.out.println(d);// Tue May 13 13:25:15 CST 2025// 格式化:SimpleDateFormat 简单日期格式化,格式化日期对象成为我们喜欢的格式。SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");String result = sdf.format(d);System.out.println(result); // 2025年05月13日 13:25:15 周二 下午System.out.println("---------------------------");// JDK 8之后的方案: LocalDate LocalTime LocalDateTime 获取此刻日期时间 新项目推荐。// 获取此刻日期时间对象LocalDateTime now = LocalDateTime.now();System.out.println(now);// 2025-05-13T13:25:15.551119400System.out.println(now.getYear());// 2025// 获取当前是第几天System.out.println(now.getDayOfYear());// 133LocalDateTime now2 = now.plusSeconds(60); // 60秒后System.out.println(now);// 2025-05-13T13:25:15.551119400System.out.println(now2);// 2025-05-13T13:26:15.551119400// 格式化:DateTimeFormatter// 1、创建一个格式化对象DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss EEE a");// 2、格式化now对象的时间String result2 = dtf.format(now);System.out.println(result2);// 2025/05/13 13:25:15 周二 下午}
}
字符串的高效操作方案
- 对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler,效率更高!
- 注意:如果操作字符串较少,或者不需要操作,以及定义字符串变量,还是建议用String。
StringBuilder
- StringBuilder代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的。
- 好处:StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁。
构造器 | 说明 |
---|---|
public StringBuilder() | 创建一个空白的可变的字符串对象,不包含任何内容 |
public StringBuilder(String str) | 创建一个指定字符串内容的可变字符串对象 |
方法名称 | 说明 |
---|---|
public StringBuilder append(任意类型) | 添加数据并返回StringBuilder对象本身 |
public StringBuilder reverse() | 将对象的内容反转 |
public int length() | 返回对象内容长度 |
public String toString() | 通过toString()就可以实现把StringBuilder转换为String |
public class Test2 {public static void main(String[] args) {// 目标:高效拼接字符串。// + 号拼接字符串内容,如果是大量拼接,效率极差!// String的对象时不可变变量: 共享数据性能可以,但是修改数据性能差!
// String s = "";
// for (int i = 0; i < 1000000 ; i++) {
// s = s + "abc";
// }
// System.out.println(s);// 定义字符串可以使用String类型,但是操作字符串建议大家用StringBuilder(性能好)StringBuilder sb = new StringBuilder(); // StringBuilder对象是可变内容的容器 sb = "";for (int i = 0; i < 1000000 ; i++) {sb.append("abc");}System.out.println(sb);// StringBuilder只是拼接字符串的手段,结果还是要恢复成字符串(目的)String s = sb.toString();System.out.println(s);StringBuilder sb2 = new StringBuilder();String result = sb2.append("张三").append("李四").append("王五").toString();System.out.println(result);}
}
BigDecimal
用于解决浮点型运算时,出现结果失真的问题。
double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 0.30000000000000004
// 为什么会失真
// 浮点数在内存中以二进制形式存储,所以浮点数在计算机中无法精确表示。
BigDecimal的常见构造器、常用方法
构造器 | 说明 |
---|---|
public BigDecimal(double val) 注意:不推荐使用这个 | 将 double转换为 BigDecimal |
public BigDecimal(String val) | 把String转成BigDecimal |
方法名 | 说明 |
---|---|
public static BigDecimal valueOf(double val) | 转换一个 double成 BigDecimal |
public BigDecimal add(BigDecimal b) | 加法 |
public BigDecimal subtract(BigDecimal b) | 减法 |
public BigDecimal multiply(BigDecimal b) | 乘法 |
public BigDecimal divide(BigDecimal b) | 除法 |
public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式) | 除法、可以控制精确到小数几位 |
public double doubleValue() | 将BigDecimal转换为double |
总结
BigDecimal的作用是什么 ?
解决浮点型运算时,出现结果失真的问题。
应该如何把浮点型转换成BigDecimal的对象?
BigDecimal b1 = BigDecimal.valueOf(0.1)
BigDecimal提供了哪些常见的方法 ?
import java.math.BigDecimal;
import java.math.RoundingMode;public class Test3 {public static void main(String[] args) {// 目标:掌握BigDecimal解决小数运算结果失真问题。double a = 0.1;double b = 0.2;System.out.println(a + b); // 0.30000000000000004// 为什么会失真// 浮点数在内存中以二进制形式存储,所以浮点数在计算机中无法精确表示。// 如何解决呢? 使用BigDecimal// 1、把小数包装成BigDecimal对象来运算才可以。// 必须使用 public BigDecimal(String val) 字符串构造器才能解决失真问题
// BigDecimal a1 = new BigDecimal(Double.toString(a));
// BigDecimal b1 = new BigDecimal(Double.toString(b));// 优化方案,可以直接调用valueOf方法,内部使用的就是public BigDecimal(String val) 字符串构造器BigDecimal a1 = BigDecimal.valueOf(a);BigDecimal b1 = BigDecimal.valueOf(b);BigDecimal c1 = a1.add(b1); // 解决精度问题的手段double result = c1.doubleValue(); // 目的 把BigDecimal对象转成double类型System.out.println(result);// 0.3System.out.println("------------");BigDecimal i = BigDecimal.valueOf(0.1);BigDecimal j = BigDecimal.valueOf(0.3);// 除法// 默认除法运算精度 divide(BigDecimal divisor, int scale, RoundingMode roundingMode)// scale:精度 // roundingMode:舍入模式BigDecimal k = i.divide(j, 2, RoundingMode.HALF_UP); // 抛异常System.out.println(k);}
}
项目实现思路分析
综合案例请参考我的java专栏。
相关文章:
java之网络编程
文章目录 网络编程概述什么是网络编程基本的通信架构CS架构BS架构 Java提供了哪些网络编程解决方案? 网络编程三要素IPIP地址IP域名(Domain Name)DNS域名解析(Domain Name System)公网IP、内网IP本机IPInetAddress类In…...
苍穹外卖--新增菜品
1.需求分析和设计 产品原型 业务规则: 菜品名称必须是唯一的 菜品必须属于某个分类下,不能单独存在 新增菜品时可以根据情况选择菜品的口味 每个菜品必须对应一张图片 接口设计: 根据类型查询分类(已完成) 文件上传 新增菜品 根据类型…...
Spark处理过程-转换算子
(一)RDD的处理过程 Spark使用Scala语言实现了RDD的API,程序开发者可以通过调用API对RDD进行操作处理。RDD的处理过程如图所示; RDD经过一系列的“转换”操作,每一次转换都会产生不同的RDD,以供给下一次“转换”操作使…...
运行Spark程序-在Spark-shell——RDD
一、基本概念 RDD(弹性分布式数据集)是 Apache Spark 的核心抽象,是 Spark 提供的最基本的数据处理单元。理解 RDD 的概念对于掌握 Spark 编程至关重要。以下是 RDD 的核心概念和特性: 1. 什么是 RDD? 定义…...
Qt应用程序启动时的一些思路:从单实例到性能优化的处理方案
程序启动时优化的价值 在桌面软件开发领域,应用程序的启动过程就像音乐的序曲,决定了用户对软件品质的第一印象。比如首次启动等待超过3秒时,会让大多数用户产生负面看法,而专业工具软件的容忍阈值甚至更低。Qt框架作为跨平台开发…...
vue3父子组件传值
父 → 子:props 父组件 <template><ChildComponent :message"parentMessage" :user"user" /> </template><script setup> import ChildComponent from ./ChildComponent.vue; const parentMessage Hello from paren…...
中国品牌日 | 以科技创新为引领,激光院“风采”品牌建设结硕果
品牌,作为企业不可或缺的隐形财富,在当今竞争激烈的市场环境中,其构建与强化已成为推动企业持续繁荣的关键基石。为了更好地保护自主研发产品,激光院激光公司于2020年3月7日正式注册“风采”商标,创建拥有自主知识产权…...
合合信息上线智能文档处理领域首批MCP服务,助力企业快速搭建Agent
随着大模型及Agent技术的飞速发展,通过大模型调用外部工具正在成为AI应用开发的新范式。然而,由于不同大模型的调用结构和参数格式各异,开发者需要分别编写工具调用逻辑,AI工具集成效率低下,MCP(Model Cont…...
佰力博科技与您探讨表面电阻的测试方法及应用领域
表面电阻测试是一种用于测量材料表面电阻值的技术,广泛应用于评估材料的导电性能、静电防护性能以及绝缘性能。 1、表面电阻的测试测试方法: 表面电阻测试通常采用平行电极法、同心圆电极法和四探针法等方法进行。其中,平行电极法通过在试样…...
【DeepSeek】判断两个 PCIe 设备是否属于**同一个 PCIe 子树
在 Linux 系统中,判断两个 PCIe 设备是否属于**同一个 PCIe 子树(Subtree)**是 P2P 通信的关键前提。以下是具体方法和步骤: 一、基本原理 两个 PCIe 设备属于同一子树的条件: 共享同一 Root Port:它们的…...
一份完整的高级前端性能优化手册
以下是一份完整的高级前端性能优化手册,涵盖核心原理、关键指标、优化策略及工具链,适合中大型项目深度优化: 高级前端性能优化手册 🚀 以用户体验为核心的极致性能实践 一、性能指标体系与度量 1. 核心性能指标 (Core Web Vitals) LCP (Largest Contentful Paint):最大…...
Leetcode 3543. Maximum Weighted K-Edge Path
Leetcode 3543. Maximum Weighted K-Edge Path 1. 解题思路2. 代码实现 题目链接:3543. Maximum Weighted K-Edge Path 1. 解题思路 这一题思路上就是一个遍历的思路,我们只需要考察每一个节点作为起点时,所有长为 k k k的线段的长度&…...
agentmain对业务的影响
前面一篇已经说了java agent技术主要有premain和agentmain两种形式,如果大部分业务已经在线上运行的话,不方便用premain的方式来实现,所以agentmain的方式是更加通用、灵活的 由于RASP是与用户业务运行在同一个jvm中的 ,所以RASP…...
【前端】【JavaScript】【总复习】四万字详解JavaScript知识体系
JavaScript 前端知识体系 📌 说明:本大纲从基础到高级、从语法到应用、从面试到实战,分层级讲解 JavaScript 的核心内容。 一、JavaScript 基础语法 1.1 基本概念 1.1.1 JavaScript 的发展史与用途 1. 发展简史 1995 年:JavaS…...
开源模型应用落地-qwen模型小试-Qwen3-8B-融合VLLM、MCP与Agent(七)
一、前言 随着Qwen3的开源与技术升级,其在企业中的落地场景正加速拓展至多个垂直领域。依托Agent智能体能力 和MCP协议的工具调用接口 ,Qwen3可深度融入企业业务流程,为企业提供从需求解析到自动化开发的全链路支持。 本篇将介绍如何实现Qwen3-8B模型集成MCP实现智能体交互。…...
【Linux学习笔记】理解一切皆文件实现原理和文件缓冲区
【Linux学习笔记】理解一切皆文件实现原理和文件缓冲区 🔥个人主页:大白的编程日记 🔥专栏:Linux学习笔记 前言 哈喽,各位小伙伴大家好!上期我们讲了重定向 今天我们讲的是理解一切皆文件实现原理和文件缓冲区。话不…...
MCP-RAG 服务器:完整设置和使用指南
在快速发展的人工智能应用时代,结合静态领域知识和实时网络信息的系统需求比以往任何时候都更加迫切。传统的检索增强生成(RAG)模型通常依赖于预先索引的数据,这限制了它们对新发展的反应能力。MCP-RAG Server通过将基于语义的向量…...
裸金属服务器 VS 传统物理机
一:首先,我们先介绍一下,什么是裸金属服务器? 1.虚拟机的外表-平台可视化 可以通过后台管理界面查看当前所使用的全部信息包括:当前系统版本、CPU、内存、硬盘等相关信息。 2.虚拟机的外表-操作自动化 同样也可以在…...
React百日学习计划-Grok3
关键点 研究表明,100天内学习React是可行的,尤其是你已有HTML、JS和CSS基础。该计划包括基础知识、hooks、状态管理、路由、样式化及综合项目,适合初学者。建议每天花2-3小时学习,结合免费教程和社区支持。 开始学习 学习React…...
Android NDK 高版本交叉编译:为何无需配置 FLAGS 和 INCLUDES
引言:NDK 交叉编译的演进 Android NDK(Native Development Kit)是开发高性能C/C代码的核心工具链,而交叉编译(在x86主机上生成ARM架构代码)一直是NDK的核心功能。过去,开发者需要手动配置大量编…...
Java详解LeetCode 热题 100(15):LeetCode 189. 轮转数组(Rotate Array)详解
文章目录 1. 题目描述2. 理解题目3. 解法一:使用额外数组3.1 思路3.2 Java代码实现3.3 代码详解3.4 复杂度分析3.5 适用场景 4. 解法二:环状替换法(原地算法)4.1 思路4.2 Java代码实现4.3 代码详解4.4 复杂度分析4.5 陷阱与注意事…...
出于PCB设计层面考虑,连排半孔需要注意哪些事项?
通过拼接作为后处理运行,用拼接联排半孔填充铜的自由区域。为了使通缝成为可能,必须在不同的层上有重叠的铜区域连接到指定的网上。铜的支持区域包括填充、多边形和动力平面。 高电流对电路板的潜在负面影响的另一个例子是电路板结构的物理失效。制造原始…...
JIT+Opcache如何配置才能达到性能最优
首先打开php.ini文件,进行配置 1、OPcache配置 ; 启用OPcache opcache.enable1; CLI环境下启用OPcache(按需配置) opcache.enable_cli0; 预加载脚本(PHP 7.4,加速常用类) ; opcache.preload/path/to/prel…...
VR和眼动控制集群机器人的方法
西安建筑科技大学信息与控制工程学院雷小康老师团队联合西北工业大学航海学院彭星光老师团队,基于虚拟现实(VR)和眼动追踪技术实现了人-集群机器人高效、灵活的交互控制。相关研究论文“基于虚拟现实和眼动的人-集群机器人交互方法” 发表于信…...
LabVIEW与PLC通讯程序S7.Net.dll
下图中展示的是 LabVIEW 环境下通过调用S7.Net.dll 组件与西门子 PLC 进行通讯的程序。LabVIEW 作为一种图形化编程语言,结合S7.Net.dll 的.NET 组件优势,在工业自动化领域中可高效实现与 PLC 的数据交互,快速构建工业监控与控制应用。相较于…...
【华为】现场配置OSPF
原创:厦门微思网络 实验目的 1、了解OSPF的运行原理 2、掌握OSPF的配置方法 实验拓扑 实验需求 1、根据实验拓扑图,完成设备的基本配置; 2、分别在R1、R2、R3上创建Loopback0接口,IP地址分别是1.1.1.1/32、2.2.2.2/32、3.3.3.…...
STM32-DMA数据转运(8)
目录 一、简介 二、存储器映像 三、DMA框图编辑 四、DMA基本结构 五、两个数据转运的实例 一、简介 直接存储器存取简称DMA(Direct Memory Access),它是一个数据转运小助手,主要用来协助CPU,完成数据转运的工作…...
课题推荐——低成本地磁导航入门,附公式推导和MATLAB例程运行演示
地磁导航利用地球磁场的自然特性,通过感知磁场变化,帮助机器人或无人设备实现定位和导航。相比于 GPS、激光雷达等导航方法,地磁导航具有以下优势: 低成本:使用地磁传感器(如电子罗盘)ÿ…...
微信小程序学习之底部导航栏
首先,我们在app.json中添加4个页面, "pages": ["pages/index/index","pages/category/category","pages/cart/cart","pages/user/user"], 其次我们把8张图片放到imaes文件夹下, 图标可…...
c++ std库中的文件操作学习笔记
1. 概述 C标准库提供了 头文件中的几个类来进行文件操作,这些类封装了底层的文件操作,提供了面向对象和类型安全的接口,使得文件读写更加便捷和高效。主要的文件流类包括: std::ifstream:用于从文件中读取数据。 st…...
多臂赌博机:探索与利用的平衡艺术
1. 引言 在机器学习领域,多臂赌博机(Multi-Armed Bandit,MAB)问题是强化学习的一个经典且基础的模型。这个名称源于赌场中的"单臂老虎机"(One-armed Bandit),因为这种赌博机器像强盗…...
分布式异步强化学习框架训练32B大模型:INTELLECT-2
INTELLECT-2 模型详解 一、模型概述 INTELLECT-2 是一个拥有 320 亿参数的语言模型,其训练采用了一种创新的方式,即通过社区贡献的分布式、无需许可的 GPU 资源进行强化学习训练。该模型基于 qwen2 架构构建,因此与 vllm 或 sglang 等流行库…...
HTML应用指南:利用POST请求获取全国京东快递服务网点位置信息
京东快递作为中国领先的智能供应链与综合物流服务提供商,自2007年成立以来,始终致力于通过技术创新与高效运营,为客户提供安全、可靠、快速的物流解决方案。京东快递依托京东集团的强大资源支持,凭借其自营仓储、干线运输、末端配送一体化的物流网络,在激烈的市场竞争中脱…...
通过POI实现对word基于书签的内容替换、删除、插入
一、基本概念 POI:即Apache POI, 它是一个开源的 Java 库,主要用于读取 Microsoft Office 文档(Word、Excel、PowerPoint 等),修改 或 生成 Office 文档内容,保存 为对应的二进制或 XML 格式&a…...
git进行版本控制时遇到Push cannot contain secrets的解决方法
git进行版本控制,push遇到Push cannot contain secrets的解决方法 最近在项目开发过程中,我遇到了一个让我头疼不已的问题。 问题的出现 一开始,我的项目远程仓库连接的是 Gitee,在开发过程中一切都很顺利,我也习惯…...
Java GUI 开发之旅:Swing 组件与布局管理的实战探索
在编程的世界里,图形用户界面(GUI)设计一直是提升用户体验的关键环节。Java 的 Swing 库为我们提供了强大的工具来构建跨平台的 GUI 应用。今天,我将通过一次实验,分享如何使用 Java Swing 开发一个功能丰富的 GUI 应用…...
OpenVLA (2) 机器人环境和环境数据
文章目录 前言1 BridgeData V21.1 概述1.2 硬件环境 2 数据集2.1 场景与结构2.2 数据结构2.2.1 images02.2.2 obs_dict.pkl2.2.3 policy_out.pkl 前言 按照笔者之前的行业经验, 数据集的整理是非常重要的, 因此笔者这里增加原文中出现的几个数据集和环境的学习 1 BridgeData V…...
【Ansible】基于windows主机,采用NTLM+HTTPS 认证部署
我们现在准备Linux centos7(Ansible控制机)和Windows(客户机)环境下的详细部署步骤: 一、Windows客户机配置 1. 准备SSL证书 1.1 生成自签名证书(测试用) 以管理员身份打开PowerShell&#…...
React19源码系列之 API(react-dom)
API之 preconnect preconnect – React 中文文档 preconnect 函数向浏览器提供一个提示,告诉它应该打开到给定服务器的连接。如果浏览器选择这样做,则可以加快从该服务器加载资源的速度。 preconnect(href) 一、使用例子 import { preconnect } fro…...
鸿蒙Next开发 获取APP缓存大小和清除缓存
1. 鸿蒙Next开发 获取APP缓存大小和清除缓存 1.1. 介绍 1.1.1. 文件系统分类 在最新的Core File Kit套件中,按文件所有者的不同。分为如下三类: (1)应用文件:文件所有者为应用,包括应用安装文件、应用…...
PNG转ico图标(支持圆角矩形/方形+透明背景)Python脚本 - 随笔
摘要 在网站开发或应用程序设计中,常需将高品质PNG图像转换为ICO格式图标。本文提供一份基于Pillow库实现的,能够完美保留透明背景且支持导出圆角矩形/方形图标的格式转换脚本。 源码示例 圆角方形 from PIL import Image, ImageDraw, ImageOpsdef c…...
『大模型笔记』Langchain作者Harrison Chase专访:环境智能体与全新智能体收件箱
Langchain作者Harrison Chase专访:环境智能体与全新智能体收件箱 文章目录 摘要访谈内容什么环境智能体为什么要探索环境智能体怎么让人类能更方便地和环境智能体互动参考文献摘要 LangChain 的 CEO Harrison Chase 提出了_“环境智能体”(Ambient Agents)的概念,这是一种…...
GPT( Generative Pre-trained Transformer )模型:基于Transformer
GPT是由openAI开发的一款基于Transformer架构的预训练语言模型,拥有强大的生成能力和多任务处理能力,推动了自然语言处理(NLP)的快速发展。 一 GPT发展历程 1.1 GPT-1(2018年) 是首个基于Transformer架构…...
游戏引擎学习第275天:将旋转和剪切传递给渲染器
回顾并为今天的内容定下基调 我们认为在实现通用动画系统之前,先学习如何手写动画逻辑是非常有价值的。虽然加载和播放预设动画是合理的做法,尤其是在团队中有美术人员使用工具制作动画的情况下更是如此,但手动编写动画代码能让我们更深入理…...
conda 输出指定python环境的库 输出为 yaml文件
conda 输出指定python环境的库 输出为 yaml文件。 有时为了项目部署,需要匹配之前的python环境,需要输出对应的python依赖库。 假设你的目标环境名为 myenv,运行以下命令: conda env export -n myenv > myenv_environment.ym…...
ES6 语法
扩展运算符 … 口诀:三个点,打散数组,逐个放进去 例子: let arr [1, 2];let more [3, 4];arr.push(...more); // arr 变成 [1, 2, 3, 4]解构赋值 口诀:左边是变量,右边是值,一一对应 例子&…...
BFS算法篇——打开智慧之门,BFS算法在拓扑排序中的诗意探索(下)
文章目录 引言一、课程表1.1 题目链接:https://leetcode.cn/problems/course-schedule/description/1.2 题目分析:1.3 思路讲解:1.4 代码实现: 二、课程表||2.1 题目链接:https://leetcode.cn/problems/course-schedul…...
While语句数数字
import java.util.Scanner;public class Hello {public static void main(String[] args) {Scanner in new Scanner(System.in);int number in.nextInt();int count 0;while( number > 0 ){number number / 10;count count 1;}System.out.println(count);} }...
G1JVM内存分配机制详解
为什么堆内存不是预期的3G? 当您设置-XX:MaxRAMPercentage75时,JVM并不会简单地将容器内存(4G)的75%全部分配给堆,原因如下: 计算基准差异: 百分比是应用于"可用物理内存"而非"容器总内存" &q…...
“端 - 边 - 云”三级智能协同平台的理论建构与技术实现
摘要 随着低空经济与智能制造的深度融合,传统集中式云计算架构在实时性、隐私保护和资源效率上的瓶颈日益凸显。本文提出“端 - 边 - 云”三级智能协同平台架构,以“时空 - 资源 - 服务”三维协同理论为核心,构建覆盖终端感知、边缘计算、云端…...