网络编程套接字 -- TCP/UDP

news2024/11/17 6:55:52

网络编程套接字 -- TCP/UDP

  • 一、网络编程
    • 1.1 什么是网络编程
    • 1.2 网络编程中的基本概念
    • 1.3 TCP和UDP
  • 二、UDP数据报套接字编程
    • 2.1 DatagramSocket API
    • 2.2 DatagramPacket API
    • 2.3 InetSocketAddress API
    • 2.4 回显程序 (UDP)
    • 2.5 翻译程序 (UDP)
  • 三、TCP流套接字编程
    • 3.1 ServerSocket API
    • 3.2 Socket API
    • 3.3 回显程序 (TCP)
    • 3.4 翻译程序 (TCP)

一、网络编程

1.1 什么是网络编程

网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信 (或称为网络数据传输)
在这里插入图片描述
当然,我们只要满足进程不同就行;所以即便是同一个主机,只要是不同进程,基于网络来传输数据,
也属于网络编程。

1.2 网络编程中的基本概念

发送端和接收端
在一次网络数据传输时:
发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。
在这里插入图片描述

请求和响应
一般来说,获取一个网络资源,涉及到两次网络数据传输:
第一次:请求数据的发送;第二次:响应数据的发送。
好比在快餐店点一份炒饭,先要发起请求点一份炒饭;再有快餐店提供的对应响应提供一份炒饭。
在这里插入图片描述
客户端和服务端
服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务。
客户端:获取服务的一方进程,称为客户端。

常见的客户端服务端模型:

  1. 客户端先发送请求到服务端
  2. 服务端根据请求数据,执行相应的业务处理
  3. 服务端返回响应:发送业务处理结果
  4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)

在这里插入图片描述

1.3 TCP和UDP

网络编程套接字就是通过写代码来完成网络编程。
需要用到socket套接字,是操作系统给应用程序提供的API,也就是传输层给应用层提供的!!!
网络传输层中有很多种协议,其中最知名的就是TCP、UDP协议。
而两者工作特性差别较大,因此操作系统就提供了两个版本、风格迥异的API~~

简单说一下TCP和UDP之间的区别:

在这里插入图片描述

有无连接:打电话是有连接,得是通信双方建立好连接才能通信 (交互数据),即A给B打电话,B得接了才能说话;发短信/微信是无连接,直接一发就过去了~~

是否为可靠传输:可靠传输,不是说A给B发的数据100%能够让B收到 (网络环境非常复杂,无法给出100%的承诺),而是A能够知道B是不是收到了~~

字节流和数据报:字节流在文件IO的时候介绍过:博客链接,TCP和文件操作一样,也是基于流的;数据报则是将数据整合起来统一发送/接收。

全双工和半双工:全双工是双向通信;半双工是单向通信。网络通信一般都是全双工的~~

socket对应到网卡这个硬件设备,操作系统也是把网卡当作文件来管理!通过网卡发送数据就是"写文件";通过网卡接收数据就是"读文件"~~

二、UDP数据报套接字编程

2.1 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()关闭此数据报套接字

2.2 DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报。
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 方法:

方法签名方法说明
SocketAddress getSocketAddress()获取主机IP地址和端口号
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据
int getLength()获取数据长度

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

2.3 InetSocketAddress API

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

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

2.4 回显程序 (UDP)

(服务器) 过程及代码实现:

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

public class UdpEchoServer {
    private DatagramSocket socket = null;

    // 参数的端口表示咱们的服务器要绑定的端口.
    public UdpEchoServer(int port) throws SocketException {
        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);
            // 把这个 DatagramPacket 对象转成字符串, 方便去打印.
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            // 2. 根据请求计算响应
            String response = process(request);
            // 3. 把响应写回到客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);

            // 4. 打印一个日志, 记录当前的情况
            System.out.printf("[%s:%d] req: %s; resp: %s\n", requestPacket.getAddress().toString(),
                    requestPacket.getPort(), request, response);
        }
    }

    // 当前写的是一个回显服务器.
    // 响应数据就和请求是一样的.
    public String process(String request) {
        return request;
    }

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

(客户端) 过程及代码实现:

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;

    // 两个参数一会会在发送数据的时候用到.
    // 暂时先把这俩参数存起来, 以备后用.
    public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
        // 这里并不是说就没有端口, 而是让系统自动指定一个空闲的端口~~
        socket = new DatagramSocket();
        // 假设 serverIP 是形如 1.2.3.4 这种点分十进制的表示方式 (关于点分十进制, 后面详细说)
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 从控制台读取用户输入的内容.
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 构造一个 UDP 请求, 发送给服务器.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(this.serverIP), this.serverPort);
            socket.send(requestPacket);
            // 3. 从服务器读取 UDP 响应数据. 并解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            // 4. 把服务器的响应显示到控制台上.
            System.out.println(response);
        }
    }

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

细节:
1)
在这里插入图片描述
可以通过 jconsole 来观察阻塞~~

2)客户端的端口号是系统分配的,而服务器的端口号是自己设置的。即为什么服务器就不害怕端口冲突,而客户端就担心端口冲突呢???
在这里插入图片描述

2.5 翻译程序 (UDP)

服务器代码完全可以继承上一题的啊~~
(服务器) 过程及代码实现:

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class UdpTranslateServer extends UdpEchoServer {
    // 翻译是啥? 本质上就是 key -> value
    private Map<String, String> dict = new HashMap<>();

    public UdpTranslateServer(int port) throws SocketException {
        super(port);

        dict.put("cat", "小猫");
        dict.put("dog", "小狗");
        dict.put("fuck", "卧槽");
        // 在这里就可以填入很多很多的内容. 像有道这样的词典程序, 也就无非如此, 只不过这里有一个非常大的哈希表, 包含了几十万个单词.
    }

    // 重写 process 方法, 实现查询哈希表的操作
    @Override
    public String process(String request) {
        return dict.getOrDefault(request, "词在词典中未找到");
    }

    // start 方法和父类完全一样, 不用写了.

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

客户端代码上一题的同样适用~~
(客户端) 过程及代码实现:

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

public class UdpTranslateClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;

    // 两个参数一会会在发送数据的时候用到.
    // 暂时先把这俩参数存起来, 以备后用.
    public UdpTranslateClient(String serverIP, int serverPort) throws SocketException {
        // 这里并不是说就没有端口, 而是让系统自动指定一个空闲的端口~~
        socket = new DatagramSocket();
        // 假设 serverIP 是形如 1.2.3.4 这种点分十进制的表示方式 (关于点分十进制, 后面详细说)
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 从控制台读取用户输入的内容.
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 构造一个 UDP 请求, 发送给服务器.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(this.serverIP), this.serverPort);
            socket.send(requestPacket);
            // 3. 从服务器读取 UDP 响应数据. 并解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            // 4. 把服务器的响应显示到控制台上.
            System.out.println(response);
        }
    }

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

三、TCP流套接字编程

3.1 ServerSocket API

ServerSocket 是创建TCP服务端Socket的API。
ServerSocket 构造方法:

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

ServerSocket 方法:

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

3.2 Socket API

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

Socket 构造方法:

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

Socket 方法:

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

3.3 回显程序 (TCP)

(服务器) 过程及代码实现:

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 {
    // 代码中会涉及到多个 socket 对象. 使用不同的名字来区分.
    private ServerSocket listenSocket = null;

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

    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService service = Executors.newCachedThreadPool();
        while (true) {
            // 1. 先调用 accept 来接受客户端的连接.
            Socket clientSocket = listenSocket.accept();
            // 2. 再处理这个连接. 这里应该要使用多线程. 每个客户端连上来都分配一个新的线程负责处理~
            //    此处使用多线程, 雀食能解决问题, 但是会导致频繁创建销毁多次线程!!
//            Thread t = new Thread(() -> {
//                try {
//                    processConnection(clientSocket);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            });
//            t.start();

            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        // 接下来就处理客户端的请求了.
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            while (true) {
                // 1. 读取请求并解析.
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()) {
                    // 读完了, 连接可以断开了.
                    System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                String request = scanner.next();
                // 2. 根据请求计算响应
                String response = process(request);
                // 3. 把响应写回给客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                // 刷新缓冲区确保数据确实是通过网卡发送出去了.
                printWriter.flush();

                System.out.printf("[%s:%d] req: %s; resp: %s\n", clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(), request, response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 为啥这个地方要关闭 socket ? 而前面的 listenSocket 以及 udp 程序中的 socket 为啥就没 close??
            clientSocket.close();
        }
    }

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

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

细节:
1)
在这里插入图片描述

2)为什么这里需要clientSocket.close();,而前面的 listenSocket 以及 UDP 程序中的 socket 为啥就不必 close?
在这里插入图片描述
在这里插入图片描述

3)若不使用多线程处理 clientSocket,则会在等待用户输入时进行阻塞,进而无法同时为多个客户端提供服务!!!
那么为什么相比于上述UDP代码,TCP需要特别使用多线程呢?
1.使用TCP需要先建立一对一的客户端服务器连接;
2.TCP建立连接之后需要处理客户端的多次请求 (长连接),导致无法快速调用到 accept;如果TCP每个连接只处理一个客户端的请求 (短连接),也能够保证快速调用到 accept!!!修改循环即可~~

4)这里会多次频繁创建销毁线程,因此使用线程池最为合适!!!

(客户端) 过程及代码实现:

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 = null;

    public TcpEchoClient(String serverIP, int serverPort) throws IOException {
        // 和服务器建立连接. 就需要知道服务器在哪了.
        // 这里和上节课写的 UDP 客户端差别较大了.
        socket = new Socket(serverIP, serverPort);
    }

    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            while (true) {
                // 1. 从控制台读取数据, 构造成一个 请求
                System.out.print("-> ");
                String request = scanner.next();
                // 2. 发送请求给服务器
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                // 这个 flush 不要忘记. 否则可能导致请求没有真发出去.
                printWriter.flush();
                // 3. 从服务器读取响应
                Scanner respScanner = new Scanner(inputStream);
                String response = respScanner.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.4 翻译程序 (TCP)

服务器代码完全可以继承上一题的啊~~
(服务器) 过程及代码实现:

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class TcpTranslateServer extends TcpEchoServer{
    private Map<String, String> dict = new HashMap<>();

    public TcpTranslateServer(int port) throws IOException {
        super(port);
        dict.put("cat", "小猫");
        dict.put("dog", "小狗");
        dict.put("fuck", "卧槽");
    }

    @Override
    public String process(String request) {
        return dict.getOrDefault(request,"词在词典中未找到");
    }

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

客户端代码上一题的同样适用~~
(客户端) 过程及代码实现:

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 TcpTranslateClient {
    // 客户端需要使用这个 socket 对象来建立连接.
    private Socket socket = null;

    public TcpTranslateClient(String serverIP, int serverPort) throws IOException {
        // 和服务器建立连接. 就需要知道服务器在哪了.
        // 这里和上节课写的 UDP 客户端差别较大了.
        socket = new Socket(serverIP, serverPort);
    }

    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            while (true) {
                // 1. 从控制台读取数据, 构造成一个 请求
                System.out.print("-> ");
                String request = scanner.next();
                // 2. 发送请求给服务器
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                // 这个 flush 不要忘记. 否则可能导致请求没有真发出去.
                printWriter.flush();
                // 3. 从服务器读取响应
                Scanner respScanner = new Scanner(inputStream);
                String response = respScanner.next();
                // 4. 把响应显示到界面上
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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

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

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

相关文章

考研数学模拟卷经典题总结

考研数学模拟卷经典题总结1、李林四套卷的题目&#xff1a; 【23考研数学】李林老师四套卷两道二重积分计算题目分享——利用雅可比变换大大减少计算量与利用轮换对称性解题_哔哩哔哩_bilibili 上面两道题目都可以采用轮换对称性来做&#xff0c;第一道题目也可以使用雅可比行…

Java超市系统超市自提超市多商家系统源码超市自提网站

简介 Ssm多商家超市自提系统。用户注册申请开店成为商家&#xff0c;普通注册用户下单时选择离自己较近的自提点次日取货。管理员进行店铺审核、用户、分类管理等。 演示视频 https://www.bilibili.com/video/BV1hg411E77q/?share_sourcecopy_web&vd_sourceed0f04fbb7131…

Java老鸟5年压箱底面试真题资料+自学手册,秋招拿下阿里45k offer

背景 又逢“金三银四”&#xff0c;年轻的毕业生们满怀希望与忐忑&#xff0c;去寻找、竞争一个工作机会。已经在职的开发同学&#xff0c;也想通过社会招聘或者内推的时机争取到更好的待遇、更大的平台。然而&#xff0c;面试人群众多&#xff0c;技术市场却相对冷淡&#xf…

轻量日志收集系统loki

1.Loki简介 Loki是受Prometheus启发由Grafana Labs团队开源的水平可扩展&#xff0c;高度可用的多租户日志聚合系统。 开发语言: Google Go。它的设计具有很高的成本效益&#xff0c;并且易于操作。使用标签来作为索引&#xff0c;而不是对全文进行检索&#xff0c;也就是说&a…

基于帝国主义竞争算法(ICA)求解旅行商问题(TSP)(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维…

如何用Python破解邻居家的WIFI?

Hallo&#xff0c;各位小伙伴们大家好&#xff0c;这篇文章我们来干一件大事&#xff0c;如标题所示——用Python破解邻居家的WiFi。这是偶然间在码云上看到的一个项目&#xff0c;感觉蛮有趣的&#xff0c;分享给大家。文中用到的语料库和源码博主也会在文章最后贴给大家&…

Nginx教程(2)

文章目录2.1 Nginx解决跨域问题2.2 Nginx解决静态资源防盗链问题2.3 Nginx的模块化体系2.4 Nginx集群负载均衡2.5 四层负载均衡和七层负载均衡2.6 使用Nginx构建Tomcat集群2.1 Nginx解决跨域问题 所谓的跨域问题是指&#xff0c;比如我们现在我们访问域名www.imooc.com&#xf…

Linux从入门到进阶学习(Ⅳ):Linux实用操作

目录 1 实用技巧 2 软件安装 2.1 CentOs系统 2.2 Ubuntu系统 3 systemctl控制软件 4 软链接 5 日期和时区 5.1 查看日期 5.2 修改时区 5.3 时间校准 6 IP地址和主机名 6.1 IP地址与主机名 6.2 域名解析 7 固定IP地址 8 网络请求和下载 8.1 ping 8.2 wget 8.3…

2022 软件测试填空判断题【太原理工大学】

期末复习汇总&#xff0c;点这里&#xff01;https://blog.csdn.net/m0_52861684/category_12095266.html?spm1001.2014.3001.5482 目录 二、填空题 三、判断题 二、填空题 全是课本原话&#xff0c;不一定只填红色部分&#xff0c;可能下次就换了这句话的其它地方&#xff…

高比例风电电力系统储能运行及配置研究(pythonMatlab实现)

目录 1 概述 2 案例 3 Matlab实现 3.1 题目及分析 3.2 Matlab代码 4 七个题全部代码&#xff08;值得学习&#xff09; 1 概述 “碳中和”目标驱动下未来电力系统必将是高比例可再生能源电力系统&#xff0c;可再生能源输出功率强随机波动性导致系统运行中功率实时平…

比较器和浅谈深浅拷贝

比较器和浅谈深浅拷贝 文章目录比较器和浅谈深浅拷贝前言一.比较器方法一方法二二.深浅拷贝2.1 浅拷贝2.2 深拷贝2.3 总结前言 我们学习完接口以后&#xff0c;我在这里会介绍一个比较器的接口&#xff0c;至于他是来干嘛的&#xff0c;比较器顾名思义就是来比较的&#xff0c…

【安卓学习之常见问题】百度地图卫星地图精度不够

█ 【安卓学习之常见问题】百度地图卫星地图精度不够 █ 系列文章目录 提示&#xff1a;这里是收集了和文件分享有关的文章 【安卓学习之常见问题】android路径及文件问题 【安卓学习之常见问题】文件分享–文件不存在 【安卓学习之常见问题】自定义组件-刷新后跳到第一行 【…

修复 IDEA 使用 Gradle 构建出错时的乱码问题(maven项目转Gradle后乱码,并报“错误,找不到符号”)

在迁移一个基于 Maven 构建项目到基于 Gradle 进行构建, 迁移的过程中发现编译失败了, IDEA 的 Gradle build output 面板出现了许多方块型的乱码. 这样子&#xff1a; 解决步骤1&#xff1a; Step 1: 点击 IDEA 顶部菜单栏中的 HelpStep 2: 点击 Edit Custom VM OptionsStep…

天权信安catf1ag网络安全联合公开赛-AGCTFS战队 wp

文章目录webPOPEzloginFileuploadHistoryMISC简单隐写十位马CryptoEasyrsa疑惑ReverseCheckinPwnCheckinAngrweb POP 脚本 <?php class catf1ag1{ public $hzy; public $arr; public function __construct(){$this->hzy new catf1ag2;$this->arr [&apos;pp…

数据库实验二:安全性语言实验

实验二 安全性语言实验 实验 2.1 自主存取控制实验 1.实验目的 掌握自主存取控制权限的定义和维护方法。 2.实验内容和要求 定义用户、角色&#xff0c;分配权限给用户、角色&#xff0c;回收权限&#xff0c;以相应的用户名登录数据库验证权限分配是否正确。选择一个应用…

【GRU回归预测】基于matlab鲸鱼算法优化门控循环单元WOA-GRU神经网络回归预测(多输入单输出)【含Matlab源码 2285期】

⛄一、CNN-GRU数据预测 1 理论基础 1.1 CNN算法 负荷序列数据为一维数据&#xff0c;用一维卷积核对数据进行卷积处理&#xff0c;以获取数据的特征。 现设定卷积核的维度为3&#xff0c;移动步长为1&#xff0c;对输入数据进行卷积&#xff0c;以获得特征图图谱&#xff0c;即…

postgresql_internals-14 学习笔记(四)TOAST 超尺寸字段存储技术

TOAST之前一直没太弄懂&#xff0c;这一节单独拆出来学习。 一、 引入原因 pg中的每个行只能存在一个page里&#xff0c;不能跨page存储。因此对于一些非常长的行&#xff0c;就需要使用到 TOAST&#xff08;The OverSized Attribute Storage Technique&#xff0c;超尺寸字段存…

import sklearn出现报错,如何正确安装sklearn

目录 一&#xff1a;前言 二&#xff1a;解决方法 三&#xff1a;测试是否成功安装 一&#xff1a;前言 博主最早只使用下面安装命令&#xff0c;安装sklearn pip3 install sklearn -i https://pypi.mirrors.ustc.edu.cn/simple/ 但在pycharm编辑器&#xff0c;导入sklearn模…

更合理的 BBR

BBR 倾向于排空队列&#xff0c;甚至用特殊的 ProbeRTT 状态来排空自己产生的队列以测量 RTT&#xff0c;但这并不现实。一言以蔽之&#xff0c;BBR 无法实时跟踪现状&#xff0c;只靠拢理想。 若因背景流量造成 buffer 抖动&#xff0c;BBR 完全无法应对&#xff0c;其运行状…

手撕B树 | 二三查找树,B+树B*树你都会了吗? | 超详细的数据结构保姆级别实现

说在前面 今天给大家带来B树系列数据结构的讲解&#xff01; 博主为了这篇博客&#xff0c;做了很多准备&#xff0c;试了很多画图软件&#xff0c;就是为了让大家看得明白&#xff01;希望大家不要吝啬一键三连啊&#xff01;&#xff01; 前言 那么这里博主先安利一下一些…