2. 网络之网络编程

news2024/11/26 10:25:18

网络编程

文章目录

  • 网络编程
  • 1. UDP
    • 1.1 DatagramSocket
      • 1.1.1 DatagramSocket 构造方法
      • 1.1.2 DatagramSocket 方法:
    • 1.2 DatagramPacket
      • 1.2.1 DatagramPacket构造方法
      • 1.2.2 DaragramPacket方法
      • 1.2.3InetSocketAddress API
    • 1.3 UDP回显服务器
      • 1.3.1 框架结构
      • 1.3.2 读取请求并解析
      • 1.3.3 根据请求构建响应
      • 1.3.4 响应发回客户端
      • 1.3.5 打印日志
      • 1.3.6 完整程序
    • 1.4 UDP回显客户端
      • 1.4.1构建框架
      • 1.4.2 控制台读取数据构建请求
      • 1.4.3 发送请求
      • 1.4.4 接收响应
      • 1.4.5 输出响应
      • 1.4.6 完整代码
  • 2. TCP
    • 2.1 ServerSocket
      • 2.1.1ServerSocket 构造方法
      • 2.1.2 ServerSocket 方法
    • 2.2 Socket
      • 2.2.1 Socket 构造方法
      • 2.2.2 Socket 方法
    • 2.3 UDP回显服务器
    • 2.4 UDP回显客户端
  • 3. UDP和TCP的异同
    • 3.1 异
    • 3.2 同
  • 4. 部署至云服务器
    • 4.1 打包
    • 4.2 上传
    • 4.3 执行
    • 4.4 问题总结:

    网络编程是使用 IP地址,或域名,和 端口连接到另一台计算机上对应的程序,按照规定的 协议 (数据格式)来交换数据,实际编程中建立连接和发送、接收数据在语言级已经实现,做的更多的工作是设计协议,以及编写生成和解析数据的代码罢了,然后把数据转换成逻辑的结构显示或控制逻辑即可。

    网络编程的三要素

  • IP 地址: 用于标识网络设备的网络地址。
  • 端囗: 应用程序在设备中唯一的标识,对不同应用程序进行区分。
  • 协议:数据在网络中传输(传输层)的规则,其中最主要的UDP协议和TCP协议。
    • TCP:用户传输协议
    • UDP:用户数据报协议

    我们这里的重点不在于介绍UDP、TCP协议的内容,而是关注Java中使用UDP、TCP协议(传输层)进行数据传输,并且通过这两个传输层协议完成基础的回显服务器、客户端的编写

1. UDP

1.1 DatagramSocket

    DatagramSocket是UDP Socket,用于发送和接收UDP数据报。我们使用这个类来完成UDP数据传输。

1.1.1 DatagramSocket 构造方法

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)
  • DatagramSocket()操作系统会随机分配一个空闲的端口

  • DatagramSocket(int)port 传入一个端口号(1024~65535),

    DatagramSocket类提供了两个版本,一个带端口(port)一个不带,而带端口的一般用于服务器端,不带端口的一般用于客户端。由于服务端端口的占用情况未知,一般交给操作系统(OS)自动分配,而服务器这边的端口占用情况开发人员一般会比较清楚,所以会手动指定。

1.1.2 DatagramSocket 方法:

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该法会阻塞等待)
void send(DatagramPacketp)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字
  • receive(DatagramPacket p) 这里的p是输出型参数,内部会将数据填入p中
  • send(DatagramPacketp)用来发送数据报,数据要提前存放在DatagramPacket对象中
  • close()使用完后请记得关闭!!!

1.2 DatagramPacket

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

1.2.1 DatagramPacket构造方法

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket 用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[] buf, int offset, int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号
  • DatagramPacket(byte[] buf, int length) 指定byte数组作为缓冲区,length是要存放的长度
  • DatagramPacket(byte[] buf, int offset, int length,SocketAddress address) 比上面多路一个offset(偏移量)和address,offset表示从第几个字节开始填充,address表示ip地址和端口号。

1.2.2 DaragramPacket方法

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

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

1.2.3InetSocketAddress API

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

    了解了上面这两个类我们就可以在Java中利用UDP来编写一个回显程序。

1.3 UDP回显服务器

1.3.1 框架结构

    首先搭建服务器程序的基本框架,并在构造方法中创建出一个DatagramSocket对象。构造时要传入一个端口号,因为在网络通信中,服务器是被动方,如果端口号为随机,那么此时客户端就不知道服务器的端口号,也就无法进行通信了。

public class UdpEchoServer {
    private DatagramSocket socket = null;
 
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() {
    }
}

    接着在start中实现具体的服务器代码,首先是一个while(true)循环包含整个方法体,因为大多数服务器7*24小时运行,不断处理客户端发送的请求,返回响应。

1.3.2 读取请求并解析

// receive 方法的参数是一个输出型参数
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
// 如果客户端发来了请求,receive就能顺利读出来请求,如果没有请求就会进入阻塞
socket.receive(requestPacket);
// 将数组中的数据转化为字符串,方便读取
String request = new String(requestPacket.getData(),0,requestPacket.getLength());

1.3.3 根据请求构建响应

 String response = process(request);
 // .......
 public String process(String request) {
    return request;
 }

1.3.4 响应发回客户端

// 此处DatagramPacket 的参数就不能是空的数组了,因为要将响应的字符串返回去
// send的参数也是DatagramPacket
// 在receive时,requestPacket中已经存放了 客户端的IP地址和端口号
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
socket.send(responsePacket);

1.3.5 打印日志

System.out.printf("[%s:%d] req: %s;resp : %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
// 日志格式 - 客户端的IP,客户端的端口号,请求,响应

1.3.6 完整程序

package UDPEchoServer;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer {
    // 创建一个DatagramSocket对象,操作网卡
    private DatagramSocket socket = null;
    public UdpEchoServer(int port) throws SocketException {
        // 服务器端手动分配端口 - 只申请了一个socket对象,一直使用到结束不用close()
        socket = new DatagramSocket(port);
    }

    // 启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动!!!");
        while(true) {
            // 1.读取请求并解析 => 字节数组(输出型参数)
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            // 当前完成receive后数据是以二进制存储到requestPacket中
            // 想要显示出这里的请求,还需要将这里的字节数组够造成字符串
            // getLength() 拿到的是收到的数据的真实长度(字节数)
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());

            // 2. 根据请求计算响应(业务)
            String response = process(request);

            // 3. 把响应写会客户端
            // 响应对象DatagramPacket ,构造好响应数据,再通过send发送【指定数据和目的地(无连接)】
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            // 打印日志,把这次交互的详情打印出来
            System.out.printf("[%s,%d] req=%s, req=%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }

    public String process(String request) {
        // 当前是echo server 请求即响应
        return request;
    }

    public static void main(String[] args) throws IOException {
		UdpEchoServer server = new UdpEchoServer(5265);// port range :1023 ~  65535	
        server.start();
    }
}

1.4 UDP回显客户端

1.4.1构建框架

    构建客户端的基本框架,相比于服务器,客户端在构造方法处还需要传入服务器的端口号和IP。

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP = null;
    private int serverPort = 0;
    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }
    public void start() {
 
    }
}

1.4.2 控制台读取数据构建请求

Scanner scanner = new Scanner(System.in);

System.out.print("->");
String request = scanner.next();
// 判断是否要退出
if(request.equals("exit")) {
    System.out.println("goodbye");
    break;
}

1.4.3 发送请求

// 构造一个 DatagramPacket 对象 此时该对象的参数要传入客户端的 IP(serverIP) 和 端口(serverPort)
// 此处的IP需要使用getByName()方法
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIP),serverPort);
socket.send(requestPacket);

1.4.4 接收响应

DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(),0,responsePacket.getLength());

1.4.5 输出响应

System.out.println(response);

1.4.6 完整代码

package UDPEchoServer;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp = "";
    private int serverPort = 0;
    public UdpEchoClient(String ip, int port) throws SocketException {
        // 系统自动分配客户端端口
        socket = new DatagramSocket();
        this.serverIp = ip;
        this.serverPort = port;
    }
    public void start() throws IOException {
        System.out.println("客户端启动!!!");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 从控制台读取数据,作为请求
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 把请求够造成DatagramPacket对象
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length
            , InetAddress.getByName(serverIp),serverPort);

             // 3. 发送请求
            socket.send(requestPacket);

            // 4. 尝试读取响应
            DatagramPacket responPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responPacket);

            // 5. 将响应转成字符串打印出来
            String response = new String(responPacket.getData(),0,responPacket.getLength());
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("152.136.59.108",9090);
        client.start();
    }
}

2. TCP

2.1 ServerSocket

    ServerSocket 是TCP服务端的API。

2.1.1ServerSocket 构造方法

    ServerSocket 是创建TCP服务端Socket的API

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

2.1.2 ServerSocket 方法

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

2.2 Socket

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

2.2.1 Socket 构造方法

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

2.2.2 Socket 方法

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

2.3 UDP回显服务器

    由于流程和UDP大差不差,这里介绍一些大概步骤,然后给出所有代码。

  1. 读取请求并解析

  2. 根据请求构造响应

  3. 响应返回客户端

  4. 打印日志

完整代码

package network;

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 {
    private ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService service = Executors.newCachedThreadPool();
        while (true) {
            // 通过 accept 方法, 把内核中已经建立好的连接拿到应用程序中.
            // 建立连接的细节流程都是内核自动完成
            Socket clientSocket = serverSocket.accept();
            // 使用线程池.
            service.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(clientSocket);
                }
            });
        }
    }

    // 通过这个方法, 来处理当前的连接.
    public void processConnection(Socket clientSocket) {
        // 进入方法, 先打印一个日志, 表示当前有客户端连上了.
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
        // 接下来进行数据的交互.
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            // 使用 try ( ) 方式, 避免后续用完了流对象, 忘记关闭.
            // 由于客户端发来的数据, 可能是 "多条数据", 针对多条数据, 就循环的处理.
            while (true) {
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()) {
                    // 连接断开了. 此时循环就应该结束
                    System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
                    break;
                }
                // 1. 读取请求并解析. 此处就以 next 来作为读取请求的方式. next 的规则是, 读到 "空白符" 就返回.
                String request = scanner.next();
                // 2. 根据请求, 计算响应.
                String response = process(request);
                // 3. 把响应写回到客户端.
                //    可以把 String 转成字节数组, 写入到 OutputStream
                //    也可以使用 PrintWriter 把 OutputStream 包裹一下, 来写入字符串.
                PrintWriter printWriter = new PrintWriter(outputStream);
                //    此处的 println 不是打印到控制台了, 而是写入到 outputStream 对应的流对象中, 也就是写入到 clientSocket 里面.
                //    此处使用 println 带有 \n 也是为了后续 客户端这边 可以使用 scanner.next 来读取数据.
                printWriter.println(response);
                //    刷新缓冲区. 如果没有刷新操作, 可能数据仍然是在内存中, 没有被写入网卡.
                printWriter.flush();
                // 4. 打印一下这次请求交互过程的内容
                System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(),
                        request, response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 在这个地方, 进行 clientSocket 的关闭.
                // processConnection 就是在处理一个连接. 这个方法执行完毕, 这个连接也就处理完了.
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String process(String request) {
        // 此处也是写的回显服务器. 响应和请求是一样的.
        return request;
    }

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

2.4 UDP回显客户端

    同样,这里也是给出流程和完整代码。

  1. 控制台读取数据构建请求

  2. 发送请求

  3. 接收响应

  4. 打印日志

完整代码

package network;

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 {
    private Socket socket = null;

    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        // 需要在创建 Socket 的同时, 和服务器 "建立连接", 此时就得告诉 Socket 服务器在哪里~~
        // 具体建立连接的细节, 不需要咱们代码手动干预. 是内核自动负责的.
        // 当我们 new 这个对象的时候, 操作系统内核, 就开始进行 三次握手 具体细节, 完成建立连接的过程了.
        socket = new Socket(serverIp, serverPort);
    }

    public void start() {
        // tcp 的客户端行为和 udp 的客户端差不多.
        // 都是:
        // 3. 从服务器读取响应.
        // 4. 把响应显示到界面上.
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            PrintWriter writer = new PrintWriter(outputStream);
            Scanner scannerNetwork = new Scanner(inputStream);
            while (true) {
                // 1. 从控制台读取用户输入的内容
                System.out.print("-> ");
                String request = scanner.next();
                // 2. 把字符串作为请求, 发送给服务器
                //    这里使用 println, 是为了让请求后面带上换行.
                //    也就是和服务器读取请求, scanner.next 呼应
                writer.println(request);
                writer.flush();
                // 3. 读取服务器返回的响应.
                String response = scannerNetwork.next();
                // 4. 在界面上显示内容了.
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

3. UDP和TCP的异同

3.1 异

  • UDP 是无连接的,TCP是有连接的
  • UDP 是不可靠传输的,TCP是可靠传输的
  • UDP 是面向数据报的,TCP是面向字节流的

3.2 同

    UDP 和 TCP都是全双工的,什么是全双工?一个信道既可以接收数据又可以发送数据就是全双工的。
在这里插入图片描述

4. 部署至云服务器

4.1 打包

    这里就使用IDE进行打包(jar包)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/06061fa462e845409c659bafaff403f9.png
在这里插入图片描述
    此时就会多出一个out目录,这个目录下artifacts目录下就会有jar包
在这里插入图片描述

4.2 上传

    将程序上传到云服务器上。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 执行

在这里插入图片描述
    启动服务端程序!!!

java -jar Network.jar

    最后就可以在其他计算机上运行客户端来访问到这个回显程序服务器了。
在这里插入图片描述

4.4 问题总结:

    记得将你使用的端口在云服务器控制台放行,不然可能也访问不了。
    如果没有安装java环境,请执行以下命令安装环境

yum install java

    如果本篇文章对你有帮助,请点赞、评论、转发,你的支持是我创作的动力。

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

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

相关文章

USART HMI串口屏+GPS模块显示时间和经纬度

USART HMI串口屏GPS模块显示时间和经纬度 📍相关篇《基于u-box GPS模块通过串口指令调整输出信息》 📋在不使用其他单片机做数据中转处理情况下,利用USART HMI串口屏主动解析模式,来接收并解析GPS模块数据并显示,功能包…

Android 如何在Android studio中快速创建raw和assets文件夹

一 方案 1. 创建raw文件夹 切成project浏览模式——>找到res文件粘贴要放入raw文件夹下的文件。 当然此时raw文件还没有,直接在右侧输入框中出现的路径~\res后面加上\raw即可。 2. 创建assets文件夹 同理在main文件夹下粘贴要放入assets文件夹的文件&#xff0…

【深度学习基础】专业术语汇总(欠拟合和过拟合、泛化能力与迁移学习、调参和超参数、训练集、测试集和验证集)

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

【高光谱与多光谱:空间-光谱双优化模型驱动】

A Spatial–Spectral Dual-Optimization Model-Driven Deep Network for Hyperspectral and Multispectral Image Fusion (一种用于高光谱与多光谱图像融合的空间-光谱双优化模型驱动深度网络) 深度学习,特别是卷积神经网络(CNN…

【算法练习Day35】01背包问题分割等和子集

​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 01背包问题分割等和子集总结…

C语言从入门到精通之【编译过程】

!!!本文内容毕业生面试必问哈。 编译过程 编译包含四个阶段,预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)、链接(Linking&#x…

JAVA 实现PDF转图片(spire.pdf.free版)

1.引入jar包 导入方法1: 手动引入。将Free Spire.PDF for Java下载到本地,解压,找到lib文件夹下的Spire.PDF.jar文件。在IDEA中打开如下界面,将本地路径中的jar文件引入Java程序: 导入方法2:如果您想通过…

Day17力扣打卡

打卡记录 参加会议的最多员工数&#xff08;拓扑排序 分类讨论&#xff09; 链接 计算内向基环树的最大基环&#xff0c;基环树基环为2的情况分类讨论。 class Solution { public:int maximumInvitations(vector<int> &favorite) {int n favorite.size();vector…

STM32中微秒延时的实现方式

STM32中微秒延时的实现方式 0.前言一、裸机实现方式二、FreeRTOS实现方式三、定时器实现&#xff08;通用&#xff09;4、总结 0.前言 最近在STM32驱动移植过程中需要用到微秒延时来实现一些外设的时序&#xff0c;由于网上找到的驱动方法良莠不齐&#xff0c;笔者在实现时序过…

链表指定节点的插入

向现有链表中插入结点&#xff0c;根据插入位置的不同&#xff0c;可分为以下 3 种情况&#xff1a; 插入到链表的头部&#xff0c;作为新的链表中第一个存有数据的结点&#xff08;又称为”首元结点”&#xff09;&#xff1b;插入到链表中某两个结点之间的位置&#xff1b;插…

通达信对子数的指标公式大全

对子数&#xff1a;形如9.22,12.21, 4.44,11.00等 顺子数&#xff1a;形如&#xff13;.89,4.98,7.56等 进一步的了解,自行百度。 在通达里查找价格为对子数的个股&#xff0c;有两个自带的函数&#xff0c; INTPART(X),返回数值的整数部分&#xff0c; FRACPART&#xff…

安达发|APS生产排程解决五金制造企业的需求

在五金制造行业中&#xff0c;生产排程一直是一个非常重要的环节。然而&#xff0c;由于五金行业的特点和痛点&#xff0c;传统的生产排程方法往往难以满足企业的需求。本文将针对五金行业的痛点&#xff0c;探讨如何利用APS生产排程解决这些问题。 首先&#xff0c;我们需要了…

代码随想录二刷Day 56

1143.最长公共子序列 本题和动态规划&#xff1a;718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了&#xff0c;但要有相对顺序&#xff0c;即&#xff1a;"ace" 是 "abcde" 的子序列&#xff0c;但 "aec" 不是 "abcd…

大模型时代目标检测任务会走向何方?

参考&#xff1a; 大模型时代目标检测任务会走向何方&#xff1f; 细数从常见的目标检测到现在 MLLM 盛行的时代&#xff0c;和 Object Detection 的任务以及近期涌现的新任务。>>加入极市CV技术交流群&#xff0c;走在计算机视觉的最前沿 你或许很好奇&#xff0c;现在…

人工智能时代八大类算法你了解吗?(文末包邮送书6本)

文章目录 本文导读1. 关联规则分析2. 回归分析3. 分类分析4. 聚类分析5. 集成学习6. 自然语言处理7. 图像处理8. 深度学习9. 书籍推荐&#xff08;包邮送书6本&#xff09; 本文导读 从零带你了解人工智能时代需要掌握的8大类算法&#xff0c;包括基础理论、关联规则分析、回归…

Vue 创建自定义 ref 函数

Vue 创建自定义 ref 函数 customRef customRef 用于&#xff1a;创建一个自定义的 ref 函数&#xff0c;并对其依赖项跟踪和更新触发进行显式控制。 使用 customRef 创建自定义 ref 函数 // 创建自定义 ref 函数 function myRef(value) {return customRef((track, trigger) &g…

自动曝光算法(第一讲)

序言 失业在家无事&#xff0c;想到以后换方向不做自动曝光了&#xff0c;但是自动曝光的工作经验也不能浪费了&#xff0c;准备写一个自动曝光的教学&#xff0c;留给想做自动曝光的小伙伴参考。笔者当时开发自动曝光没有按摄影的avtvevbvsv公式弄&#xff0c;而是按正确的增…

[架构之路-251/创业之路-82]:目标系统 - 纵向分层 - 企业信息化的呈现形态:常见企业信息化软件系统 - 商业智能、决策支持系统、知识管理

目录 前言&#xff1a; 一、企业信息化的结果&#xff1a;常见企业信息化软件 1.1 商业智能 - 管理层 1.1.1 什么是商业智能What 1.1.1.1 商业智能常见工具 1.1.2 为什么需要商业智能Why&#xff1f; 1.1.3 谁需要商业智能who&#xff1f; 1.1.4 商业智能在企业管理中的…

微信小程序开发(搭建)

首先去微信开发者网站下载微信开发者工具 然后打开电脑命令框wincmd 全局安装 vue-clinpm install --global vue-cli创建一个基于 mpvue-quickstart 模板的新项目vue init mpvue/mpvue-quickstart my-project安装依赖cd my-projectnpm install启动构建npm run dev 记得为vue配…

Docker dnmp 多版本php安装 php8.2

Laravel9 开发需要用到php8.1以上的版本&#xff0c;而dnmp只支持到php8.0。安装php8.2的步骤如下&#xff1a; 1. 从/services/php80目录复制一份出来&#xff0c;重命名为php82&#xff0c;extensions目录只保留 install.sh 和 install-php-extensions 这两个文件 2. 修改.en…