网络编程初识
注:此博文为本人学习过程中的笔记
1.socket api
这是操作系统提供的一组api,由传输层向应用层提供。
2.传输层的两个核心协议
传输层的两个核心协议分别是TCP协议和UDP协议,它们的差别非常大,编写代码的风格也不同,因此socket提供了两套api。TCP协议是有连接,可靠传输,面向字节流,全双工。UDP协议是无连接,不可靠传输,面向数据报,全双工。
1.有连接/无连接
这里的有无连接是抽象的概念,对于网络通信来说,物理上(网线)的连接时必须的。这里的连接是指在通信的时候有没有保存对方的信息。
对于TCP协议来说,A和B通信,会让A保存B的信息,B保存A的信息,让它们彼此知道谁是和它建立连接的那一个。
对于UDP协议来说,不保存对方的协议。当然程序员可以在自己的代码中保存对方的信息,但这不属于UDP协议的行为。
2.可靠传输/不可靠传输
网络上,数据是非常容易出现丢失的情况,用来传输的光/电信号很容易受到外界的影响。所以我们不能指望一个数据包发送之后,能百分之一百到达对方。
可靠传输的意思不是保证数据包百分之一百到达,而是尽可能提高传输成功的概率,如果丢包了,可以感知到。
不可靠传输就是指数据包发送之后就不管了。
3.面向字节流/面向数据报
面向字节流是指读写数据的时候以字节为单位。它可以灵活地控制读写的长度,但是容易出现粘包问题。
面向数据报是指读写数据的时候以数据报为单位。一次必须读取一个数据报的长度,但不容易出现粘包问题。
4.全双工/半双工
全双工是指一个通信链路支持双向通信
半双工是指一个通信链路只支持单向通信
3.使用socket api进行编程
1.UDP服务器
这是操作系统提供的功能,Java进行了封装。这里我们先讲解基于UDP协议的写法。
1.DatagramSocket
计算机中的文件广义上还能代指硬件设备,将它们抽象成文件。这里我们将网卡抽象成socket文件,操作网卡的时候和普通的文件差不多,打开(也会在文件描述符表分配一个表项)->读写->关闭。直接操作网卡不好操作,把网卡操作转换成socket文件操作更加方便。
1.构造方法
DatagramSocket()
创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int port)
创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务器)
2.DatagramPacket
这个类表示一个完整的UDP数据报
1.构造方法
UDP数据报的载荷可以通过构造方法来指定
DatagramPacket(byte[] buf, int length)
构造一个DatagramPacket用来接收数据报,接收的数据报保存在字节数组,指定长度
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)
构造一个DatagramPacket用来接收数据报,接收的数据报保存在字节数组,指定数组下标,数组长度,目的IP和端口号
2.receive/send
1.void receive(DatagramPacket p)
接收数据报,没有接收到会阻塞等待
2.void send(DatagramPacket p)
发送数据报
3.代码示例
这里我们使用回显服务器,回显服务器是指响应和请求都是相同的服务器。我们实现的功能是用户输入一个字符串,服务器返回这个字符串。
1.服务器代码
代码展示
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {private 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就表示一个UDP数据报,此处传入的字节数组保存UDP的载荷部分DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);//把读取到的二进制数据转化成字符串,只读取有效的部分String request = new String(requestPacket.getData(), 0, requestPacket.getLength());//2.根据请求,计算响应(服务器最关键的逻辑)//因为我们写的是回显服务器,所以这个步骤省略了String response = process(request);//3.把响应返回给客户端//根据response构造DatagramPacket返回给客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length, requestPacket.getSocketAddress());socket.send(responsePacket);}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer udpEchoServer = new UdpEchoServer(9090);udpEchoServer.start();}
}
解析
1. socket对象代表网卡文件,读这个文件相当于从网卡收数据,写这个文件相当于向网卡发数据
2.启动服务器,在循环中做三件事
3. 读取请求并解析
a)构造DatagramPacket对象,这个对象就代表UDP数据报,有表头和载荷(创建字节数组来保存数据)
b)调用receive接收数据,这里使用的是输出型参数,所以虽然我们是接收一个UDP数据报,但我们还是创建了一个空的DatagramPacket对象。
c)根据字节数组构造纯出一个String
4.根据请求计算响应
5.把响应返回给客户端
这里构造响应的数据报时,传入了字节数组作为载荷,指定了数组下标和有效长度,传入了目的端口和IP。
6.socket不用close
一个文件是否要关闭,需要考虑这个文件的生命周期,这里的socket对象自始至终都会伴随整个UDP服务器,如果服务器关闭,会自动释放PCB的文件描述附表里面的所有资源,所以就不用手动关闭了。
2.客户端代码
import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;//UDP本身不保存对端的信息,所以我们在自己的代码保存一下private String serverIp;private int serverPort;//和服务器不同,这里的构造方法需要指定访问服务器的地址public UdpEchoClient(String serverIp, int serverPort) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;//这里的DatagramSocket不推荐使用固定端口号,如果客户端是固定端口,//很可能在这个程序运行的时候指定的端口被其他程序占用了,客户端在用户手上,//程序员不能控制socket = new DatagramSocket();}public void start() throws IOException {Scanner scanner = new Scanner(System.in);//1.从控制台读取用户输入的内容System.out.println("请输入要发送的内容");String request = scanner.next();//2.把请求放松给服务器,需要构造DatagramPacket对象//构造过程中,不光要构造载荷,还要指定服务器的IP和端口号DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);//3.发送数据报socket.send(requestPacket);//4.接收服务器的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);//5.把从服务器读取出来的数据开始解析,打印出来String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}public static void main(String[] args) throws IOException {//127.0.0.1是一个环回ip,非常特殊,无论你的主机是什么,都可以用这个ip表示当前主机,相当于thisUdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1", 9090);udpEchoClient.start();}
}
2.TCP服务器
因为TCP服务器进行网络通信的基本单位是字节,所以它不像UDP服务器的那样有DatagramPacket类作为基本单位,可以直接使用InputStream/OutputStream。
1.ServerSocket
这个类是专门给服务器用的,作为一开始的牵头人,和客户端建立连接后,就会使用Socket和客户端进行通信
ServerSocket(int port)
创建一个服务器端流套接字,并指定端口号
accept()
和客户端进行连接
2.Socket
这个类服务器和客户端都会使用
Socket(String host, int port)
这两个参数指的是需要指定的服务器IP和端口号
InputStream getInputStream()/OutputStream getOutputStream()
这两个方法是字节流对象
3.代码解析和修改
初始服务器代码
public class TcpEchoServer {private ServerSocket serverSocket= null;//这里和Udp服务器类似,也是在构造的时候指定端口号public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");while(true) {//对于tcp来说,需要向处理客户端发过来的连接//通过读写clientSocket和客户端进行通信//如果没有客户端发送连接,那么accept就会阻塞Socket clientSocket = serverSocket.accept();processConnection(clientSocket);}}//处理一个客户端的连接//可能涉及多个客户端的连接和响应,这里暂不涉及private void processConnection(Socket clientSocket) {try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);PrintWriter writer = new PrintWriter(outputStream);//处理三个步骤while(true) {//1.读取请求并解析,可以直接read,也可以借助scannerif(!scanner.hasNext()) {break;}String request = scanner.next();//2.根据请求计算响应String response = procoss(request);//3.返回响应到客户端writer.println(response);}} catch (IOException e) {e.printStackTrace();}}private String procoss(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}
初始客户端代码
public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int port) throws IOException {//这里可以直接使用字符串的ip作为参数socket = new Socket(serverIp, port);}public void start() {Scanner scanner = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {//为了方便使用,套壳操作Scanner scannerNet = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);//从控制台读取请求String request = scanner.next();//发送给服务器printWriter.println(request);//获取服务器的响应String response = scannerNet.next();//打印到控制台System.out.println(response);} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1", 9090);tcpEchoClient.start();}
}
问题1
当我们把客户端关闭再启动时,输入数据服务器没有响应。原因在于println只是把数据写入“发送缓冲区”,并没有真正写入网卡,此时我们需要用flush方法来属性缓冲区,让数据真正写入网卡。
问题2
这里的pringln里的ln是加上了换行,如果这里我们把ln删去,那么数据能发送过去,而服务器接收不到。
因为hasNext是以空白符(换行,回车,制表符,翻页符...)为基准,遇到空白符则是一个完整的next(),否则就会阻塞。
编写客户端代码的时候是需要约定请求和响应之间的分隔符的,这里我们使用的是\n
问题3
如果没有客户端连接,就会阻塞在accept这里
如果客户端不发送请求, 就会阻塞在hasNext这里
我们的服务器无法同时等待accept和客户端请求,当我们在等待客户端发送请求时,如果这时有新的客户端想要连接进来,就无法连接。
在这个场景下,我们就能引入多线程,让一个线程专门负责连接服务器。同时可以引入线程池优化效率。
问题4
服务器的socket要记得及时关闭,因为这个socket的生命周期不再是跟随整个服务器了
问题5
当我们的客户端多到一定程度时,服务器无法承担,此时我们就可以使用操作系统中内置的IO多路复用,这个操作本质上是让一个线程处理多个客户端的请求。多个客户端发送数据大概率不是同时的,客户端很可能在阻塞等待。
优化后服务器代码
public class TcpEchoServer {private ServerSocket serverSocket= null;//这里和Udp服务器类似,也是在构造的时候指定端口号public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {ExecutorService executorService = Executors.newCachedThreadPool();System.out.println("启动服务器");while(true) {//对于tcp来说,需要向处理客户端发过来的连接//通过读写clientSocket和客户端进行通信//如果没有客户端发送连接,那么accept就会阻塞//主线程负责进行accept,每次accept到一个新客户端,就创建一个新线程来处理客户端的请求Socket clientSocket = serverSocket.accept();executorService.submit(() -> {processConnection(clientSocket);});}}//处理一个客户端的连接//可能涉及多个客户端的连接和响应,这里暂不涉及private void processConnection(Socket clientSocket) {try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);PrintWriter writer = new PrintWriter(outputStream);//处理三个步骤while(true) {//1.读取请求并解析,可以直接read,也可以借助scannerif(!scanner.hasNext()) {break;}String request = scanner.next();//2.根据请求计算响应String response = procoss(request);//3.返回响应到客户端writer.println(response);writer.flush();}} catch (IOException e) {e.printStackTrace();}}private String procoss(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}
优化后客户端代码
public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int port) throws IOException {//这里可以直接使用字符串的ip作为参数socket = new Socket(serverIp, port);}public void start() {Scanner scanner = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {//为了方便使用,套壳操作Scanner scannerNet = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);//从控制台读取请求String request = scanner.next();//发送给服务器printWriter.println(request);//加上刷新缓冲区操作,才是真正写入网卡printWriter.flush();//获取服务器的响应String response = scannerNet.next();//打印到控制台System.out.println(response);} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1", 9090);tcpEchoClient.start();}
}
相关文章:
网络编程初识
注:此博文为本人学习过程中的笔记 1.socket api 这是操作系统提供的一组api,由传输层向应用层提供。 2.传输层的两个核心协议 传输层的两个核心协议分别是TCP协议和UDP协议,它们的差别非常大,编写代码的风格也不同,…...
疾病传播模拟 ——python实操
1、需求 疾病传播模拟 定义一个Infection类,包含初始感染人数、每日感染率等属性,以及一个simulate_spread方法用于模拟疾病传播过程。 使用numpy随机生成初始感染人数(范围1-100)和每日感染率(范围0.01-0.1)。 创建Infection对象,模拟10天的疾病传播过程,每天计算感染…...
用docker ffmpeg测试视频vmaf分数,很快不用编译
之前测试vmaf要自己编译libvmaf,自己编译ffmpeg,巨麻烦,或者用老旧不再维护的docker仓库,最近在docker hub上发现了编译了libvmaf的ffmpeg的docker,而且镜像很小,适合直接运行。 # dest.mp4 评分视频&…...
【浅学】Windows下ffmpeg+nginx+flv将本地视频推流在本地搭建的Web前端页面中播放,超详细步骤
Nginx安装和配置 下载nginx-1.19.3-http-flv 模块预编译包并解压放在d盘,路径就跟安装步骤里说的一样(如下图),不然会有其他问题出现。 打开conf/nginx.conf,查看RTMP和http相关的配置,确认端口号和路由名称 ffpemg推流视频…...
SQL笔记——左连接、右连接、内连接
前言:总是忘记表连接的区别,在面试的时候也容易被问到,因此就好记性不如烂笔头吧 集合运算 有并集、交集、差集 联合查询*(针对行合并的)* union为关键字,就是将两个select的结果求并集(此时重…...
iOS启动优化:从原理到实践
前言 在iOS应用开发中,启动速度是影响用户体验的重要因素之一。研究表明,启动时间每增加1秒,用户留存率就会下降约7%。本文将深入探讨iOS启动优化的各个方面,从底层原理到具体实践,帮助开发者打造更快的应用启动体验。…...
202553-sql
目录 一、196. 删除重复的电子邮箱 - 力扣(LeetCode) 二、602. 好友申请 II :谁有最多的好友 - 力扣(LeetCode) 三、176. 第二高的薪水 - 力扣(LeetCode) 一、196. 删除重复的电子邮箱 - 力扣…...
Socket-TCP
在TCP/ip协议中,用源IP、源端口号、目的IP、目的端口号、协议号这样一个五元组来标识一个通信! 端口号范围划分 0 - 1023: 知名端口号,HTTP,FTP,SSH 等这些广为使用的应用层协议,他们的端口号都是固定的。…...
BOSS的收入 - 华为OD机试(A卷,C++题解)
华为OD机试题库《C》限时优惠 9.9 华为OD机试题库《Python》限时优惠 9.9 华为OD机试题库《JavaScript》限时优惠 9.9 代码不懂有疑问欢迎留言或私我们的VX:code5bug。 题目描述 一个 XX 产品行销总公司,只有一个 boss,其有若干一级分销&…...
神经网络的基本概念与深度解析——基于生物机制的仿生建模与工程实现
广义上讲,神经网络是泛指生物神经网络与人工神经网络这两个方面。所谓生物神经网络是指由中枢神经系统(脑和脊髓)及周围神经系统(感觉神经、运动神经、交感神经、副交感神经等)所构成的错综复杂的神经网络,…...
JavaScript基础-运算符优先级
在JavaScript编程中,理解运算符的优先级是编写正确且高效代码的关键之一。当一个表达式包含多个运算符时,JavaScript会根据运算符的优先级来决定执行顺序。如果不了解这些规则,可能会导致意外的结果。本文将详细介绍JavaScript中的运算符优先…...
【RocketMQ NameServer】- NameServer 启动源码
文章目录 1. 前言2. RocketMQ 通信架构3. NameServer 启动流程3.1 创建 NameServerController3.2 启动 NameServerController3.3 NamesrvController#initialize3.3.1 Netty 通信的整体流程3.3.2 创建 NettyRemotingServer 3.4 this.remotingServer.start()3.4.1 this.remotingS…...
Learning vtkjs之WindowedSincPolyDataFilter
过滤器 模型简化(光滑处理) 介绍 像是对模型进行特征信息的简化(光滑处理) 效果 核心代码 主要流程 const fullScreenRenderer vtkFullScreenRenderWindow.newInstance({background: [0, 0, 0],rootContainer: vtkContainerR…...
C++ - 数据容器之 forward_list(创建与初始化、元素访问、容量判断、元素遍历、添加元素、删除元素)
一、创建与初始化 引入 <forward_list> 并使用 std 命名空间 #include <forward_list>using namespace std;创建一个空 forward_list forward_list<int> fl;创建一个包含 5 个元素,每个元素初始化为 0 的 forward_list forward_list<int&g…...
ES6/ES11知识点
ES 全称ECMAScript ,是脚本语言的规范,javascript是ES的一种实现。 作用域链 在 JavaScript 中,作用域链是一个非常重要的概念,它决定了变量和函数的访问顺序。掌握作用域链有助于深入理解执行上下文、闭包和变量查找等概念。 …...
力扣面试150题--二叉树的最大深度
Day 40 题目描述 做法 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right…...
360驱动大师v2.0(含网卡版)驱动工具软件下载及安装教程
1.软件名称:360驱动大师 2.软件版本:2.0 3.软件大小:218 MB 4.安装环境:win7/win10/win11 5.下载地址: https://www.kdocs.cn/l/cdZMwizD2ZL1?RL1MvMTM%3D 提示:先转存后下载,防止资源丢失&…...
Excel-CLI:终端中的轻量级Excel查看器
在数据驱动的今天,Excel 文件处理成为了我们日常工作中不可或缺的一部分。然而,频繁地在图形界面与命令行界面之间切换,不仅效率低下,而且容易出错。现在,有了 Excel-CLI,一款运行在终端中的轻量级Excel查看…...
AI Agent开发第48课-DIFY中利用AI动态判断下一步流程-DIFY调用API、REDIS、LLM
开篇 之前我们在《AI Agent开发第47课-DIFY处理多步流程慢?你确认用对了?》中讲述了DIFY的设计中在整合多步LLM时如避免过多调用LLM的良好设计,并给出了AI工作流的相应设计手法。今天我们要在上一篇的基础上把“上门维修预约”这个流程进一步按照实际业务需求加入用户在整个…...
C# 操作符
C# 操作符 一、操作符概览二、优先级与运算顺序三、各类操作符的实例 一、操作符概览 操作符(运算符)的本质是函数的简记法 操作符不能脱离与它关联的数据类型 int x 5; int y 4; int z x / y; Console.WriteLine(z);//输出1double a 5.0; double b…...
python下载
一、下载python和IDIE 1.进入python官网 加载可能有点慢,因为是国外网站 下载 点击Downloads按钮,选择版本下载。 安装 勾选两个多选框,点击Install Now安装完成,进入开始菜单,多出一个Python xxx.xxx文件夹&…...
tp5 php获取农历年月日干支甲午
# 切换为国内镜像源 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/# 再次尝试安装 composer require overtrue/chinese-calendar核心写法一个农历转公历,一个公历转农历 农历闰月可能被错误标记(例如 闰四月 应表示…...
MySQL安装完全指南:从零开始到配置优化(附避坑指南)
🔥 前言:为什么你总是装不好MySQL? (实话实说)每次看到新手在MySQL安装环节疯狂踩坑,老司机都忍不住想摔键盘!明明官网下载的安装包,怎么就会报错呢?为什么别人的环境变…...
5.3刷题
P3370 【模板】字符串哈希 #include<bits/stdc.h> using namespace std; #define int long long typedef unsigned long long ull; int n; ull myhash(string s){ull code 0, x 131, y 140814840257324663;for(int i 0; i < s.size(); i){code (code * x (ull)…...
KeyPresser 一款自动化按键工具
1. 简介 KeyPresser 是一款自动化按键工具,它可以与窗口交互,并支持后台运行, 无需保持被控窗口在前台运行。用户可以选择要操作的目标窗口,并通过勾选复选框来控制要发送哪些按键消息。可以从组合框中选择所需的按键,并在编辑框中输入时间间隔以控制按键发送之间的延迟。程…...
# LeetCode 1007 行相等的最少多米诺旋转
LeetCode 1007 行相等的最少多米诺旋转 原题英文:Minimum Domino Rotations For Equal Row 难度:中等 | 标签:数组、贪心 1 题目重述 给定两行长度相同的多米诺骨牌: tops[i] 表示第 i 张骨牌上面的数字;bottoms[…...
【Agent搭建】利用coze平台搭建一个AI销售?
目录 一、关于coze 核心功能 二、搭建属于你自己智能体 备注:(以下说明比较需要调整的板块) 1、从Prompt工程开始 2、搭建工作流 3、添加知识 三、总结 一、关于coze Coze是字节跳动推出的AI应用开发平台,专注于帮助用户快速…...
Linux系统中安装GitLab
一、安装前准备:确认系统要求(新手必看!) 系统版本:推荐 Ubuntu 20.04 或更高(本文以 Ubuntu 22.04 为例)。内存要求: 最低:2GB RAM(仅建议测试环境…...
PowerShell安装Chocolatey
文章目录 环境背景安装参考 环境 Windows 11 专业版PowerShell 7.5.1.NET Framework 4.0Chocolatey v2.4.3 背景 Chocolatey是Windows上的包管理工具,有点类似于Linux的 yum 和 apt 命令。比如,PowerShell里默认没有 grep 命令,则可以通过…...
UDP / TCP 协议
目录 一、前言: 数据封装与分用: 二、网络协议分层模型: 三、UDP / TCP 协议 UDP 协议: 1、UDP 协议段格式: 2、UDP 的特点: TCP 协议: 1、TCP 协议段格式: 2、TCP 协议的十…...
Coding Practice,48天强训(28)
Topic 1:悠悠的重组数组 游游的重组偶数__牛客网 比较简单的一个题,因为前两天写了快速幂算法,一直想着用进位 &1之类的处理偶数,其实就正常用string装数字遍历%2就行了 #include <bits/stdc.h> using namespace std;…...
第一章 初识SpringMVC
一、什么是MVC MVC是一种软件架构模式(是一种软件架构设计思想,不止Java开发中用到,其它语言也需要用到),它将应用分为三块: M:Model(模型) V:View…...
虚幻引擎入门笔记
【虚幻5】UE5新手入门尝试 虚幻引擎的基础设置 1.验证-当文件误删的时候,对其进行验证,可以恢复。 2.虚幻引擎极其强大,可以实现多种复合技能,所在创建项目页面可以看见不只是创建游戏的项目 3.更改虚幻引擎默认的缓存地址。有些…...
Oracle 11g通过dg4odbc配置dblink连接神通数据库
1、安装unixodbc 2、安装神通数据库 3、 配置神通数据库odbc数据源,测试连通性 4、配置透明网关、监听文件以及对应编写的hsodbc的ora文件,我这里是initst.ora ##对应编写的hsodbc的ora文件 vim $ORACLE_HOME/hs/admin/initst.ora ##添加如下 HS_FDS_CO…...
2.2 矩阵
考点一:方阵的幂 1. 计算方法 (1) 找规律法 适用场景:低阶矩阵或具有周期性规律的矩阵。示例: 计算 A ( 0 1 1 0 ) n A \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}^n A(0110)n: 当 n n n 为奇…...
Linux《进程概念(下)》
在之前我们已经了解了进程基本的概念、知道了如何去创建子进程;还了解了进程状态、进程切换、进程O(1)调度算法等,那么接下来在本篇当中我们就来学习环境变量和程序地址空间的相关知识,相信通过本篇的学习你会有很大的所获,一起加…...
MySQL 比较运算符详解
(1)符号类型运算符 运算符名称作用示例等于运算符判断两个值、字符串或表达式是否相等SELECT * FROM users WHERE age 25SELECT name FROM products WHERE category Electronics<>安全等于运算符安全地判断两个值、字符串或表达式是否相等&…...
No qualifying bean of type ‘XXX‘ available
没有某类型的bean可供使用 问题一解决方案错误问题配置类YuApiClientConfig依赖导入测试方法 问题二解决方法问题现场问题解决 问题一 Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.transbit.yuapiclientsd…...
手搓一个 MCP Server 实现水质在线数据查询
随着人工智能技术的快速发展,如何将大语言模型(LLM)与实际业务场景结合,提供精准、可控的服务成为一个热门话题。MCP(Model Context Protocol)作为一种开放协议,为应用程序向 LLM 提供标准化的上下文接口,极大地简化了这一过程。本文将以构建一个水质在线查询 MCP 服务…...
neo4j初尝试
neo4j 下载并安装 这里以ubuntu 下载为例 打开neo4j官网,如下图所示,找到下载中心 选择 每个人可以根据自己的系统进行下载。然后解压tar -xf neo4j-community-2025.04.0-unix.tar.gz,如果不出意外的话,这里就可以直接输入命令启动了&#…...
数据分析业务拆解底层思维
业务拆解 分析前要有方法,从用户体验入手,将业务拆解,找到对象以及对象之间的关系。 电商平台卖的不是用户时间,不是流量,而是机会,而作为一个分析师就得分析机会在哪,帮助平台将机会更好的提…...
Linux运维——Vim技巧一
Vim技巧 一、优化重复操作1.1、 . 命令1.2、* 命令1.3、重复修改示例 二、删除单词(daw)三、对数字做算数运算四、操作符与动作五、插入模式5.1、插入模式下删除5.2、返回普通模式5.3、插入-普通模式5.4、不离开插入模式,粘贴寄存器中的文本5…...
第一节:OpenCV 基础入门-简介与环境搭建
一、OpenCV 是什么?为什么值得学习? OpenCV(Open Source Computer Vision Library) 是一个开源的计算机视觉和机器学习库,由英特尔实验室于1999年发起,现已成为全球计算机视觉领域最广泛使用的工具之一。它…...
前端面经-VUE3篇(二)--vue3组件知识(一)组件注册、props 与 emits、透传、插槽(Slot)
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成一个层层嵌套的树状结构: 一、注册 Vue 组件本质上是一个可以复用的 自定义 HTML 元素,为了在其他组件中使用一…...
Python的简单练习
两数的最大公约数 def gcd(a, b):while b ! 0:a, b b, a % breturn a# 示例 a 36 b 60 print(f"{a} 和 {b} 的最大公约数是: {gcd(a, b)}") while b ! 0: while:是 Python 的 循环语句,意思是“当...的时候一直重复做某事”。 b ! 0&am…...
ipvsadm,是一个什么工具?
1. ipvsadm 是什么? ipvsadm(IP Virtual Server Administration)是 Linux 内核中 IPVS(IP Virtual Server) 模块的管理工具,用于配置和监控内核级的负载均衡规则。它是 Kubernetes 中 kube-proxy 在 IPVS …...
QT6 源(72):阅读与注释单选框这个类型的按钮 QRadioButton,及各种属性验证,
(1)按钮间的互斥: (2)源码来自于头文件 qradiobutton . h : #ifndef QRADIOBUTTON_H #define QRADIOBUTTON_H#include <QtWidgets/qtwidgetsglobal.h> #include <QtWidgets/qabstractbutton.h>…...
Qt 中实现观察者模式(Observer Pattern)
在 Qt 中实现**观察者模式(Observer Pattern)通常利用其内置的信号与槽(Signals & Slots)**机制,这是最符合 Qt 设计哲学的方式。以下是详细实现方法和关键点: —### 1. 观察者模式的核心思想- Subject(被观察者):维护一个观察者列表,在状态变化时通知观察者。- …...
Vue3源码学习5-不使用 `const enum` 的原因
文章目录 前言✅ 什么是 const enum❌ 为什么 Vue 3 不使用 const enum1. 📦 **影响构建工具兼容性**2. 🔁 **难以做模块间 tree-shaking**3. 🧪 **调试困难**4. 📦 **Vue 是库,不掌控用户配置** ✅ 官方推荐做法&…...
自己部署后端,浏览器显示久久未响应
CIDER地址写错了,应该要写成0.0.0.0/0 。。。。...