《Java-SE-第三十一章》之网络编程

前言

在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!”

博客主页:KC老衲爱尼姑的博客主页

博主的github,平常所写代码皆在于此

共勉:talk is cheap, show me the code

作者是爪哇岛的新手,水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!


文章目录

  • 网络编程
    • 为什么需要网编程?
    • 什么是网络编程
    • 网络编程中的基本概念
      • 发送端和接收端
      • 请求和响应
      • 客户端和服务端
      • 常见的客户端服务端模型
    • Socket套接字
      • 概念
      • 套接字分类
        • Java数据报套接字通信模型
        • Java流套接字通信模型
      • UDP数据报套接字编程
          • UDP客户端服务器回显服务程序
          • UDP客户端服务器简单翻译服务程序
      • TCP流套接字编程
        • TCP客户端服务器回显服务程序
      • TCP中的长短连接
        • 一发一收(短连接)

网络编程

为什么需要网编程?

&ebsp;&ebsp;当我们使用浏览器进行搜索时,浏览器会根据关键字搜索出视频,图片文本等资源,这些资源都属于网络资源。网络资源相比于本地资源来说更加的丰富多彩。而这些网络资源都需要通过网络编程来进行数据传输。

什么是网络编程

&ebsp;&ebsp;网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络数据传输。但是,同一台主机上的不同进程,如果是基于网络来进行通信,也属于网络编程。

在这里插入图片描述

网络编程中的基本概念

发送端和接收端

在一次网络数据传输时:

发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。

接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。

收发端:发送端和接收端两端,也简称为收发端。

注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。

在这里插入图片描述

请求和响应

一般来说,获取一个网络资源,涉及到两次网络数据传输:

第一次:请求数据的发送,告诉服务端我要获取xx资源。

第二次:响应数据的发送,服务端返回给客户端xx资源。

举个栗子,这就好比,在外面吃饭,你跟老板说来一份青椒炒肉,自然就会给你提供一份青椒炒肉。
在这里插入图片描述

客户端和服务端

服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务,就像我们平时用的B站app上面的视频,图片等资源,都是通过网络从服务器上得到数据,然后通过网络传输到app上。

客户端获取服务的一方进程,称为客户端。简单来说就是各种软件。

对于服务来说,一般是提供:

  • 客户端获取服务资源

在这里插入图片描述

  • 客户端保存资源在服务端
    在这里插入图片描述

举个栗子, 银行提供了存款服务,用户(客户端)把钱(资源)存在银行(服务端)。同时银行提供了取款服务,用户可以去银行取钱(获得服务端资源)。

常见的客户端服务端模型

最常见的场景,客户端是指给用户使用的程序,服务端是提供用户服务的程序:

  1. 客户端先发送请求到服务端

  2. 服务端根据请求数据,执行相应的业务处理

  3. 服务端返回响应:发送业务处理结果

  4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)

在这里插入图片描述

Socket套接字

概念

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程

套接字分类

  1. 流套接字:使用传输层TCP协议,对于字节流来说,可以简单的理解为,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。
  2. 数据报套接字:使用传输层UDP协议,对于数据报来说,可以简单的理解为,传输数据是一块一块的,发送一块数据假如100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节。
  3. 原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。

Java数据报套接字通信模型

在这里插入图片描述

以上只是一次发送端的UDP数据报发送,及接收端的数据报接收,并没有返回的数据。也就是只有请求,没有响应。对于一个服务端来说,重要的是提供多个客户端的请求处理及响应,流程如下:

在这里插入图片描述

Java流套接字通信模型

在这里插入图片描述

UDP数据报套接字编程

DatagramSocket API

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

DatagramSocket 构造方法:

方法签名方法说明
DatagramSocket ()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket (int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)

DatagramSocket 方法:

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报。

DatagramPacket 构造方法:

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组
DatagramPacket(byte[] buf,int offset,int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组。address指定目的主机的IP和端口号

DatagramPacket 方法

InetAddress
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端的ip
int getPort()接收端主机IP地址从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端的主机和端口号
byte[] getData()取接收端主机端口号获取数据报中的数据

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

InetSocketAddress API

InetSocketAddress ( SocketAddress 的子类 )构造方法:

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号
UDP客户端服务器回显服务程序

回显程序就是客户端向服务端发送什么,服务端就返回给客户端什么,就像在夜深人静的时候,你突然说了一句话,然后无形你听到了一句一模一样你刚说的话。

客户端代码设计

  1. .创建客户端DatagramSocket
  2. 准备要发送的数据
  3. .组装要发送的UDP数据报,包含数据,及发送的服务端信息
  4. 发送UDP数据报

代码示例

import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {/***/private DatagramSocket clientSocket;/*** 服务器IP地址*/private String serverIp;/*** 服务器端口号*/private int serverPort;public UdpEchoClient(String ip, int port) throws SocketException {//客户端可以自己指定端口号,也可以让系统自动分配,但是自己指定的端口号可能已经被使用了,所以系统分配端口号更好this.clientSocket = new DatagramSocket();this.serverIp = ip;this.serverPort = port;}/*** 启动客户端* @throws IOException*/public void start() throws IOException {//1. 获取用户输入的数据Scanner sc = new Scanner(System.in);while (true) {System.out.print("请输入需要发送的数据->");String request = sc.next();//2. 根据用户输入的数据,将数据打包,待发送DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);// 3.发送数据clientSocket.send(requestPacket);// 4.接收请求DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);clientSocket.receive(responsePacket);String response = new String(responsePacket.getData(), 0, responsePacket.getLength(), "UTF-8");System.out.printf("我的请求: %s, 它的回应: %s\n", request, response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();}
}

服务端代码设计

  1. 创建服务端DatagramSocket
  2. 创建数据报,用于接收客户端发送的数据
  3. 等待客户端数据,一旦得到构造数据报
  4. 返回数据

代码示例

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {/***  准备好socket实例,准备传输*/private DatagramSocket serverSocket;/***指定端口* @param port* @throws SocketException*/public UdpEchoServer(int port) throws SocketException {this.serverSocket = new DatagramSocket(port);}/*** 启动服务器* @throws IOException*/public void start() throws IOException {System.out.println("服务器准备就绪!");while (true) {//1. 读取客户端的请求DatagramPacket requestPacket = new DatagramPacket(new byte[1024], 1024);//参数为储存数据的数组与最大空间大小serverSocket.receive(requestPacket);//2. 解析收到的数据包,一般解析成字符串进行处理String request = new String(requestPacket.getData(), 0, requestPacket.getLength(), "UTF-8");//3. 处理请求String response = process(request);//4. 发送请求,因为数据的传输是依据DatagramPacket来进行传输的,所以我们需要先包装在发送//除此之外,我们还需要知道客户端的地址和端口号//接收DatagramPacket对象时。该对象里面存有客户端的地址和端口号。可以使用getSocketAddress方法获取DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());serverSocket.send(responsePacket);//5. 输出发送日志System.out.printf("[%s:%d] 收到的请求: %s, 回应: %s\n",requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);}}/*** .处理数据,回显服务直接将原数据返回即可* @param data* @return*/public String process(String data) {return data;}public static void main(String[] args) throws IOException {UdpEchoServer udpEchoServer = new UdpEchoServer(9090);udpEchoServer.start();}
}

运行结果:
在这里插入图片描述

在这里插入图片描述

UDP客户端服务器简单翻译服务程序

翻译其实就是利用了哈希表,我们只需要将中文中的词和英文中相对应意思的词一一对应,全部存放在哈希表中,这样就 构成了一个词库。当需要将中文翻译好成英文的时候,就只需要在哈希表中查找对应的英文。对应该程序我们只需将上述的服务端代码中的处理请求的部分稍加修改就行。

翻译服务端代码

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;public class UdpDictServer extends UdpEchoServer{//最简单的翻译处理服务器private final HashMap<String, String> dict = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);dict.put("cat", "小猫");dict.put("dog", "小狗");dict.put("bird", "小鸟");}@Overridepublic String process(String data) {return dict.getOrDefault(data, "词库没有该单词!");}public static void main(String[] args) throws IOException {UdpDictServer server = new UdpDictServer(9090);server.start();}
}

运行结果:
在这里插入图片描述
在这里插入图片描述

TCP流套接字编程

ServerSocket API

ServerSocket 是创建TCP服务端Socket的API。

ServerSocket 构造方法:

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

Socket API

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法:

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

TCP客户端服务器回显服务程序

TCP和UDP不同,TCP是需要建立连接,并且通过对文件读写的方式以字节为单位进行传输。对于TCP传输,java 中提供了2个类来进行数据的传输,一个是ServerSocket,用于服务端接受客户端的连接,另一个是Socket,用于服务端和客户端之间的通信。

TCP客户端服务器简单翻译服务程序

客户端程序设计:

  1. 创建Socket对象
  2. 初始化服务端的ip和端口
  3. 启动客户端,发送数据并接收返回数据

示例代码

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {/*** 创建Socket对象*/private Socket socket;/**** @param serverIP  服务端ip* @param serverPort 服务端口* @throws IOException*/public TcpEchoClient(String serverIP, int serverPort) throws IOException {socket = new Socket(serverIP, serverPort);}/*** 启动客户端*/public void start() {System.out.println("客户端启动成功!");//用户输入数据Scanner input = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream()) {try (OutputStream outputStream = socket.getOutputStream()) {while (true) {//请输入数据System.out.print("请输入需要传输的数据!->");String request = input.next();//发送数据PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);//刷新缓冲区printWriter.flush();//接收回应Scanner receiverScanner = new Scanner(inputStream);String response = receiverScanner.next();//输出数据System.out.printf("我的请求:%s 它的回应:%s\n", request, response);}}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9092);client.start();}
}

服务端设计:

  1. 创建socket对象,初始化端口
  2. 接收客户端的数据,返回客户端的数据。

示例代码

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoServer {/***  创建socket对象*/private ServerSocket serverSocket;/***  初始化服务端端口*/public TcpEchoServer(int port) throws IOException {this.serverSocket = new ServerSocket(port);}/*** 启动服务器* @throws IOException*/public void start() throws IOException {System.out.println("服务器准备就绪!");while (true) {// 3. 接收客户端的数据Socket clientSocket = serverSocket.accept();// 4. 接收 处理 回应数据processContain(clientSocket);}}private void processContain(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 服务器正式与客户端建立连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());try (InputStream inputStream = clientSocket.getInputStream()) {try (OutputStream outputStream = clientSocket.getOutputStream()) {//接收数据 使用Scanner比InputStream的原生方法read更方便Scanner receiveScanner = new Scanner(inputStream);while (true) {if (!receiveScanner.hasNext()) {System.out.printf("[%s:%d] 服务器与客户端已经断开连接!\n", clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = receiveScanner.next();//处理数据String response = process(request);//发送数据,为了方便,我们可以使用PrintWriter类将OutputStream类对象包裹起来,就是用来把数据打印到文件里面PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);//及时刷新缓冲区printWriter.flush();//输出回应信息System.out.printf("[%s:%d] 收到的请求: %s  回应: %s\n", clientSocket.getInetAddress().toString(),clientSocket.getPort(), request, response);}}}catch (IOException e) {e.printStackTrace();} finally {//释放资源 相当于挂断电话clientSocket.close();}}public String process(String data) {return data;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9092);server.start();}
}

运行结果:
在这里插入图片描述
在这里插入图片描述

上述服务端代码无法处理多个客户端的请求,因为每次建立连接服务端只能和一个客户端连接,当服务端和客户端建立连接后,处理数据会进入processContain方法,如果此时又有一个客户端尝试建立连接发送数据,就无法跳出processContain中的循环去建立新的连接,导致客户端和服务端连接不上,为了解决上述问题,可以使用线程,每次建立连接就分配一个线程去处理该连接。

线程版服务端代码

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoServer {/***  创建socket对象*/private ServerSocket serverSocket;/***  初始化服务端端口*/public TcpEchoServer(int port) throws IOException {this.serverSocket = new ServerSocket(port);}/*** 启动服务器* @throws IOException*/public void start() throws IOException {System.out.println("服务器准备就绪!");while (true) {// 3. 接收客户端的数据Socket clientSocket = serverSocket.accept();// 4. 接收 处理 回应数据Thread t= new Thread(() -> {try {processContain(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});t.start();}}private void processContain(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 服务器正式与客户端建立连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());try (InputStream inputStream = clientSocket.getInputStream()) {try (OutputStream outputStream = clientSocket.getOutputStream()) {//接收数据 使用Scanner比InputStream的原生方法read更方便Scanner receiveScanner = new Scanner(inputStream);while (true) {if (!receiveScanner.hasNext()) {System.out.printf("[%s:%d] 服务器与客户端已经断开连接!\n", clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = receiveScanner.next();//处理数据String response = process(request);//发送数据,为了方便,我们可以使用PrintWriter类将OutputStream类对象包裹起来,就是用来把数据打印到文件里面PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);//及时刷新缓冲区printWriter.flush();//输出回应信息System.out.printf("[%s:%d] 收到的请求: %s  回应: %s\n", clientSocket.getInetAddress().toString(),clientSocket.getPort(), request, response);}}}catch (IOException e) {e.printStackTrace();} finally {//释放资源 相当于挂断电话clientSocket.close();}}public String process(String data) {return data;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9092);server.start();}
}

运行结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

server.png)]TCP客户端服务器简单翻译服务程序

该逻辑和UDP实现一致

示例代码

import java.io.IOException;
import java.util.HashMap;public class TcpDictServer extends TcpEchoServer{private final HashMap<String, String> dict = new HashMap<>();public TcpDictServer(int port) throws IOException {super(port);dict.put("cat", "小猫");dict.put("dog", "小狗");}@Overridepublic String process(String data) {return dict.getOrDefault(data, "词库为找到该单词!");}public static void main(String[] args) throws IOException {TcpDictServer server = new TcpDictServer(9092);server.start();}
}

运行结果:
在这里插入图片描述

TCP中的长短连接

TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:

  • 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。

  • 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

对比以上长短连接,两者区别如下:

  • 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。

  • 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。

  • 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等.

一发一收(短连接)

以下为一个客户端一次数据发送,和服务端多次数据接收(一次发送一次接收,可以接收多次),即只有客户端请求,但没有服务端响应的示例:

TCP服务端

示例代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TcpServer {//服务器socket要绑定固定的端口private static final int PORT = 8888;public static void main(String[] args) throws IOException {// 1.创建一个服务端ServerSocket,用于收发TCP报文ServerSocket server = new ServerSocket(PORT);// 不停的等待客户端连接while (true) {System.out.println("------------------------------------------------ ---");System.out.println("等待客户端建立TCP连接...");// 2.等待客户端连接,注意该方法为阻塞方法Socket client = server.accept();System.out.printf("客户端IP:%s%n",client.getInetAddress().getHostAddress());System.out.printf("客户端端口号:%s%n", client.getPort());// 5.接收客户端的数据,需要从客户端Socket中的输入流获取System.out.println("接收到客户端请求:");InputStream is = client.getInputStream();// 为了方便获取字符串内容,可以将以上字节流包装为字符流BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));String line;// 一直读取到流结束:TCP是基于流的数据传输,一定要客户端关闭Socket输出流才表示服务端接收IO输入流结束while ((line = br.readLine()) != null) {System.out.println(line);}// 6.双方关闭连接:服务端是关闭客户端socket连接client.close();}}
}

如果没有客户端请求,此时代码是阻塞等待在 server.accept() 代码行,直到有新的客户端申请建立连接。

TCP客户端

示例代码

import java.io.*;
import java.net.Socket;public class TcpClient {//服务端IP或域名private static final String SERVER_HOST = "localhost";//服务端Socket进程的端口号private static final int SERVER_PORT = 8888;public static void main(String[] args) throws IOException {// 3.创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接Socket client = new Socket(SERVER_HOST, SERVER_PORT);// 4.发送TCP数据,是通过socket中的输出流进行发送OutputStream os = client.getOutputStream();// 为了方便输出字符串作为发送的内容,可以将以上字节流包装为字符流PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));// 4-1.发送数据:pw.println("hello world!");// 4-2.有缓冲区的IO操作,真正传输数据,需要刷新缓冲区pw.flush();// 7.双方关闭连接:客户端关闭socket连接client.close();}
}

运行结果:

在这里插入图片描述
在这里插入图片描述

客户端向服务端发送数据后就会重新断开连接,而服务端不会断开会等待下一个客户端的连接。


各位看官如果觉得文章写得不错,点赞评论关注走一波!谢谢啦!。

在这里插入图片描述

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

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

相关文章

Windows环境利用QT+CMake编译mingw版本的opencv

Opencv官网没有提供mingw版本的opencv库&#xff0c;所以需要自己编译&#xff0c;下面是编译过程&#xff0c;32位64位方法类似。 可以直接下载编译好的mingw版本opencv4.4&#xff1a; 使用CMAKE3.22QT5.13编译后的opencv4.4&#xff08;32位的&#xff09;资源-CSDN文库 …

Python实战之使用Python进行数据挖掘详解

一、Python数据挖掘 1.1 数据挖掘是什么&#xff1f; 数据挖掘是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中&#xff0c;通过算法&#xff0c;找出其中的规律、知识、信息的过程。Python作为一门广泛应用的编程语言&#xff0c;拥有丰富的数据挖掘库&#…

抖音seo源码·源代码搭建·支持二开(开源)系统

抖音seo源码&#xff0c;抖音seo系统&#xff0c;抖音搜索排名&#xff0c;源码系统开发 场景&#xff1a;公认的视频发布功能可是必备的&#xff0c;智能剪辑和智能客服更不用说&#xff0c;作为产品中粉丝转化的重要一环也是必不可少的 抖音seo源码开发&#xff0c;即抖音搜…

Linux:shell脚本:基础使用(2)

test命令 格式1&#xff1a;test 条件表达式 格式2&#xff1a;[ 条件表达式 ] (前后至少应有一个空格) 常用的测试操作符 -d&#xff1a;测试是否为目录&#xff08;Directory) -e&#xff1a;测试目录或文件是否存在&#xff08;Exist&#xff09; -f&#xff1a;测试是否…

使用go-zero快速构建微服务

本文是对 使用go-zero快速构建微服务[1]的亲手实践 编写API Gateway代码 mkdir bookstore && cd bookstorego mod init bookstore mkdir api && goctl api -o api/bookstore.api syntax "v1"info(title: "xx使用go-zero"desc: "xx用…

文件或目录损坏且无法读取

如上图报错&#xff0c;我们直接用cmd命令输入【CHKDSK C: /F】然后回车 电脑重启后可以了&#xff0c;希望能帮助各位小伙伴

算法通关村——迭代实现二叉树的前中后序遍历

前言 递归就是每次执行方法调用都会先把当前的局部变量、参数值和返回地址等压入栈中&#xff0c;后面在递归返回的时候&#xff0c;从栈顶弹出上一层的各项参数继续执行&#xff0c;这就是递归为什么能够自动返回并执行上一层的方法的原因。因此&#xff0c;我们也可以模拟一个…

HBase Shell 操作

1、基本操作 1.1、进入HBase客户端命令行 前提是先启动hadoop集群和zookeeper集群。 bin/hbase shell 1.2、查看帮助命令 helphelp 查看指定命令的语法规则 查看 list_namespace 的用法&#xff08;‘记得加单引号’&#xff09; help list_namespace 2、namespace 我们…

EVE-NG MPLS 静态 LSP

1 拓扑 2 配置步骤 2.1 配置接口IP 和路由 LER1 interface GigabitEthernet1/0ip address 10.1.1.1 255.255.255.0quitinterface GigabitEthernet2/0ip address 11.1.1.1 255.255.255.0quitip route-static 21.1.1.0 24 10.1.1.2VPC1 ip 11.1.1.100/24 11.1.1.1 配置完成后…

应用在室外LED电子显示屏中的MiniLED背光

LED电子显示屏是一种通过控制半导体发光二极管的显示方式&#xff0c;是由几万–几十万个半导体发光二极管像素点均匀排列组成。它利用不同的材料可以制造不同色彩的LED像素点&#xff0c;以显示文字、图形、图像、动画、行情、视频、录像信号等各种信息的显示屏幕。 LED显示屏…

【100天精通python】Day30:使用python操作数据库_数据库基础入门

专栏导读 专栏订阅地址&#xff1a;https://blog.csdn.net/qq_35831906/category_12375510.html 1 数据库基础知识介绍 1.1 什么是数据库&#xff1f; 数据库是一个结构化存储和组织数据的集合&#xff0c;它可以被有效地访问、管理和更新。数据库的目的是为了提供一种可靠的…

让三驾马车奔腾:华为如何推动空间智能化发展?

上个月&#xff0c;国务院常务会议审议通过了《关于促进家居消费的若干措施》&#xff0c;其中明确提出了“推动单品智能向全屋智能发展创新培育智能消费”“开展数字家庭建设试点”等推动全屋智能拼配发展的建议与方案。 可以说&#xff0c;以整屋为单位的空间智能品类&#x…

基于Java+SpringBoot+Vue的时间管理系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

数据链路层概述

数据传输过程如下&#xff1a; 数据包按上述过程传输&#xff0c;详见&#xff08;计算机网络概述三&#xff09;。在分析数据链路层时可以假象成其沿着水平传播。 这三段链路层的传播方式可能会有所不同。 基本概念&#xff1a; 链路&#xff1a;指一个节点到相邻节点的一段物…

influxDB

文章目录 版本2.0 数据结构Organization 组织Bucket 存储桶Measurementtagfieldtimestamp retention policy (RP) 保留策略Point 一条数据Series 一组数据 写入gzip压缩 查询FluxInfluxQL 官网 https://docs.influxdata.com/v1.8 中文翻译文档 https://influxdb-v1-docs-cn.cno…

MFC第二十九天 CView类的分支(以及其派生类的功能)、MFC六大关键技术

文章目录 CView类的分支CEditViewCHtmlViewMainFrm.h CMainFrame 类的接口CMainView .h CListCtrl与CListView的创建原理 CTreeViewCTreeCtrl类简介CTreeCtrl类的原理以及常用功能 MFC六大关键技术视图和带分割栏的框架开发与消息路由CLeftView.cppCRightView.hCRightView.cppC…

Flink多流处理之connect拼接流

Flink中的拼接流connect的使用其实非常简单,就是leftStream.connect(rightStream)的方式,但是有一点我们需要清楚,使用connect后并不是将两个流给串联起来了,而是将左流和右流建立一个联系,作为一个大的流,并且这个大的流可以使用相同的逻辑处理leftStream和rightStream,也可以…

【golang】工作区与GOPATH

在学习go语言时&#xff0c;我们会从官网下载go语言的二进制包&#xff0c;然后解压并安装到某个目录&#xff0c;最后会配置环境变量&#xff0c;通过输入命令go version来验证是否安装成功。 配置了path环境后&#xff0c;我们还需要再配置3个环境变量&#xff0c;GOROOT、G…

完美的分布式监控系统——Prometheus(普罗米修斯)与优雅的开源可视化平台——Grafana(格鲁夫娜)

一、基本概念 1、之间的关系 prometheus与grafana之间是相辅相成的关系。作为完美的分布式监控系统的Prometheus&#xff0c;就想布加迪威龙一样示例和动力强劲。在猛的车也少不了仪表盘来观察。于是优雅的可视化平台Grafana出现了。 简而言之Grafana作为可视化的平台&#xff…

在excel调用SAP函数执行SAP数据查找或提交

1、下载插件 2、安装插件 3、执行函数 3.1 第一步 通过SAPRegister连接SAP服务器 var reg SAPRegister("10.10.14.15", "00", "mes", "AQ123456", "800") 需要改为实际的连接信息 "10.10.14.15" 为SAP服务器I…