Java——网络编程(中)—TCP通讯(下)

news2024/12/17 1:58:40

1 双向通讯—创建服务端

(双向通信是指通信双方中,任何一方都可为发送端,任何一方都可为接收端)

(1 创建ServerSocket对象,accept()返回socket)

(2 双向通讯——>也要创建键盘输入对象)

(3 通过与客户端对应的Socket对象获取输入流对象)

(4 通过与客户单对应的Socket对象获取输出流对象)

(5 while(true)里面读取消息和发送消息——>顺序不能乱)

(但是顺序永远先是——>服务端读取客户端发送的消息——>然后在向客户端发送消息)




public class TwoWaySocketServer {
  public static void main(String[] args) {
      
    System.out.println("服务端启动!监听端口8888。。。。");
    try(ServerSocket serverSocket = new ServerSocket(8888);
      Socket socket = serverSocket.accept();
      //创建键盘输入对象
      Scanner scanner = new Scanner(System.in);
      //通过与客户端对应的Socket对象获取输入流对象
      BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      //通过与客户单对应的Socket对象获取输出流对象
      PrintWriter pw = new PrintWriter(socket.getOutputStream());){


      while(true){
        //读取客户端发送的消息
        String str = br.readLine();
        System.out.println("客户端说:"+str);
        String keyInput = scanner.nextLine();
        //发送到客户端
        pw.println(keyInput);
        pw.flush();
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}










2 双向通讯—创建客户端

(1 创建Socket对象,传递IP和端口号)

(2 创建键盘输入对象)

(3 通过与服务端对应的Socket对象获取输入流对象——>读服务端发送过来的消息)

(4 通过与服务端对应的Socket对象获取输出流对象——>给服务端发送消息)

(5 while(true)里面发信息和读取消息——>顺序不能乱)

(但是现在有一个问题,就是接收消息和发送消息都在同一个线程当中,那么同一个线程的代码在执行时,完全是一个串行化的执行过程,所以他就没有办法让一个人说两句,只能你说一句我说一句——>如何能实现二者之间不受制约的相互的想说几句就说几句呢——>就要使用多线程了——>点对点通讯)




public class TwoWaySocketClient {
  public static void main(String[] args) {
    try(Socket socket = new Socket("127.0.0.1", 8888);
      //创建键盘输入对象
      Scanner scanner = new Scanner(System.in);
      //通过与服务端对应的Socket对象获取输入流对象
      BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      //通过与服务端对应的Socket对象获取输出流对象
      PrintWriter pw = new PrintWriter(socket.getOutputStream());){


      while (true) {
        String keyInput = scanner.nextLine();
        pw.println(keyInput);
        pw.flush();
        String input = br.readLine();
        System.out.println("服务端说:" + input);
       }
     } catch (Exception e) {
      e.printStackTrace();
     }
   }
}











3 点对点通讯—创建客户端

(之前对于发送消息和接收消息都放在一个线程里来实现的会冲突——>这次放在两个线程里面——>相当于点对点的聊天)

(1 主线程启动服务端——>加上发送消息的线程——>加上接受消息的线程)

(2 主线程里——>socket对象不能放在try里面了,主线程结束会把对象释放,socket对象没有就相当于与客户端断开连接了——>所以要放在try外面——>无论是接收还是发送消息都是通过这个socket对象获得输入和输出流的——>再吧socket对象分别传入2个线程之中)

(3 发送消息的线程——>主线程传递进来的socket——>用构造方法传进来——>重写run方法,把方法写外面,run里面调用——>创建键盘输入和向客户端输出消息的输出流——>while(true)多次发送消息——>先从键盘获取,再通过输出流输出——>在主线程里——>将与客户端对应的Socket对象传递给发送消息的线程,并启动该线程)

(4 接收消息的线程——>和发送消息的线程一样——>构造方法传进来socket——>重写run——>只需要创建缓冲字符流转换流读取客户端的消息——>while(true)多次读——>在主线程里——>将与客户端对应的Socket对象传递给接收消息的线程,并启动该线程)

(5 主线程里面的ServerSocket 是可以关闭掉的,因为一旦建立连接他们是平等的他们都是socket——>二者通讯的Socket别关闭就可以了)





/**
 * 发送消息线程----------------------------------------------------------------------------
 */
class Send extends Thread{

  private Socket socket;		//主线程传递进来的socket
  public Send(Socket socket){	//用构造方法传进来
    this.socket = socket;
   }
    	
  @Override						//重写run方法,把方法写外面,run里面调用
  public void run() {
    this.sendMsg();
   }
  /**
   * 发送消息
   */
  private void sendMsg(){		//创建键盘输入和向客户端输出消息的输出流
    //创建Scanner对象
    try(Scanner scanner = new Scanner(System.in);
      //创建向对方输出消息的流对象
      PrintWriter pw = new PrintWriter(this.socket.getOutputStream());){


      while(true){			    //多次发送消息
        String msg = scanner.nextLine();//先从键盘获取
        pw.println(msg);				//再通过输出流输出	
        pw.flush();						//刷新
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}


/**
 * 接收消息的线程---------------------------------------------------------------------------
 */
class Receive extends Thread{
  private Socket socket;
  public Receive(Socket socket){
    this.socket = socket;
   }
  @Override
  public void run() {
    this.receiveMsg();


   }
  /**
   * 用于接收对方消息的方法
   */
  private void receiveMsg(){
    //创建用于接收对方发送消息的流对象
    try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));){


      while(true){
        String msg = br.readLine();
        System.out.println("他说:"+msg);
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}

//主线程----------------------------------------------------------------------------------
public class ChatSocketServer {
  public static void main(String[] args) {


    try(ServerSocket serverSocket = new ServerSocket(8888);){
      System.out.println("服务端启动,等待连接。。。。。");
      Socket socket = serverSocket.accept();	//放在外面
      System.out.println("连接成功!");
        
      new Send(socket).start();
      new Receive(socket).start();
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}










4 点对点通讯—创建服务器

(和创建客户端方式差不多)

(1 主线程里面创建socket对象,给定IP和端口——>要写在try外面)

(2 发送消息的线程,与服务端对应的socket对象,构造方法传递,重写run方法,创建Scanner和PrinrWriter对象,while(true)一直发送,拿到信息,打印,刷新,主线程中实例化,开启线程)

(3 接收消息的线程,与服务端对应的socket对象,构造方法传递,重写run方法,创建BufferedReader和InputStreamReader对象,while(true)一直读取,按行读,打印,主线程中实例化,开启线程)






/**
 * 用于发送消息的线程类----------------------------------------------------------------------
 */
class ClientSend extends Thread{
  private Socket socket;
  public ClientSend(Socket socket){
    this.socket = socket;
   }
  @Override
  public void run() {
    this.sendMsg();
   }
  /**
   * 发送消息
   */
  private void sendMsg(){
    //创建Scanner对象
    try(Scanner scanner = new Scanner(System.in);
      //创建向对方输出消息的流对象
      PrintWriter pw = new PrintWriter(this.socket.getOutputStream());){


      while(true){
        String msg = scanner.nextLine();
        pw.println(msg);
        pw.flush();
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}
/**
 * 用于接收消息的线程类----------------------------------------------------------------------
 */
class ClientReceive extends Thread{
  private Socket socket;
  public ClientReceive(Socket socket){
    this.socket = socket;
   }
  @Override
  public void run() {
    this.receiveMsg();
   }
  /**
   * 用于接收对方消息的方法
   */
  private void receiveMsg(){
    //创建用于接收对方发送消息的流对象
    try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));){


      while(true){
        String msg = br.readLine();
        System.out.println("他说:"+msg);
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}


//主线程----------------------------------------------------------------------------------
public class ChatSocketClient {
  public static void main(String[] args) {
    try {
        
      Socket socket = new Socket("127.0.0.1", 8888);
      System.out.println("连接成功!");
        
      new ClientSend(socket).start();
      new ClientReceive(socket).start();
        
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}










5 点对点通讯—优化

(在上述代码中,会发现有大量代码,相似的是极高的

——>在使用TCP协议做消息发送时,他们仅是在链接时会有客户端跟服务端的一个角色的区分,一旦链接上了,那么他们都是相同的身份的,那就没必要弄一个客户端和服务端,把二者何为一起——>只是在连接时,在程序当中区分一下谁是服务端谁是客户端)

(1 对于主线程来说区分客户端还是服务端取决于,输入的是什么,启动服务端就创建serverSocket,客户端就创建Socket,——>但就不能用这个 try-with-resources了,用finally关闭资源——>Scanner,serverSocket,socket都创建在外面——>实例化键盘输入——>根据输入选择启动什么端,用字符串数组按照逗号分隔,启动服务端和客户端)

(2 发送消息线程——>构造方法得到socket,Scanner两个参数,重写run方法,创建向对方输出消息的流对象PrintWriter——>while(true)一直发送,拿到信息,打印,刷新,主线程中实例化,开启线程)

(3 接收消息线程——>构造方法得到socket,重写run方法,创建用于接收对方发送消息的流对象BufferedReader 和InputStreamReader——>while(true)一直读取,按行读,打印,主线程中实例化,开启线程)

(现在已经可以实现了点对点的通讯,但是目前一个服务器只能与一个客户端进行对应,如何实现一对多下面说)






/**
 * 发送消息线程----------------------------------------------------------------------------
 */
class Send extends Thread{
  private Socket socket;
  private Scanner scanner;
  public Send(Socket socket,Scanner scanner){
    this.socket = socket;
    this.scanner = scanner;
   }
  @Override
  public void run() {
    this.sendMsg();
   }
  /**
   * 发送消息
   */
  private void sendMsg(){


    //创建向对方输出消息的流对象
    try(PrintWriter pw = new PrintWriter(this.socket.getOutputStream())){
      
      while(true){
        String msg = scanner.nextLine();
        pw.println(msg);
        pw.flush();
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}


/**
 * 接收消息的线程---------------------------------------------------------------------------
 */
class Receive extends Thread{
  private Socket socket;
  public Receive(Socket socket){
    this.socket = socket;
   }
  @Override
  public void run() {
    this.receiveMsg();
   }
  /**
   * 用于接收对方消息的方法
   */
  private void receiveMsg(){
    //创建用于接收对方发送消息的流对象
    try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()))){


      while(true){
        String msg = br.readLine();
        System.out.println("他说:"+msg);
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}



//主线程----------------------------------------------------------------------------------
public class GoodTCP {
  public static void main(String[] args) {
    
      
    Scanner scanner = null;
    ServerSocket serverSocket = null;
    Socket socket = null;
    try{
      scanner = new Scanner(System.in);
      System.out.println("请输入:server,<port> 或者:<ip>,<port>");
      String str = scanner.nextLine();
      String[] arr = str.split(",");
        
        
      if("server".equals(arr[0])){
        //启动服务端
        System.out.println("TCP Server Listen at "+arr[1]+" .....");
        serverSocket = new ServerSocket(Integer.parseInt(arr[1]));
        socket = serverSocket.accept();
        System.out.println("连接成功!");


       }else{
        //启动客户端
        socket = new Socket(arr[0],Integer.parseInt(arr[1]));
        System.out.println("连接成功!");
       }
      //启动发送消息的线程
      new Send(socket,scanner).start();
      //启动接收消息的线程
      new Receive(socket).start();
        
        
     }catch(Exception e){
      e.printStackTrace();
     }finally{
      if(serverSocket != null){
        try {
          serverSocket.close();
         } catch (IOException e) {
          e.printStackTrace();
         }
       }
     }
   }
}













6 一对多通讯—设计

(1 之前在主线程当中去创建的ServerSocket的对象,然后通过ServerSocket.accept方法来负责监听端口等待客户端的链接,如果这个时候有客户端根据IP和端口来访问来链接这个Serverocket了,那么这个ServerSocket.accept方法会返回与这个客户端所对应的Socket对象

——>我们把这个Socket对象传递到了用于发送消息的线程,又传递到了用于接收消息的线程

——>然后主线程结束了,accept方法也不会再执行了——>再有客户端来连接这个服务端也无法连接了

——>这是不能实现一个服务端对应多个客户端的一个最根本的原因)

(2 只要保证这个server Socket的点accept这个方法,也就是说这一块的代码,让它一直在运行就可以了,只要它一直在运行,只要有客户端来链接,他就会返回与这个客户端对应的Socket对象——>想对多个客户端进行连接就要获得多个Socket对象)

(3 如果有多个客户端来链接服务器的话——>客户端和客户端之间是!!!相互隔离的!!!——>他们之间是完全不能做消息共享的——>比如京东服务器链接很多用户,每个人只能看自己的购物车)

(4 把Socket socket =serversocket.accept();放在死循环里面,监听到之后再监听)










在这里插入图片描述












7 一对多—应答型服务器

(允许多个客户端来连接它,其次是支持当客户端向它发送消息时——>它会将这个消息原封不动的返回给客户端)

(1 主线程——>创建ServerSocket对象,把Socket socket = serverSocket.accept();放在死循环里)

(2 应答型服务器只需要一个线程就可以——>构造方法传进来socket,重写run方法,将从客户端读取到的消息写回给客户端——>读和写——>要创建BufferedReader,InputStreamReader,PrintWriter对象)





/**
 * 定义消息处理线程类-----------------------------------------------------------------------
 */
class Msg extends Thread{
  private Socket socket;
  public Msg(Socket socket){
    this.socket = socket;
   }
  @Override
  public void run() {
    this.msg();
   }


  /**
   * 将从客户端读取到的消息写回给客户端
   */
  private void msg(){
    try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
      PrintWriter pw = new PrintWriter(this.socket.getOutputStream())){
      while(true){
        pw.println(br.readLine()+" [ok]");
        pw.flush();
       }
     }catch(Exception e){
      e.printStackTrace();
      System.out.println(this.socket.getInetAddress()+" 断线了!");
     }
   }
}

//主线程----------------------------------------------------------------------------------
public class EchoServer {
  public static void main(String[] args) {
    try(ServerSocket serverSocket = new ServerSocket(8888)){
      //等待多客户端连接
      while(true){
        Socket socket = serverSocket.accept();
        new Msg(socket).start();
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}











8 一对多—聊天型服务器

(聊天服务器——>一个客户端所发送的信息——>这些消息服务器要负责发送给所有的客户端,让其他的客户端也能看到你当前客户端所发送的内容)

(服务器线程设计——>理解为接收线程就是消息的生产者,发送线程就是消息的接收者,我们现在要把这个交给发送线程将数据发送给不同的客户端——>在生产者与消费者这个模式当中对于数据的处理时需要依赖于一个数据缓冲区)



(线程说明——>服务器启动以后,缓冲区里面还没有东西,所有用于向客户端发送消息的线程都处于一个等待的状态——>什么时候公共数据区有消息了再去发送消息——>公共数据区的数据来源于接收消息的线程——>当有某个客户端向服务端发送数据了,那么这个时候在服务端用于接收客户端消息的线程会拿到这个数据——>把数据放到公共数据区里——>对于公共数据区的访问而言,接收线程和发送线程肯定是一个线程同步的——>在访问公共数据区时肯定会让这个线程拥有相同的对象锁的——>然后当接收线程把消息放到公共数据区以后——>去唤醒同一把锁的所有的线程(发送消息的线程)notifyALL——>唤醒所以的发送消息线程——>这些线程去公共数据区当中拿到数据并且把数据发送给对应的客户端——>发送消息的线程又处于等待状态)

(1 主线程——>创建ServerSocket对象,把Socket socket = serverSocket.accept();放在死循环里——>定义公共数据区(字符串)static类型的(唯一性) )

(2 发送消息的线程类——>与服务端对应的socket对象,构造方法传递,重写run方法,创建PrintWriter对象,while(true)一直发送,——>解决线程冲突synchronized (“abc”)给字符串——>让发送消息的线程处于等待状态wait()方法——>之后如果被唤醒——>将公共数据区中的消息发送给客户端)

(3 接收客户端消息的线程类——>构造方法得到socket,重写run方法,创建用于接收对方发送消息的流对象BufferedReader 和InputStreamReader——>while(true)一直读取——> synchronized (“abc”)让他们拥有相同的锁——>把读取到的数据写入公共数据区——>唤醒发送消息的线程对象——>notifyAll())








服务器设计

  1. 服务器的连接设计
    在这里插入图片描述

  2. 服务器的线程设计
    在这里插入图片描述

/**
 * 接收客户端消息的线程类--------------------------------------------------------------------
 */
class ChatReceive extends Thread{
  private Socket socket;
  public ChatReceive(Socket socket){
    this.socket =socket;
   }
  @Override
  public void run() {
    this.receiveMsg();
   }
  /**
   * 实现接收客户端发送的消息
   */
  private void receiveMsg(){


    try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()))){


      while(true){
        String msg = br.readLine();
        synchronized ("abc"){
          //把读取到的数据写入公共数据区
          ChatRoomServer.buf="["+this.socket.getInetAddress()+"] "+msg;
          //唤醒发送消息的线程对象。
          "abc".notifyAll();
         }
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}
/**
 * 向客户端发送消息的线程类------------------------------------------------------------------
 */
class ChatSend extends Thread{
  private Socket socket;
  public ChatSend(Socket socket){
    this.socket = socket;
   }
  @Override
  public void run() {
    this.sendMsg();
   }
  /**
   * 将公共数据区的消息发送给客户端
   */
  private void sendMsg(){


    try(PrintWriter pw = new PrintWriter(this.socket.getOutputStream())){


      while(true){
        synchronized ("abc"){
          //让发送消息的线程处于等待状态
          "abc".wait();
          //将公共数据区中的消息发送给客户端
          pw.println(ChatRoomServer.buf);
          pw.flush();
         }
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}


//主线程----------------------------------------------------------------------------------
public class ChatRoomServer {
  //定义公共数据区
  public static String buf;
  public static void main(String[] args) {
    System.out.println("Chat Server Version 1.0");
    System.out.println("Listen at 8888.....");
    try(ServerSocket serverSocket = new ServerSocket(8888)){


      while(true){
        Socket socket = serverSocket.accept();
        System.out.println("连接到:"+socket.getInetAddress());
        new ChatReceive(socket).start();
        new ChatSend(socket).start();
       }
     }catch(Exception e){
      e.printStackTrace();
     }
   }
}

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

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

相关文章

JavaFX使用jfoenix的UI控件

jfoenix还是一个不错的样式&#xff0c;推荐使用&#xff0c;而且也可以支持scene builder中的拖拖拽拽 需要注意的是过高的javafx版本可能会使得某些样式或控件无法使用 比如alert控件&#xff0c;亲测javaFX 19版本可以正常使用 1.在pom.xml中引入依赖 GitHub地址https://gi…

利用cnocr库完成中文扫描pdf文件的文字识别

很多pdf文件文字识别软件都会收费&#xff0c;免费的网页版可能会带来信息泄露&#xff0c;还有一些类似于腾讯AI和百度AI的接口都有调用次数限制&#xff0c;因此&#xff0c;利用识别正确率极高且免费的cnocr库来自己动手做个pdf文件文字识别程序就是一个很不错的选择。以下程…

大数据笔记之flink-cdc实时同步数据

大数据笔记之flink-cdc实时同步数据(mysql -->doris) 一、基本概念 Flink CDC 是一个基于流的数据集成工具&#xff0c;旨在为用户提供一套功能更加全面的编程接口&#xff08;API&#xff09;。 该工具使得用户能够以 YAML配置文件的形式&#xff0c;优雅地定义其 ETL&…

【数学】矩阵的逆与伪逆 EEGLAB

文章目录 前言matlab代码作用EEGLAB 中的代码总结参考文献 前言 在 EEGLAB 的使用中&#xff0c;运行程序时出现了矩阵接近奇异值&#xff0c;或者缩放错误。结果可能不准确。RCOND 1.873732e-20 的 bug&#xff0c;调查 EEGLAB 后发现是 raw 数据的问题。 matlab代码 A_1 …

RTMP推流平台EasyDSS在无人机推流直播安防监控中的创新应用

无人机与低空经济的关系密切&#xff0c;并且正在快速发展。2024年中国低空经济行业市场规模达到5800亿元&#xff0c;其中低空制造产业占整个低空经济产业的88%。预计未来五年复合增速将达到16.03%。 随着科技的飞速发展&#xff0c;公共安防关乎每一个市民的生命财产安全。在…

【记录49】vue2 vue-office在线预览 docx、pdf、excel文档

vue2 在线预览 docx、pdf、excel文档 docx npm install vue-office/docx vue-demi0.14.6 指定版本 npm install vue-office/docx vue-demi <template><VueOfficeDocx :src"pdf" style"height: 100vh;" rendere"rendereHandler" error&…

C# 探险之旅:第二十四节 - 类型class基础,一场“类”似的奇妙冒险

嘿&#xff0c;勇敢的探险家们&#xff01;欢迎来到C#王国的“类”似奇妙冒险&#xff01;今天&#xff0c;我们要深入探索一个神秘而强大的领域——class&#xff08;类&#xff09;。想象一下&#xff0c;class就像C#世界里的一块魔法土地&#xff0c;每块土地上都能孕育出独…

Burp suite 3 (泷羽sec)

声明 学习视频来自B站UP主 泷羽sec,如涉及侵泷羽sec权马上删除文章。 笔记只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 这节课旨在扩大自己在网络安全方面的知识面&#xff0c;了解网络安全领域的见闻&#xff0c;了…

cpptoml介绍

cpptoml 是一个用于 C 的开源库&#xff0c;旨在提供对 TOML&#xff08;Toms Obvious, Minimal Language&#xff09;格式的支持。它允许开发者轻松地在 C 项目中读取、解析和生成 TOML 格式的配置文件。cpptoml 是一个轻量级、易于使用的库&#xff0c;适用于那些希望将 TOML…

用户认证系统登录界面

下面是使用HTML和JavaScript实现的一个中文版登录界面&#xff0c;包含登录、注册和修改密码功能。注册成功后会显示提示信息&#xff0c;在登录成功后进入一个大大的欢迎页面。 1.代码展示 <!DOCTYPE html> <html lang"zh-CN"> <head><meta …

Pyside6 --Qt设计师--简单了解各个控件的作用之:Item Views

目录 一、List View二、Tree View三、Table View四、Column View 一、List View 学习方法和Buttons一样&#xff0c;大家自己在qt设计师上面在属性编辑区进行相应的学习&#xff01; 我就先紧着qt设计师的页面进行讲解&#xff0c;部分内容查自AI。 后面有什么好用的控件或者…

ArcGIS MultiPatch数据转换Obj数据

文章目录 ArcGIS MultiPatch数据转换Obj数据1 效果2 技术路线2.1 Multipatch To Collada2.2 Collada To Obj3 代码实现4 附录4.1 环境4.2 一些坑ArcGIS MultiPatch数据转换Obj数据 1 效果 2 技术路线 MultiPatch --MultipatchToCollada–> Collada --Assimp–> Obj 2.…

【mybatis】缓存

目录 1. mybatis的运行 1.1 引言 1.2 具体运行&#xff1a; 1.3 sqlSession 介绍local catch 2. 缓存 2.1 概念 2.2 使用缓存的原因 2.3 什么样的数据能使用缓存 3. Mybatis缓存 3.1 一级缓存 3.1.1 测试一级缓存 3.1.2 缓存失效的四种情况 $1 sqlSession不同 $…

ElasticSearch - 理解doc Values与Inverted Index倒排索引

文章目录 概述倒排索引&#xff1a;从图书馆的索引卡片谈起倒排索引的工作原理 docValues&#xff1a;从数据库的列式存储说起docValues的工作原理 docValues与倒排索引的对比两者的联系&#xff1a;组合使用&#xff0c;优化搜索与分析 小结 概述 在使用 Elasticsearch 进行大…

Python | 数据可视化中常见的4种标注及示例

在Python的数据可视化中&#xff0c;标注&#xff08;Annotation&#xff09;技术是一种非常有用的工具&#xff0c;它可以帮助用户更准确地解释图表中的数据和模式。在本文中&#xff0c;将带您了解使用Python实现数据可视化时应该了解的4种标注。 常见的标注方式 文本标注箭…

【原生js案例】如何实现一个穿透字体颜色的导航

普通的导航大家都会做&#xff0c;像这种穿透字体的导航应该很少见吧。高亮不是通过单独设置一个active类来设置字体高亮颜色&#xff0c;鼠标滑过导航项&#xff0c;字体可以部分是黑色&#xff0c;不分是白色&#xff0c;这种效果的实现 感兴趣的可以关注下我的系列课程【we…

前端中图标的使用

1 antd 使用inconfont.cn中的图标 <template><div class"icons-list"><icon-font type"icon-tuichu" /><icon-font type"icon-facebook" /><icon-font type"icon-twitter" /></div> </templ…

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 CNN-BiGRU,即卷积神经网络(CNN)与双…

医学分割数据集B超图片肝脏分割数据集labelme格式271张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;271 标注数量(json文件个数)&#xff1a;271 标注类别数&#xff1a;1 标注类别名称:["liver"] 每个类别标注的框数&#xf…

【目标检查】YOLO系列之:Triton 推理服务器Ultralytics YOLO11

Triton 推理服务器 1、引言2、Triton服务器2.1 什么是Triton Inference Server2.2 将YOLO11 导出为ONNX 格式2.3 设置Triton 模型库2.3.1 创建目录结构2.3.2 将导出的ONNX 模型移至Triton 资源库 2.4 运行Triton 推断服务器2.4.1 使用 Docker 运行Triton Inference Server2.4.2…