Socket网络编程(四)——点对点传输场景方案

目录

  • 场景
  • 如何去获取到TCP的IP和Port?
  • UDP的搜索IP地址、端口号方案
  • UDP搜索取消实现
    • 相关的流程:
    • 代码实现逻辑
      • 服务端实现
      • 客户端实现
      • UDP搜索代码执行结果
  • TCP点对点传输实现
    • 代码实现步骤
    • 点对点传输测试结果
  • 源码下载

场景

在一个局域网当中,不知道服务器的IP地址,仅仅知道服务器公共的UDP的端口,在这种情况下,想要实现TCP的连接。TCP是点对点的连接,所以需要知道TCP的连接IP地址和端口Port。

如何去获取到TCP的IP和Port?

可以通过UDP的搜索实现,

  1. 当我们的服务器与我们所有的客户端之间约定了搜索的格式之后,我们可以在客户端发起广播
  2. 然后服务器在收到广播之后判断一下这些收到的广播是否是需要处理的。那么服务器就会回送这些广播到对应的端口(地址)上去。
  3. 客户端就能收到服务器回送过来的UDP的包。收到的这些数据包,里面就包含了端口号、IP地址等。
  4. 根据以上的流程就能够UDP的搜索得到TCP服务器的IP地址和TCP的端口,然后使用这些信息来实现TCP的连接。

UDP的搜索IP地址、端口号方案

  1. 构建基础口令消息
    原理:如果要实现UDP的交互,就要约定一组公共的数据格式,也就是基础的口令头。如果没有约定口令消息,那么别人发送的消息到达我们的服务器后就会去回送,这就会导致我们自己的基本信息(比如IP\Port)的暴露。
  2. 局域网广播口令消息(指定端口)
  3. 接收指定端口回送消息(得到客户端IP、Port,这里的客户端IP指的是server端)

20240228-154508-t3.png
如上图,BroadCast发出广播,如果有设备(服务器)感兴趣就会回送到BroadCast。如果三台(服务器)都感兴趣,就都会回送到BroadCast。

UDP搜索取消实现

相关的流程:

  1. 异步线程接收回送消息
  2. 异步线程等待完成(定时)
  3. 关闭等待-终止线程等待

代码实现逻辑

服务端实现

  1. TCP/UDP基础信息字段
    TCPConstants.java
public class TCPConstants {// 服务器固化UDP接收端口public static int PORT_SERVER = 30401;
}
  1. UDP基础信息
    UDPConstants.java
public class UDPConstants {// 公用头部(8个字节都是7,就是可回复的)public static byte[] HEADER = new byte[]{7,7,7,7,7,7,7,7};// 服务器固化UDP接收端口public static int PORT_SERVER = 30201;// 客户端回送端口public static int PORT_CLIENT_RESPONSE = 30202;
}
  1. 工具类ByteUtils
    用于校验是否为正确的口令。即对HEADER进行校验。
public class ByteUtils {/*** Does this byte array begin with match array content?** @param source Byte array to examine* @param match  Byte array to locate in <code>source</code>* @return true If the starting bytes are equal*/public static boolean startsWith(byte[] source, byte[] match) {return startsWith(source, 0, match);}/*** Does this byte array begin with match array content?** @param source Byte array to examine* @param offset An offset into the <code>source</code> array* @param match  Byte array to locate in <code>source</code>* @return true If the starting bytes are equal*/public static boolean startsWith(byte[] source, int offset, byte[] match) {if (match.length > (source.length - offset)) {return false;}for (int i = 0; i < match.length; i++) {if (source[offset + i] != match[i]) {return false;}}return true;}/*** Does the source array equal the match array?** @param source Byte array to examine* @param match  Byte array to locate in <code>source</code>* @return true If the two arrays are equal*/public static boolean equals(byte[] source, byte[] match) {if (match.length != source.length) {return false;}return startsWith(source, 0, match);}/*** Copies bytes from the source byte array to the destination array** @param source      The source array* @param srcBegin    Index of the first source byte to copy* @param srcEnd      Index after the last source byte to copy* @param destination The destination array* @param dstBegin    The starting offset in the destination array*/public static void getBytes(byte[] source, int srcBegin, int srcEnd, byte[] destination,int dstBegin) {System.arraycopy(source, srcBegin, destination, dstBegin, srcEnd - srcBegin);}/*** Return a new byte array containing a sub-portion of the source array** @param srcBegin The beginning index (inclusive)* @param srcEnd   The ending index (exclusive)* @return The new, populated byte array*/public static byte[] subbytes(byte[] source, int srcBegin, int srcEnd) {byte destination[];destination = new byte[srcEnd - srcBegin];getBytes(source, srcBegin, srcEnd, destination, 0);return destination;}/*** Return a new byte array containing a sub-portion of the source array** @param srcBegin The beginning index (inclusive)* @return The new, populated byte array*/public static byte[] subbytes(byte[] source, int srcBegin) {return subbytes(source, srcBegin, source.length);}
}
  1. 服务器端接收约定数据包,解析成功并回送包的代码
    ServerProvider
public class ServerProvider {private static Provider PROVIDER_INSTANCE;static void start(int port){stop();String sn = UUID.randomUUID().toString();Provider provider = new Provider(sn, port);provider.start();PROVIDER_INSTANCE = provider;}static void stop(){if(PROVIDER_INSTANCE != null){PROVIDER_INSTANCE.exit();PROVIDER_INSTANCE = null;}}private static class Provider extends Thread{private final byte[] sn;private final int port;private boolean done = false;private DatagramSocket ds = null;// 存储消息的Bufferfinal byte[] buffer = new byte[128];public Provider(String sn, int port){super();this.sn = sn.getBytes();this.port = port;}@Overridepublic void run() {super.run();System.out.println("UDDProvider Started.");try {// 监听20000 端口ds = new DatagramSocket(UDPConstants.PORT_SERVER);// 接收消息的PacketDatagramPacket receivePacket = new DatagramPacket(buffer,buffer.length);while(!done){// 接收ds.receive(receivePacket);// 打印接收到的信息与发送者的信息// 发送者的IP地址String clientIp = receivePacket.getAddress().getHostAddress();int clientPort = receivePacket.getPort();int clientDataLen = receivePacket.getLength();byte[] clientData = receivePacket.getData();boolean isValid = clientDataLen >= (UDPConstants.HEADER.length + 2 + 4) && ByteUtils.startsWith(clientData,UDPConstants.HEADER);System.out.println("ServerProvider receive from ip:" + clientIp + "\tport:" + clientIp +"\tport:"+clientPort+"\tdataValid:"+isValid);if(!isValid){//无效继续continue;}// 解析命令与回送端口int index = UDPConstants.HEADER.length;short cmd = (short) ((clientData[index++] << 8) | (clientData[index++] & 0xff));int responsePort = (((clientData[index++]) << 24) |((clientData[index++] & 0xff) << 16) |((clientData[index++] & 0xff) << 8) |((clientData[index++] & 0xff)));// 判断合法性if( cmd == 1 && responsePort > 0){// 构建一份回送数据ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);byteBuffer.put(UDPConstants.HEADER);byteBuffer.putShort((short)2);byteBuffer.putInt(port);byteBuffer.put(sn);int len = byteBuffer.position();// 直接根据发送者构建一份回送信息DatagramPacket responsePacket = new DatagramPacket(buffer,len,receivePacket.getAddress(),responsePort);ds.send(responsePacket);System.out.println("ServerProvider response to:" + clientIp + "\tport:"+responsePort + "\tdataLen: " + len);}else {System.out.println("ServerProvider receive cmd nonsupport; cmd:" + cmd + "\tport:" + port);}}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}private void close() {if( ds != null ){ds.close();ds = null;}}/*** 提供结束*/void exit(){done = true;close();}}
}
  1. main方法启动类
public class Server {public static void main(String[] args) {ServerProvider.start(TCPConstants.PORT_SERVER);try{System.in.read();} catch (IOException e){e.printStackTrace();}ServerProvider.stop();}
}

客户端实现

客户端广播发送消息包代码

  1. 服务器端消息实体
    ServerInfo
public class ServerInfo {private String sn;private int port;private String address;public ServerInfo(int port, String address, String sn) {this.sn = sn;this.port = port;this.address = address;}省略set/get方法 ……}
  1. 客户端启动main方法类
public class Client {public static void main(String[] args) {// 定义10秒的搜索时间,如果超过10秒未搜索到,就认为服务器端没有开机ServerInfo info = ClientSearcher.searchServer(10000);System.out.println("Server:" + info);}
}
  1. 客户端接收服务器端回送与广播发送的具体逻辑
    ClientSearcher
public class ClientSearcher {private static final int LISTENT_PORT = UDPConstants.PORT_CLIENT_RESPONSE;public static ServerInfo searchServer(int timeout){System.out.println("UDPSearcher Started.");//  成功收到回送的栅栏CountDownLatch receiveLatch = new CountDownLatch(1);Listener listener = null;try{// 监听listener = listen(receiveLatch);// 发送广播sendBroadCast();// 等待服务器返回,最长阻塞10秒receiveLatch.await(timeout, TimeUnit.MILLISECONDS);}catch (Exception e){e.printStackTrace();}// 完成System.out.println("UDPSearcher Finished.");if(listener == null){return null;}List<ServerInfo> devices = listener.getServerAndClose();if(devices.size() > 0){return devices.get(0);}return null;}/*** 监听服务器端回送的消息* @param receiveLatch* @return* @throws InterruptedException*/private static Listener listen(CountDownLatch receiveLatch) throws InterruptedException {System.out.println("UDPSearcher start listen.");CountDownLatch startDownLatch = new CountDownLatch(1);Listener listener = new Listener(LISTENT_PORT, startDownLatch,receiveLatch);listener.start();   // 异步操作,开启端口监听startDownLatch.await();return listener;}/*** 发送广播逻辑* @throws IOException*/private static void sendBroadCast() throws IOException {System.out.println("UDPSearcher sendBroadcast started.");// 作为搜索方,让系统自动分配端口DatagramSocket ds = new DatagramSocket();// 构建一份请求数据ByteBuffer byteBuffer = ByteBuffer.allocate(128);// 头部byteBuffer.put(UDPConstants.HEADER);// CMD命名byteBuffer.putShort((short)1);// 回送端口信息byteBuffer.putInt(LISTENT_PORT);// 直接构建PacketDatagramPacket requestPacket = new DatagramPacket(byteBuffer.array(), byteBuffer.position() + 1);// 广播地址requestPacket.setAddress(InetAddress.getByName("255,255.255.255"));// 设置服务器端口requestPacket.setPort(UDPConstants.PORT_SERVER);// 发送ds.send(requestPacket);ds.close();// 完成System.out.println("UDPSearcher sendBroadcast finished.");}/*** 广播消息的接收逻辑*/private static class Listener extends Thread {private final int listenPort;private final CountDownLatch startDownLatch;private final CountDownLatch receiveDownLatch;private final List<ServerInfo> serverInfoList = new ArrayList<>();private final byte[] buffer = new byte[128];private final int minLen = UDPConstants.HEADER.length + 2 + 4; // 2:CMD命令长度  4:TCP端口号长度private boolean done = false;private DatagramSocket ds = null;private Listener(int listenPort,CountDownLatch startDownLatch,CountDownLatch receiveDownLatch){super();this.listenPort = listenPort;this.startDownLatch = startDownLatch;this.receiveDownLatch = receiveDownLatch;}@Overridepublic void run(){super.run();// 通知已启动startDownLatch.countDown();try{// 监听回送端口ds = new DatagramSocket(listenPort);// 构建接收实体DatagramPacket receivePacket = new DatagramPacket(buffer,buffer.length);while( !done){// 接收ds.receive(receivePacket);// 打印接收到的信息与发送者的信息// 发送者的IP地址String ip = receivePacket.getAddress().getHostAddress();int port = receivePacket.getPort();int dataLen = receivePacket.getLength();byte[] data = receivePacket.getData();boolean isValid = dataLen >= minLen&& ByteUtils.startsWith(data, UDPConstants.HEADER);System.out.println("UDPSearch receive form ip:" + ip + "\tport:" + port + "\tdataValid:" + isValid);if( !isValid ) {// 无效继续continue;}// 跳过口令字节,从具体数据开始ByteBuffer byteBuffer = ByteBuffer.wrap(buffer,UDPConstants.HEADER.length, dataLen);final short cmd = byteBuffer.getShort(); // 占据2个字节final int serverPort = byteBuffer.getInt(); // 占据4个字节if(cmd != 2 || serverPort <= 0){System.out.println("UDPSearcher receive cmd:" + cmd + "\tserverPort:" + serverPort);continue;}String sn = new String(buffer,minLen,dataLen - minLen);ServerInfo info = new ServerInfo(serverPort,ip,sn);serverInfoList.add(info);// 成功接收到一份receiveDownLatch.countDown();}}catch (Exception e){e.printStackTrace();}finally {close();}System.out.println("UDPSearcher listener finished.");}private void close(){if(ds != null){ds.close();ds = null;}}List<ServerInfo> getServerAndClose() {done = true;close();return serverInfoList;}}
}

UDP搜索代码执行结果

服务端启动接收的结果:

UDDProvider Started.
ServerProvider receive from ip:169.254.178.74	port:169.254.178.74	port:61968	dataValid:true
ServerProvider response to:169.254.178.74	port:30202	dataLen: 50

客户端监听并发起广播的执行结果:

UDPSearcher Started.
UDPSearcher start listen.
UDPSearcher sendBroadcast started.
UDPSearcher sendBroadcast finished.
UDPSearch receive form ip:169.254.178.74	port:30201	dataValid:true
UDPSearcher Finished.
Server:ServerInfo{sn='ed4ab162-5d5c-49eb-b80e-6ddeb8b223e0', port=30401, address='169.254.178.74'}
UDPSearcher listener finished.Process finished with exit code 0

由以上结果可知,启动服务端后,客户端在启动listen监听后,向服务器端发送数据包,并获得服务器端的回送,经解析后,该回送的数据包中可以获得 ip/port,可用于TCP连接使用。在UDP解析数据包过程中,通过口令保证了客户端与服务端对消息发送、接收、回送的有效,避免不必要的回应。

TCP点对点传输实现

基于前面UDP广播-搜索的机制,Server-Client获得了建立Socket链接的IP\Port信息。
可以接着使用该信息进行建立TCP的Socket连接,实现点对点的数据收发。

代码实现步骤

  1. TCP服务端main启动方法
public class Server {public static void main(String[] args) {TCPServer tcpServer = new TCPServer(TCPConstants.PORT_SERVER);boolean isSucceed = tcpServer.start();if(!isSucceed){System.out.println("Start TCP server failed.");}UDPProvider.start(TCPConstants.PORT_SERVER);try{System.in.read();} catch (IOException e){e.printStackTrace();}UDPProvider.stop();tcpServer.stop();}
}

在UDP搜索的基础上,我们获得了TCP的链接IP。创建tcpServer对相应的端口进行监听客户端链接请求。

  1. 服务端异步线程处理Socket
    TCPServer
public class TCPServer {private final int port;private ClientListener mListener;/*** 构造* @param port*/public TCPServer(int port){this.port = port;}/*** 开始* @return*/public boolean start(){try{ClientListener listener = new ClientListener(port);mListener = listener;listener.start();}catch (Exception e){e.printStackTrace();return false;}return true;}/*** 结束*/public void stop(){if(mListener != null){mListener.exit();}}/*** 监听客户端链接*/private static class ClientListener extends Thread {private ServerSocket server;private boolean done = false;private ClientListener(int port) throws IOException {server = new ServerSocket(port);System.out.println("服务器信息: " + server.getInetAddress() + "\tP:" + server.getLocalPort());}@Overridepublic void run(){super.run();System.out.println("服务器准备就绪~");// 等待客户端连接do{// 得到客户端Socket client = null;try {client = server.accept();}catch (Exception e){e.printStackTrace();}// 客户端构建异步线程ClientHandler clientHandler = new ClientHandler(client);// 启动线程clientHandler.start();}while (!done);System.out.println("服务器已关闭!");}void exit(){done = true;try {server.close();}catch (IOException e){e.printStackTrace();}}}/*** 客户端消息处理*/private static class ClientHandler extends Thread{private Socket socket;private boolean flag = true;ClientHandler(Socket socket ){this.socket = socket;}@Overridepublic void run(){super.run();System.out.println("新客户链接: " + socket.getInetAddress() + "\tP:" + socket.getPort());try {// 得到打印流,用于数据输出;服务器回送数据使用PrintStream socketOutput = new PrintStream(socket.getOutputStream());// 得到输入流,用于接收数据BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));do {// 客户端拿到一条数据String str = socketInput.readLine();if( "bye".equalsIgnoreCase(str)){flag = false;// 回送socketOutput.println("bye");}else {// 打印到屏幕,并回送数据长度System.out.println(str);socketOutput.println("回送: " + str.length());}}while (flag);socketInput.close();socketOutput.close();}catch (IOException e){System.out.println("连接异常断开");}finally {// 连接关闭try {socket.close();}catch (IOException e){e.printStackTrace();}}System.out.println("客户端已退出:" + socket.getInetAddress() + "\tP:" + socket.getPort());}}
}

accept() 监听到客户端的链接后,通过输入流读取客户端数据,并通过输出流回送数据长度。

  1. 基于UDP回送结果建立的TCP客户端
    Client main方法
public class Client {public static void main(String[] args) {// 定义10秒的搜索时间,如果超过10秒未搜索到,就认为服务器端没有开机ServerInfo info = UDPSearcher.searchServer(10000);System.out.println("Server:" + info);if( info != null){try {TCPClient.linkWith(info);}catch (IOException e){e.printStackTrace();}}}
}

获得UDP的回送后,我们知道了建立TCP的ip、port。也就是serverInfo不为null,取出相关参数建立Socket 链接。

  1. 建立客户端连接类
    TCPClient
public class TCPClient {public static void linkWith(ServerInfo info) throws IOException {Socket socket = new Socket();// 超时时间socket.setSoTimeout(3000);// 端口2000;超时时间300mssocket.connect(new InetSocketAddress(Inet4Address.getByName(info.getAddress()),info.getPort()));//System.out.println("已发起服务器连接,并进入后续流程~");System.out.println("客户端信息: " + socket.getLocalAddress() + "\tP:" + socket.getLocalPort());System.out.println("服务器信息:" + socket.getInetAddress() + "\tP:" + socket.getPort());try {// 发送接收数据todo(socket);}catch (Exception e){System.out.println("异常关闭");}// 释放资源socket.close();System.out.println("客户端已退出~");}private static void todo(Socket client) throws IOException {// 构建键盘输入流InputStream in = System.in;BufferedReader input = new BufferedReader(new InputStreamReader(in));// 得到Socket输出流,并转换为打印流OutputStream outputStream = client.getOutputStream();PrintStream socketPrintStream = new PrintStream(outputStream);// 得到Socket输入流,并转换为BufferedReaderInputStream inputStream = client.getInputStream();BufferedReader socketBufferedReader = new BufferedReader(new InputStreamReader(inputStream));boolean flag = true;do {// 键盘读取一行String str = input.readLine();// 发送到服务器socketPrintStream.println(str);// 从服务器读取一行String echo = socketBufferedReader.readLine();if("bye".equalsIgnoreCase(echo)){flag = false;}else {System.out.println(echo);}}while(flag);// 资源释放socketPrintStream.close();socketBufferedReader.close();}
}

建立Socket链接,从键盘读取一行发送到服务器;并从服务器读取一行。以上就是基于UDP广播-搜索实现TCP点对点传输的逻辑。

点对点传输测试结果

基于UDP实现的TCP服务端日志

服务器信息: 0.0.0.0/0.0.0.0	P:30401
服务器准备就绪~
UDDProvider Started.
ServerProvider receive from ip:169.254.178.74	port:169.254.178.74	port:51322	dataValid:true
ServerProvider response to:169.254.178.74	port:30202	dataLen: 50
新客户链接: /169.254.178.74	P:57172
ping
pong

基于UDP实现的TCP客户端日志:

UDPSearcher start listen.
UDPSearcher sendBroadcast started.
UDPSearcher sendBroadcast finished.
UDPSearch receive form ip:169.254.178.74	port:30201	dataValid:true
UDPSearcher Finished.
Server:ServerInfo{sn='10595790-14d1-44dc-a068-4c64c956a944', port=30401, address='169.254.178.74'}
UDPSearcher listener finished.
已发起服务器连接,并进入后续流程~
客户端信息: /169.254.178.74	P:57172
服务器信息:/169.254.178.74	P:30401
ping
回送: 4
pong
回送: 4

源码下载

下载地址:https://gitee.com/qkongtao/socket_study/tree/master/src/main/java/cn/kt/socket/SocketDemo_L5_UDP

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

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

相关文章

26、Qt调用.py文件中的函数

一、开发环境 Qt5.12.0 Python3.7.8 64bit 二、使用 新建一个Qt项目&#xff0c;右击项目名称&#xff0c;选择“添加库” 选择“外部库”&#xff0c;点击“下一步” 点击“浏览”&#xff0c;选择Python安装目录下的libs文件夹中的“python37.lib”文件&#xff0c;点击“下…

gpt批量工具,gpt批量生成文章工具

GPT批量工具在今天的数字化时代扮演着越来越重要的角色&#xff0c;它们通过人工智能技术&#xff0c;可以自动批量生成各种类型的文章&#xff0c;为用户提供了便利和效率。本文将介绍5款不同的GPT批量工具&#xff0c;并介绍一款知名的147GPT生成工具&#xff0c;以及另外一款…

TypeScript学习

TypeScript 是一种基于 JavaScript 构建的强类型编程语言。 ts不是js的替代只是为了大型项目更好的扩展&#xff0c;微软编写的一个强类型的脚本。 ts中对参数&#xff0c;变量&#xff0c;返回值 都有限制&#xff0c;不像js那么随意&#xff0c;类的定义也更严格&#xff0…

[unity] c# 扩展知识点其一 【个人复习笔记/有不足之处欢迎斧正/侵删】

.NET 微软的.Net既不是编程语言也不是框架,是类似于互联网时代、次时代、21世纪、信息时代之类的宣传口号,是一整套技术体系的统称&#xff0c;或者说是微软提供的技术平台的代号. 1.跨语言 只要是面向.NET平台的编程语言(C#、VB、 C、 F#等等)&#xff0c;用其中一种语言编写…

雅马哈伺服器TS-S系列说明具体详情内容可参看PDF目录内容

雅马哈伺服器TS-S系列说明具体详情内容可参看PDF目录内容

快递平台独立版小程序源码|带cps推广营销流量主+前端

源码介绍&#xff1a; 快递代发快递代寄寄件小程序可以对接易达云洋一级总代 快递小程序&#xff0c;接入云洋/易达物流接口&#xff0c;支持选择快递公司&#xff0c;三通一达&#xff0c;极兔&#xff0c;德邦等&#xff0c;功能成熟 如何收益: 1.对接第三方平台成本大约4元…

低密度奇偶校验码LDPC(七)——SPA和积译码算法的简化

一、SPA译码算法的实际应用 查找表与拟合 盒加SPA译码器 二、SPA译码算法的简化算法 最小和算法(MSA) 归一化最小和算法(Normalized MSA, NMSA) 偏移最小和算法(Offset MSA, OMSA) 三、NMSA算法的Matlab实现 function [x_hat, iter_this_time] Layered_NMSA_BP_decoder(ll…

【C语言】linux内核xmit_one函数

一、中文注释 static int xmit_one(struct sk_buff *skb, struct net_device *dev,struct netdev_queue *txq, bool more) {unsigned int len;int rc;// 如果全局ptype列表或者设备特定的ptype列表不为空&#xff0c;则执行网络接口层网络层的NIT&#xff08;Network Tap&…

GenAI助力DevOps,塑造软件工程的未来

自 2022 年以来&#xff0c;GenAI 无疑已成为一种普遍的技术趋势。在本文中&#xff0c;我们将探索 DevOps 中令人兴奋的 GenAI 领域&#xff0c;讨论其潜在优势、局限性、新兴趋势和最佳实践&#xff0c;深入了解 AI 支持的 DevOps 前沿世界&#xff0c;并探索这一强大组合如何…

31-k8s集群svc的代理模式-iptables修改为ipvs

一、概述 学到这里&#xff0c;我们都知道&#xff0c;k8s集群的外部网络分发&#xff0c;借助kube-proxy组件来完成&#xff1b; 问题&#xff1a;我们为什么要将代理模式修改为ipvs而不继续使用iptables呐&#xff1f; 因为&#xff1a; 1&#xff0c;iptables底层使用四表五…

SpringBoot整合Redis及其持久化机制(二)

SpringBoot整合Redis及其持久化机制 1、Redis全局命令1.2、Redis事务 2、Redis持久化2.1、RDB方式2.1.1、客户端触发机制2.1.2、服务端触发机制2.2.3、配置生成快照名称和位置2.2.4、优点2.2.5、缺点 2.2、AOF方式2.2.1、优点2.2.2、缺点 2.3、RDB-AOF混合方式2.4、持久化机制的…

路由守卫:前置守卫和后置守卫

聚沙成塔每天进步一点点 本文内容 ⭐ 专栏简介路由守卫&#xff1a;前置守卫和后置守卫1. 前置守卫使用方式全局前置守卫局部前置守卫 2. 后置守卫使用方式全局后置守卫 案例&#xff1a;路由跳转前后权限验证总结 ⭐ 写在最后 ⭐ 专栏简介 Vue学习之旅的奇妙世界 欢迎大家来到…