JAVA网络编程——socket套接字的介绍下(详细)

news2025/6/2 18:18:34

目录

前言

1.TCP 套接字编程 与 UDP 数据报套接字的区别

2.TCP流套接字编程 

API 介绍

TCP回显式服务器

Scanner 的多种使用方式

PrintWriter 的多种使用方式

 TCP客户端

3. TCP 服务器中引入多线程

结尾

前言

各位读者大家好,今天笔者继续更新socket套接字的下半部分,这部分承接上半篇的内容接着往下写

JAVA网络编程——socket套接字的介绍上(详细)-CSDN博客

上半篇博客笔者主要汇总了一些网络编程的基础知识,并介绍了UDP数据报套接字编程和代码案例

实现了一个简单的回显服务器和客户端

博客的主要内容如下:

1.TCP流套接字编程 与 UDP 数据报套接字的区别,并结合具体代码,说明两者在实现方式上的差异。

2.TCP流套接字 编程常用 API 和代码示例,并尝试引入多线程思路对服务端代码进行优化。

3.最后,笔者还将分享一些学习过程中遇到的问题和经验,希望能对读者有所启发。

本篇博客的内容会和上半篇博客有联系,但您依旧可以把他看作是独立的知识博客,无需太多阅读门槛,言尽于此,就让我们开始吧!

1.TCP 套接字编程 与 UDP 数据报套接字的区别

在实际编程之前,我们首先要了解:为什么 TCP 和 UDP 的套接字写法会有所不同?

 从传输层协议的角度来看, TCP和UDP是不同的协议

TCP 是一种面向连接的传输层协议,在通信前需要通过“三次握手”建立连接,通信过程中也会通过校验、序号、确认应答等机制保证数据的可靠传输。可以理解为,TCP 的通信就像是打电话,必须先拨号接通,双方确认后才能说话。

 而 UDP 是一种无连接的协议,发送数据前并不建立连接,也不会确认数据是否成功送达。UDP 更像是发快递,你把包裹投递出去就完事了,送达与否不做额外处理。这种机制导致 UDP 的通信过程更加简单高效,但也更容易出现数据丢失、乱序的问题。

也正因为如此,在编程中,两者的使用方式也大相径庭。

对于UDP套接字编程,正如前文提到的服务端通过 DatagramSocket 创建一个端口并监听,客户端发送数据时需要用 DatagramPacket 显式地指定目标 IP 和端口号。

  通俗来说 UDP就像发短信

  • 直接发送,不管对方是否收到
  • 发完就完了,不知道对方看没看到
  • 快速简单,但不保证送达

 相比之下,TCP 流套接字编程更加结构化。服务端使用 ServerSocket 来监听端口,当有客户端发起连接时,会通过 accept() 方法返回一个与客户端进行一对一通信的 Socket 对象。在这之后,服务端和客户端之间就建立起了一个稳定的通信通道,后续的通信就像操作输入输出流一样,不需要再关注 IP 和端口这些底层细节。

换句话说:TCP读取数据的基本单位是字节,TCP 协议本身是面向字节流(byte stream)的协议

 同样通俗的说 , TCP就像打电话

  • 拨号建立连接,确认对方接听后才开始说话
  • 说话过程中可以确认对方是否听到
  • 如果线路有问题会重新说一遍
  • 说完话要挂断电话结束通话

也就是说,UDP 更加“灵活”和“轻便”,每次通信都要说明来龙去脉(目标地址);而 TCP 则是“关系型”的,一旦连接建立,双方就可以安心地进行数据交换,程序的逻辑也更加清晰。

接下来笔者开始介绍API和代码示例,并介绍TCP套接字的代码是如何体现它和UDP的区别的. 

2.TCP流套接字编程 

 和UDP数据报套接字编程类似,TCP流套接字编程 同样有两个重要的API

API 介绍

1.ServerSocket
ServerSocket 这个类用于服务器端监听特定端口,等待客户端来连接。 它体现了 TCP 协议中"先建立连接,再通信”的特性。

 ServerSocket 构造方法

ServerSocket serverSocket = new ServerSocket(int port);

其中 int port 表示 监听的端口号 ,一旦绑定成功,port端口就会被占用,等待客户端连接

常用方法:

1.Socket accept()

    开始监听指定端⼝(创建时绑定的端⼝),有客⼾端连接后,返回⼀个服务端Socket对象,并基于该Socket建⽴与客⼾端的连接,否则阻塞等待
具体一点说:

accept() 方法执行以后:

服务器端和客户端之间就建立起了一条可靠的 TCP 连接,双方都会在系统内核中保存关于对方的关键信息,如:

  • 客户端的 IP 地址

  • 客户端的端口号

  • 服务器的 IP 地址

  • 服务器的端口号

这 4 个信息,加上传输协议(TCP),就构成了所谓的 “五元组”,唯一标识一条 TCP 连接。这也体现了 TCP协议和UDP协议之间的区别

2.Socket close()

    关闭此套接字

2. Socket

Socket 是客户端/服务端之间的通信通道

客户端和服务端之间每一次连接,都会被封装成一个 Socket 对象,负责双方的输入输出数据流。

Socket 构造方法

 构造方法(客户端使用):

Socket socket = new Socket(String host, int port);

其中 host 表示 IP 地址,port表示端口

常用方法:

1.InputStream getInputStream()


获取输入流,用于读取从对端发送过来的字节数据。

2.OutputStream getOutputStream()


获取输出流,用于向对端发送字节数据。

3.close()


关闭当前连接。

主要的API介绍完了,接下来我们通过代码示例来展示他们如何使用,笔者还是先展示一个回显服务器+客户端

TCP回显式服务器

根据上面对 ServerSocket 的介绍,我们可以知道:

在编写一个 TCP 回显式服务器时,首先需要创建一个 ServerSocket 实例并指定监听的端口号。这个操作会在当前机器上开启一个服务器进程,等待客户端的连接请求

一旦有客户端连接到这个端口,服务器就会通过 accept() 方法接收这个连接请求,并返回一个新的 Socket 对象。这个 Socket 对象就代表了服务器与某个客户端之间的一条通信通道

public class TcpEchoServer {
    ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        // 绑定端口号
//      和 UDP 不同,TCP 在通信前必须先建立连接(就是三次握手)。
// 所以服务器要做的第一件事:不是接收数据,而是 等待客户端来连我。
    }
}

然后我们启动服务器:

    public void start() throws IOException {
        System.out.println("服务器启动了");

        Socket socket = serverSocket.accept(); // 建立连接
        processwork(socket);
    }

 其中 processwork () 方法内来实现服务器的功能

而我们的服务器主要实现的功能为:

1.读取请求

2.响应

3.返回请求

请看代码:

    private  void processwork(Socket socket) throws IOException {
        // 1.读取请求
        // 2.响应
        // 3.返回响应
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream())
        {
            // 包装一下
            Scanner scanner = new Scanner(inputStream);//填入什么参数,就代表了什么输入方式
            PrintWriter printWriter = new PrintWriter(outputStream);
      while(true) {


          String request = scanner.nextLine();// 读取请求

          String response = process(request); // 回显

          printWriter.println(response); // 返回响应
          printWriter.flush(); // 刷新缓冲区,确保已经返回

//            4.打印日志
          System.out.printf("[%s:%d] request: %s, response: %s\n",
                  socket.getInetAddress().toString(),
                  socket.getPort(),
                  request,

                  response);
            }
        }
        finally {
            socket.close();
        }
    }

   InputStream 表示从客户端读入数据的字节流,OutputStream 表示写数据给客户端的字节流

使用了 try-with-resources 语法,能确保在代码执行完毕后,自动关闭资源(这里是输入输出流)。这种写法简洁、安全,避免了流忘记关闭导致的资源泄露问题。

 使用 Scanner 包装输入流,能够将字节数据按照「行文本」的形式解析,方便我们通过 scanner.nextLine() 读取一整行字符串。相比直接用 inputStream.read() 读取字节数组,这种方式更直观、适合处理文本请求。

我们都知道,我们常用 Scanner scanner = new Scanner(System.in); 这代表控制台输入,这是我们初学时学会的,但实际上 Scanner 会根据你传入参数的不同表示不同的输入方法

Scanner 的多种使用方式

1. 控制台输入:

Scanner scanner = new Scanner(System.in);

从键盘读取用户输入,适合交互式程序。


2. 从文件中读取:

Scanner scanner = new Scanner(new File("input.txt"));

读取文件内容,适用于处理数据文件或配置文件等场景。


3. 从字符串中读取:

Scanner scanner = new Scanner("Hello World\n123");

可以将字符串当作输入源,非常适合字符串解析。


4. 从网络输入流中读取(Socket 网络通信中):

InputStream inputStream = socket.getInputStream();
 Scanner scanner = new Scanner(inputStream);

这是网络编程中常见的用法,此时 Scanner 会从网络连接中读取对方(比如客户端)发送来的数据。比如 TCP 编程中,服务器端使用 socket.getInputStream() 获取输入流,从客户端接收数据。

同理

PrintWriter 是对输出流的包装,能够方便地以「文本行」的形式输出数据,比如我们可以用 printWriter.println(response) 将一行响应发出去。注意它默认有缓冲机制,发送数据前必须手动调用 flush() 刷新缓冲区,确保数据立即写出。 

同理,我在这里汇总一下

PrintWriter 的多种使用方式

1. 输出到控制台

PrintWriter writer = new PrintWriter(System.out);
writer.println("Hello, Console!");
writer.flush();

2. 输出到文件

PrintWriter writer = new PrintWriter(new File("output.txt")); 
writer.println("Write this to file."); writer.flush(); writer.close();
  • 输出目标:磁盘文件

  • 适用场景:日志记录、写入结果、持久化数据

3. 输出到网络(如 TCP 编程)

OutputStream outputStream = socket.getOutputStream(); 
PrintWriter writer = new PrintWriter(outputStream); 
writer.println("Hello, client!");
writer.flush();
  • 输出目标:通过 TCP 连接的对方客户端(或服务器)

  • 适用场景:TCP 套接字通信中,服务器/客户端发送响应或数据

4. 输出到内存字符串缓冲区

StringWriter stringWriter = new StringWriter();
 PrintWriter writer = new PrintWriter(stringWriter);
 writer.println("Write to memory."); 
writer.flush(); 
String result = stringWriter.toString(); // 获取最终字符串
  • 输出目标:内存中的字符串

  • 适用场景:构建复杂字符串、模板处理、动态拼接内容

最后,无论通信过程中是否抛出异常,最终都要关闭 socket。这是网络编程中很重要的一步,必须手动释放网络资源,避免连接堆积导致服务器崩溃。

那么为什么之前的UDP不用?

本质原因:UDP 是无连接的

TCP 是一种面向连接的协议,通信前需要建立连接,通信后要关闭连接,连接的生命周期是明确的,因此必须显式关闭以释放资源。

而 UDP 是无连接的协议DatagramSocket 并不会维持一个长时间的连接状态。它只是一个发送/接收数据报的工具,就像一个“邮筒”或“信箱”,你发完信或者收完信就可以不管它了,系统会随着进程结束自动回收资源。

 因此完整的服务器代码如下:

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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        // 绑定端口号
//      和 UDP 不同,TCP 在通信前必须先建立连接(就是三次握手)。
// 所以服务器要做的第一件事:不是接收数据,而是 等待客户端来连我。
    }
    public void start() throws IOException {
        System.out.println("服务器启动了");

        Socket socket = serverSocket.accept(); // 建立连接
        processwork(socket);
    }

    private  void processwork(Socket socket) throws IOException {
        // 1.读取请求
        // 2.响应
        // 3.返回响应
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream())
        {
            // 包装一下
            Scanner scanner = new Scanner(inputStream);//填入什么参数,就代表了什么输入方式
            PrintWriter printWriter = new PrintWriter(outputStream);
      while(true) {


          String request = scanner.nextLine();// 读取请求

          String response = process(request); // 回显

          printWriter.println(response); // 返回响应
          printWriter.flush(); // 刷新缓冲区,确保已经返回

//            4.打印日志
          System.out.printf("[%s:%d] request: %s, response: %s\n",
                  socket.getInetAddress().toString(),
                  socket.getPort(),
                  request,

                  response);
            }
        }
        finally {
            socket.close();
        }
    }

    private  String process(String request)
    {
        return request;
    }

    public static void main(String[] args) throws IOException {
         TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
         tcpEchoServer.start();
    }
}

 TCP客户端

 接下来是客户端,他大概有两个功能

1.构造请求,并发送给服务器

2.读取服务器发送回来的请求

我们首先创建一个 Socket 对象,并且绑定好IP地址和端口号

public class TcpEchoClient{
    private Socket socket = null;


    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        // 连接服务器
        socket = new Socket(serverIp, serverPort);
    }
}

 然后实现功能:

代码和服务器原理一致,笔者就不过多细说了

    public void start() throws IOException
    {
        System.out.println("客户端启动,已连接服务器");
        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);
            while(true)
            {
                // 1.读取内容
                System.out.println("输入内容");
                String request = scanner.nextLine();
               //  2.发送给服务器
                 printWriter.println(request);
                 // 加上ln, 暗中约定一个请求以\n作为结尾
                 // 刷新缓冲区,保证数据能正确发出去
                printWriter.flush();

                // 3.读取服务器返回的响应
                String response = scannerNet.nextLine();

                //4.打印返回的数据
                System.out.println(response);


            }
        }
        catch (IOException e)
        {
         throw  new RuntimeException(e);
        }

    }

 最后效果如下:

3. TCP 服务器中引入多线程

接下来我们谈一下 多线程的问题

在最初的 TCP 服务器代码中,我们使用如下方式来接收客户端连接:

Socket socket = serverSocket.accept();
processwork(socket);

这种写法是单线程、串行处理,意味着服务器一次只能处理一个客户端的请求。当一个客户端连接上来,服务器就会一直处理这个客户端的请求,直到处理完毕后,才能继续 accept() 等待下一个客户端。这带来两个致命问题:

  1. 其他客户端无法同时连接
    如果第一个客户端一直占用服务器,那么第二个客户端连接时,服务器就无法 accept(),连接会阻塞甚至超时。

  2. 服务器响应效率极低
    在网络通信中,尤其是长连接的场景下,一个客户端可能长时间保持连接,服务器如果不使用并发机制,就会严重浪费资源和降低效率。

TCP 的连接机制导致必须并发处理

TCP 是面向连接的协议,通信前需要完成三次握手,通信过程中保持连接状态。每个 Socket 实例都代表一次独立的连接。一旦 accept() 接收了连接,这个 Socket 的处理过程就独占了当前线程。如果不多线程处理,服务器根本无法同时应对多个 Socket 连接。

因此我们可以引入多线程的写法, 那么,我们怎么引入呢?

 笔者选的的是线程池,这样方便管理

来看具体代码:

ExecutorService executorService = Executors.newCachedThreadPool(); // 创建线程池

while (true) {
    Socket socket = serverSocket.accept(); // 接受连接
    executorService.submit(() -> {         // 把任务提交给线程池
        try {
            processwork(socket);           // 多线程处理该连接
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    });
}
  • newCachedThreadPool()这是一个可自动扩容的线程池,适合连接数不固定、通信时长不一致的场景;

  • submit(() -> {...})使用 Lambda 表达式将每个客户端的任务包装成线程任务提交;

  • 每个客户端的 Socket 都被交给线程池中的一个线程独立处理,互不干扰。

 完整代码:


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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        // 绑定端口号
//      和 UDP 不同,TCP 在通信前必须先建立连接(就是三次握手)。
// 所以服务器要做的第一件事:不是接收数据,而是 等待客户端来连我。
    }
    public void start() throws IOException {
        System.out.println("服务器启动了");
        ExecutorService executorService = Executors.newCachedThreadPool();//动态增长的线程池
        while (true) {
            Socket socket = serverSocket.accept(); // 建立连接
            executorService.submit(() ->{
                try {
                    processwork(socket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
//        Socket socket = serverSocket.accept(); // 建立连接
//        processwork(socket);
    }

    private  void processwork(Socket socket) throws IOException {
        // 1.读取请求
        // 2.响应
        // 3.返回响应
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream())
        {
            // 包装一下
            Scanner scanner = new Scanner(inputStream);//填入什么参数,就代表了什么输入方式
            PrintWriter printWriter = new PrintWriter(outputStream);
      while(true) {


          String request = scanner.nextLine();// 读取请求

          String response = process(request); // 回显

          printWriter.println(response); // 返回响应
          printWriter.flush(); // 刷新缓冲区,确保已经返回

//            4.打印日志
          System.out.printf("[%s:%d] request: %s, response: %s\n",
                  socket.getInetAddress().toString(),
                  socket.getPort(),
                  request,

                  response);
            }
        }
        finally {
            socket.close();
        }
    }

    private  String process(String request)
    {
        return request;
    }

    public static void main(String[] args) throws IOException {
         TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
         tcpEchoServer.start();
    }
}

效果如下:

由此可见,可以同步的和服务器进行网络通信

如果多线程依旧无法满足要求,那么还可以考虑多路复用,这个的话以后有时间笔者完全理解了,就写博客分享一下

结尾

这一篇的文本量也达到了1w字往上,希望对于读者们有帮助

后面笔者还想开博客介绍一下 IO操作,HTTPS和HTTP协议,希望能多多支持

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

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

相关文章

实验三 企业网络搭建及应用

实验三 企业网络搭建及应用 一、实验目的 1.掌握企业网络组建方法。 2.掌握企业网中常用网络技术配置方法。 二、实验描述 某企业设有销售部、市场部、技术部和财务部四个部门。公司内部网络使用二层交换机作为用户的接入设备。为了使网络更加稳定可靠,公司决定…

顶会新热门:机器学习可解释性

🧀机器学习模型的可解释性一直是研究的热点和挑战之一,同样也是近两年各大顶会的投稿热门。 🧀这是因为模型的决策过程不仅需要高准确性,还需要能被我们理解,不然我们很难将它迁移到其它的问题中,也很难进…

《STL--stack 和 queue 的使用及其底层实现》

引言: 上次我们学习了容器list的使用及其底层实现,相对来说是比较复杂的,今天我们要学习的适配器stack和queue与list相比就简单很多了,下面我们就开始今天的学习: 一:stack(后进先出&#xff…

基于springboot的医护人员排班系统设计与实现(源码+文档+部署讲解)

技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

CRISPR-Cas系统的小型化研究进展-文献精读137

Progress in the miniaturization of CRISPR-Cas systems CRISPR-Cas系统的小型化研究进展 摘要 CRISPR-Cas基因编辑技术由于其简便性和高效性,已被广泛应用于生物学、医学、农学等领域的基础与应用研究。目前广泛使用的Cas核酸酶均具有较大的分子量(通…

利用python工具you-get下载网页的视频文件

有时候我们可能在一个网站看到一个视频(比如B站),想下载,但是页面没有下载视频的按钮。这时候,我们可以借助python工具you-get来实现下载功能。下面简要说下步骤 (一)因为使用的是python工具&a…

【stm32开发板】单片机最小系统原理图设计

一、批量添加网络标签 可以选择浮动工具中的N,单独为引脚添加网络标签。 当芯片引脚非常多的时候,选中芯片,右键选择扇出网络标签/非连接标识 按住ctrl键即可选中多个引脚 点击将引脚名称填入网络名 就完成了引脚标签的批量添加 二、电源引…

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.2 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第5章析因设计引导5.7节思考题5.2 R语言解题。主要涉及方差分析&#xff0c;正态假设检验&#xff0c;残差分析&#xff0c;交互作用。 dataframe<-data.frame( Surfacec(74,64,60,92…

2025山东CCPC题解

文章目录 L - StellaD - Distributed SystemI - Square PuzzleE - Greatest Common DivisorG - Assembly Line L - Stella 题目来源&#xff1a;L - Stella 解题思路 签到题&#xff0c;因为给出的字母不是按顺序&#xff0c;可以存起来赋其值&#xff0c;然后在比较。 代码…

CentOS Stream 9 中部署 MySQL 8.0 MGR(MySQL Group Replication)一主两从高可用集群

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《MySQL技术精粹》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、MySQL 8.0 中的高可用方案 2、适用场景 二、环境准备 1、系统环境说明…

pycharm 新UI 固定菜单栏 pycharm2025 中文版

pycharm 新UI 文件 -> 设置 -> 外观与行为 -> 外观 -> UI选项 -> 主菜单:显示在主工具栏上方. 即可固定

我的世界Java版1.21.4的Fabric模组开发教程(十一)创建方块

这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第十一章——创建方块。想要阅读其他内容&#xff0c;请查看或订阅上面的专栏。 方块(Block) 是构成Minecraft世界的主要组成部分&#xff0c;是组成游戏地图的最基本单元&#xff0c;也是模组开发的核心元素之一…

VR/AR 视网膜级显示破局:10000PPI 如何终结颗粒感时代?

一、传统液晶 “纱窗效应”&#xff1a;VR 沉浸体验的最大绊脚石 当用户首次戴上 VR 头显时&#xff0c;眼前密密麻麻的像素网格往往打破沉浸感 —— 这正是传统液晶显示在近眼场景下的致命缺陷。受限于 500-600PPI 的像素密度&#xff0c;即使达到 4K 分辨率&#xff0c;等效到…

系统思考:化繁为简的艺术

系统思考&#xff0c;其实是一门化繁为简的艺术。当我们能够把复杂的问题拆解成清晰的核心以及更加简单&#xff0c;从而提升团队的思考品质和行动品质&#xff0c;发挥最大的合力。 每个公司都想在某方面成为最优秀的&#xff0c;但是实际上具有穿透性的洞察力和摆脱虚荣心的清…

Angularjs-Hello

1 关于Angularjs 最近因为项目需要又要做这个&#xff0c;所以简单复习下。其实这个大概7&#xff0c;8年前就用过&#xff0c;当时做了几个简单页面觉得太简单就还是回去做嵌入式了。按照互联网技术的进化速度&#xff0c;本来以为早死在 沙滩上了&#xff0c;没想到现在还在坚…

Linux 1.0.4

父子shell linux研究的就是shell 打开两个窗口就是两个shell 终端的软件有很多 bash也是一个软件 我们在terminal里面再打开一个bash&#xff0c;然后再次使用ps命令发现多出来一个bash&#xff0c;之后点击exit只是显示了一个exit&#xff0c;这个只是退出了在terminal中打开…

Qt -下载Qt6与OpenCV

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【暂无】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 前言 呃啊&#xff0c;本来就想在 Qt 里简单几个 OpenVC 的函数&#xff0c;没想到一搞就是一天。 我之前的开发环境是 Qt 5.14.2&#xff0c;使用 MinGW 7.3.0 64-bit 编…

机器学习无监督学习sklearn实战一:K-Means 算法聚类对葡萄酒数据集进行聚类分析和可视化( 主成分分析PCA特征降维)

本项目代码在个人github链接&#xff1a;https://github.com/KLWU07/Machine-learning-Project-practice/tree/main/1-Wine%20cluster%20analysis 如果对于聚类算法理论不理解可参考这篇之前文章机器学习中无监督学习方法的聚类&#xff1a;划分式聚类、层次聚类、密度聚类&…

可灵2.1 vs Veo 3:AI视频生成谁更胜一筹?

在Google发布Veo 3几天后,可灵显然感受到了压力,发布了即将推出的视频模型系列可灵 2.1的早期体验版。 据我了解,有三种不同的模式: 可灵 2.1 标准模式: 720p分辨率 仅支持图像转视频(生成更快,一致性更好) 5秒视频仍需20积分 可灵 2.1 专业模式: 1080p分辨率 仅在图…

LLM优化技术——Paged Attention

在Transformer decoding的过程中&#xff0c;需要存储过去tokens的所有Keys和Values&#xff0c;以完成self attention的计算&#xff0c;称之为KV cache。 &#xff08;1&#xff09;KV cache的大小 可以计算存储KV cache所需的内存大小&#xff1a; batch * layers * kv-he…