JAVA—网络通信

news2024/9/23 5:28:46

        本文是学习网络通信入门和简单了解UDP协议和TCP协议,学习和了解CS架构和简单了解BS架构和HTTP协议(部分图片来自黑马程序员)

目录

1.网络通信三要素

(1)IP地址

(2)端口号

(3)协议

2.UDP通信—快速入门

3.UDP通信—多发多收

4.TCP通信—快速入门

5.TCP通信—多发多收

6.TCP通信—同时接收多个客户端

7.TCP通信—综合案例

(1)即时通信-群聊

(2)实现一个简易的BS架构

 *线程优化


网络编程

可以让设备中的程序与网络其他设备中的程序进行数据交互

基本通信框架

有两种形式:CS架构(CLient客户端/Server服务器)和 BS架构(Browser浏览器/Server服务器)

1.网络通信三要素

(1)IP地址

  • IP(InternetProtocol)全称“互联网协议地址”,是分配给上网设备的唯一标志
  • 有两种形式 IPV4 和 IPV6

    IPV4 由四个字节组成一般使用点分十进制表示法

    IPV6 由8段组成 一段每四位编码成一个十六进制数 一般使用冒分十六进制表示 

127.0.0.1/ localhost  代表本机IP,只会寻求当前所在的主机

InetAddress

 代表IP地址

名称说明
public static InetAddress getLocalHost()读取本机IP,会以一个inetAddress的对象返回
public static  InetAddress getByname(String host)

根据ip地址或者域名 返回一个inetAddress对象

public String getHostName()获取该IP地址对象对应的主机名
public String getHostAddress()获取该IP地址中的IP地址信息
public boolean isReachable(int timeout)在指定毫秒内,判断主机与该IP是否能连通

(2)端口号

  • 标记正在计算机设备上运行的应用程序 被固定为一个16位的二进制 范围是0~65535

        分类

  • 周知端口:0~1023 被预先定义的知名应用占用(如HTTP占用80,FTP占用21)
  • 注册端口:1024~49151 分配给用户或某些应用程序
  • 动态端口:49152~65535 一般不固定分配某种进程,而是动态分配

        注意:我们自己开发的程序一般选择使用注册端口,且一个设备不能出现两个程序的端口号一致,否则出错

(3)协议

        网络上通信的设备 事先固定的连接规则 以及传输数据的规则被称为网络通信协议

 UDP协议 (通信效率高 用于语音 视频通话)

  • 特点:无连接,不可靠通信
  • 不事先建立连接数据,按照包发一包数据包含自己的IP程序端口,目的地IP程序端口的数据限制在64kb内的。
  • 发送方不管对方是否在线树立在中间丢失也不管如果接受方式的数据也不返回确认故而不可靠

 TCP协议 (通信效率相对不高 网页 文件下载,支付)

  • 特点:面向连接 可靠通信
  • TCP的最终目的:要保障在不可信的信道上实现可靠的传输
  • 主要三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接(确保双方数据的收发都已经完成)
  • 三次握手

2.UDP通信—快速入门

 实现单发单收

package IP_Study.upd01;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class Client {
    public static void main(String[] args) throws Exception {

        // 1.创建客户端
        DatagramSocket socket = new DatagramSocket();

        // 2.创建数据包
        // public DatagramPacket(byte buff[], int offset, int length,
        //                          InetAddress address, int port)
        //            参数一:封装要发出去的数据
        //            参数二:发送要发出去的数据大小(字节个数)
        //            参数三:服务端的IP地址
        //            参数四:服务端程序的端口
        String rs = "万水千山 我陪你去看";
        byte[] buff = rs.getBytes();
        DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getLocalHost(),8088);

        // 3.正式发送这个数据包数据
        socket.send(packet);

        System.out.println("客户端数据发送完毕");
        socket.close(); //关闭流 释放资源
    }
}
package IP_Study.upd01;

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

public class Server {
    public static void main(String[] args) throws Exception {
        // 1.创建一个服务端对象
        DatagramSocket socket = new DatagramSocket(8088);
        System.out.println("服务端启动");

        // 2.创建一个数据包对象,用于接收数据
        byte [] buffer = new byte[1024 *64]; //64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        // 3.正式使用数据包来接收客户端发来的数据
        socket.receive(packet);

        // 4.从字节数组中 打印接收的数据
        int len = packet.getLength();
        String rs = new String(buffer,0, len);
        System.out.println(rs);

        System.out.println(packet.getAddress().getHostAddress()); //获取发起IP
    }
}

3.UDP通信—多发多收

改造UDP单发单收代码已实现多发多收

package IP_Study.upd01;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {

        // 1.创建客户端
        DatagramSocket socket = new DatagramSocket();

        // 2.创建数据包
        // public DatagramPacket(byte buff[], int offset, int length,
        //                          InetAddress address, int port)
        //            参数一:封装要发出去的数据
        //            参数二:发送要发出去的数据大小(字节个数)
        //            参数三:服务端的IP地址
        //            参数四:服务端程序的端口
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String rs = sc.next();

            //一旦发现客户输入exit 则退出客户端
            if("exit".equals(rs)){
                System.out.println("退出成功");
                socket.close();
                break;
            }
            byte[] buff = rs.getBytes();
            DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getLocalHost(),8088);

            // 3.正式发送这个数据包数据
            socket.send(packet);
        }
    }
}
package IP_Study.upd01;

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

public class Server {
    public static void main(String[] args) throws Exception {
        // 1.创建一个服务端对象
        DatagramSocket socket = new DatagramSocket(8088);
        System.out.println("服务端启动");

        // 2.创建一个数据包对象,用于接收数据
        byte [] buffer = new byte[1024 *64]; //64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            // 3.正式使用数据包来接收客户端发来的数据
            socket.receive(packet);

            // 4.从字节数组中 打印接收的数据
            int len = packet.getLength();
            String rs = new String(buffer,0, len);
            System.out.println(rs);

            System.out.println(packet.getAddress().getHostAddress()); //获取发起IP
            System.out.println(packet.getPort());
            System.out.println("---------------");
        }
    }
}

4.TCP通信—快速入门

package IP_Study.tcp01;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1.创建socket对象 并同时请求与服务端程序的连接
        Socket socket = new Socket("127.0.0.1",8888);

        // 2.从Socket中得到一个字节输出流并包装成数据输出流
        OutputStream os = socket.getOutputStream();

        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        // 4.开始写出数据
        dos.writeUTF("万水千山");
        dos.close();

        socket.close(); //释放资源
    }
}
package IP_Study.tcp01;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动成功");

        // 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求
        Socket socket = serverSocket.accept();

        // 3.从Socket中获得一个字节数入流管道
        InputStream is = socket.getInputStream();

        // 4.把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        // 5.使用数据输入流读取客户端发送的消息
        String rs = dis.readUTF(); //信息格式要统一
        System.out.println(rs);

        // 获取客户端的IP地址
        System.out.println(socket.getRemoteSocketAddress());

        dis.close();
        socket.close();
    }
}


5.TCP通信—多发多收

package IP_Study.tcp01;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1.创建socket对象 并同时请求与服务端程序的连接
        Socket socket = new Socket("127.0.0.1",8888);

        // 2.从Socket中得到一个字节输出流并包装成数据输出流
        OutputStream os = socket.getOutputStream();

        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            // 4.开始写出数据
            System.out.println("请说");
            String rs = sc.nextLine();

            // 一旦输入 exit 就退出客户端
            if("exit".equals(rs)){
                System.out.println("退出成功");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(rs);
            dos.flush(); //刷新数据流 以免数据没有发出去
        }
    }
}
package IP_Study.tcp01;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动成功");

        // 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求
        Socket socket = serverSocket.accept();

        // 3.从Socket中获得一个字节数入流管道
        InputStream is = socket.getInputStream();

        // 4.把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        while (true) {
            // 5.使用数据输入流读取客户端发送的消息
            try {
                String rs = dis.readUTF(); //信息格式要统一
                System.out.println(rs);

                // 获取客户端的IP地址
                System.out.println(socket.getRemoteSocketAddress());
            } catch (Exception e) {
                System.out.println(socket.getRemoteSocketAddress() + "离线了");
                dis.close();
                socket.close();
                break;
            }
        }
    }
}

         此时的代码是不能实现与多个客户端进行通信的 因为服务器只搭建一个通道


6.TCP通信—同时接收多个客户端

改造代码时 不能单纯依靠死循环 还需要使用线程技术进行处理

package IP_Study.tcp01;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1.创建socket对象 并同时请求与服务端程序的连接
        Socket socket = new Socket("127.0.0.1",8888);

        // 2.从Socket中得到一个字节输出流并包装成数据输出流
        OutputStream os = socket.getOutputStream();

        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            // 4.开始写出数据
            System.out.println("请说");
            String rs = sc.nextLine();

            // 一旦输入 exit 就退出客户端
            if("exit".equals(rs)){
                System.out.println("退出成功");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(rs);
            dos.flush(); //刷新数据流 以免数据没有发出去
        }
    }
}
package IP_Study.tcp01;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动成功");

        while (true) {
            // 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求
            Socket socket = serverSocket.accept();
            System.out.println("有人上线了"+socket.getRemoteSocketAddress());

            // 把这个客户端的Socket通信管道交给一个独立的线程去完成
            new SeverReadder(socket).start();


        }
    }
}

 使用一个线程类来实现功能

package IP_Study.tcp01;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class SeverReadder extends Thread{
    private Socket socaket;

    public SeverReadder(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run(){
        // 3.从Socket中获得一个字节数入流管道
        try {
            InputStream is = socket.getInputStream();
            // 4.把原始的字节输入流包装成数据输入流
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                try {
                    // 5.使用数据输入流读取客户端发送的消息
                    String rs = dis.readUTF(); //信息格式要统一
                    System.out.println(rs);
                    // 获取客户端的IP地址
                    System.out.println(socket.getRemoteSocketAddress());
                } catch (IOException e) {
                    System.out.println(socket.getRemoteSocketAddress() + "离线了");
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
           e.printStackTrace();
        }
    }
}

7.TCP通信—综合案例

(1)即时通信-群聊

    TCP通信-端口转发 实现思路是将存储好当前在线的socket都进行一次信息发送

package IP_Study.tcp01;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1.创建socket对象 并同时请求与服务端程序的连接
        Socket socket = new Socket("127.0.0.1",8888);

        // 创建一个独立线程 负责随机从socket中接收服务器发送的信息
        new ClientReader(socket);

        // 2.从Socket中得到一个字节输出流并包装成数据输出流
        OutputStream os = socket.getOutputStream();

        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            // 4.开始写出数据
            System.out.println("请说");
            String rs = sc.nextLine();

            // 一旦输入 exit 就退出客户端
            if("exit".equals(rs)){
                System.out.println("退出成功");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(rs);
            dos.flush(); //刷新数据流 以免数据没有发出去
        }
    }
}
package IP_Study.tcp01;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class ClientReader extends Thread{
    private Socket socket;
    public ClientReader(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            // 4.把原始的字节输入流包装成数据输入流
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                try {
                    // 5.使用数据输入流读取客户端发送的消息
                    String rs = dis.readUTF(); //信息格式要统一
                    System.out.println(rs);
                    // 获取客户端的IP地址
                    System.out.println(socket.getRemoteSocketAddress());
                } catch (IOException e) {
                    System.out.println("自己离线了"+socket.getRemoteSocketAddress());
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
package IP_Study.tcp01;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {
    public static List<Socket> onLineSockets = new ArrayList<>();
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动成功");

        while (true) {
            // 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求
            Socket socket = serverSocket.accept();
            onLineSockets.add(socket);
            System.out.println("有人上线了"+socket.getRemoteSocketAddress());

            // 把这个客户端的Socket通信管道交给一个独立的线程去完成
            new SeverReader(socket).start();
        }
    }
}
package IP_Study.tcp01;

import java.io.*;
import java.net.Socket;

public class SeverReader extends Thread{
    private Socket socket;

    public SeverReader(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run(){
        // 3.从Socket中获得一个字节数入流管道
        try {
            InputStream is = socket.getInputStream();
            // 4.把原始的字节输入流包装成数据输入流
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                try {
                    // 5.使用数据输入流读取客户端发送的消息
                    String rs = dis.readUTF(); //信息格式要统一
                    System.out.println(rs);
                    //把这个信息发给全部客户端进行接收
                    SendMsgToAll(rs);
                    // 获取客户端的IP地址
                    System.out.println(socket.getRemoteSocketAddress());
                } catch (IOException e) {
                    System.out.println(socket.getRemoteSocketAddress() + "离线了");
                    Server.onLineSockets.remove(socket);
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
           e.printStackTrace();
        }
    }

    private void SendMsgToAll(String rs) throws Exception {
        // 发送给全部在线的socket管道接受
        for (Socket onLineSocket : Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            dos.writeUTF(rs);
            dos.flush();
        }
    }
}

 实现思路:

当客户端有信息传输到服务器中,先将信息在服务端调用,在向所有在线的通信管道传输信息

(2)实现一个简易的BS架构

package IP_Study.tcp02;

import IP_Study.tcp01.SeverReader;

import java.net.ServerSocket;
import java.net.Socket;

public class Sever {
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动成功");

        while (true) {
            // 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求
            Socket socket = serverSocket.accept();

            System.out.println("有人上线了"+socket.getRemoteSocketAddress());

            // 把这个客户端的Socket通信管道交给一个独立的线程去完成
            new SeverReader(socket).start();
        }
    }
}
package IP_Study.tcp02;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

public class SeverReader extends Thread{
    private Socket socket;

    public SeverReader(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
    // 响应一个网页内容
        try {
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os);
            ps.println("HTTP/1.1 200 OK");
            ps.println("Content-Type:text/html;charset=UTF-8");
            ps.println();//必须换行
            ps.println("<div style='color:purple;font-size:101px;text-align:center' >万水千山 我陪你去看");
            ps.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 *线程优化

  在高并发下 处理任务容易宕机 所以使用线程池来处理线程(注意线程池的参数)

package IP_Study.tcp02;

import IP_Study.tcp01.SeverReader;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Sever {
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动成功");

        // 创建线程池 负责处理通信管道任务
        ThreadPoolExecutor pool = new ThreadPoolExecutor(16 * 2, 16 * 2, 0, TimeUnit.SECONDS,new ArrayBlockingQueue<>(8)
                , Executors.defaultThreadFactory()
                , new ThreadPoolExecutor.AbortPolicy());

        while (true) {
            // 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求
            Socket socket = serverSocket.accept();
            pool.execute(new SeverReader(socket));
            System.out.println("有人上线了"+socket.getRemoteSocketAddress());

            // 把这个客户端的Socket通信管道交给一个独立的线程去完成
            new SeverReader(socket).start();
        }
    }
}

                                                                                                        学习时间:2024.09.04

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

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

相关文章

RHCE必过技巧,无需本人参加也可拿证?

RHCE(无需本人参加&#xff0c;给信息给款即可拿证) ​培训&#xff0b;认证 ​月初一期 ​月尾一期

回归预测 | Matlab基于贝叶斯算法优化XGBoost(BO-XGBoost/Bayes-XGBoost)的数据回归预测+交叉验证

回归预测 | Matlab基于贝叶斯算法优化XGBoost(BO-XGBoost/Bayes-XGBoost)的数据回归预测交叉验证 目录 回归预测 | Matlab基于贝叶斯算法优化XGBoost(BO-XGBoost/Bayes-XGBoost)的数据回归预测交叉验证效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现基于贝叶…

生命科学、食品科学信息类综合全文数据库

一、Nature系列资源 《Nature》杂志1869年创刊于英国&#xff0c;是最早的国际性科技期刊&#xff0c;其办刊宗旨是“将科学发现的重要结果介绍给公众&#xff0c;让公众尽早知道全世界自然知识的每一分支中取得的所有进展”。它报道和评论全球科技领域里最重要的突破&#xf…

【2024全国大学生数学建模竞赛】B题 模型建立与求解(含代码与论文)

目录 1问题重述1.1问题背景1.2研究意义1.3具体问题 2总体分析3模型假设4符号说明&#xff08;等四问全部更新完再写&#xff09;5模型的建立与求解5.1问题一模型的建立与求解5.1.1问题的具体分析5.1.2模型的准备 目前B题第一问的详细求解过程以及对应论文部分已经完成&#xff…

python_使用tkinter建立一个页面的模板

python_使用tkinter建立一个页面的模板 效果如图&#xff0c; 代码如下 """ python设计一下tkinter的布局在最上面排列5个按钮&#xff0c;然后一排4个水平分布的按钮,下面分左右两个图像显示&#xff0c;默认为白色背景为了实现您所描述的Tkinter布局&…

计组 2.Linux上程序的编写与调试

1. 我们之间使用vim创建.c文件&#xff0c;在里面编写完成后按住esc后冒号加wq保存退出 再使用gcc编译.c文件即可 vim test.c gcc test.c2. 这道题对比上一道题多出了编译过程&#xff0c;我们只需要按要求编译即可 gcc -E hello.c -o hello.i # 预处理阶段 gcc -S hello.i…

【超详细】windows Docker安装

关于 Docker 可以把应用以及其依赖都打包到一个容器中&#xff0c;而这个容器的性能开销极低。 Docker 并非是一个通用的容器工具&#xff0c;它依赖于已存在并运行的 Linux 内核环境。Docker Desktop 是 Docker 在 Windows 10 和 macOS 操作系统上的官方安装方式&#xff0c…

opencv实战项目二十一:MediaPipe人体姿态检测

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、MediaPipe是什么&#xff1f;二、MediaPipe使用&#xff1a;三、算法流程&#xff1a;四、效果&#xff1a; 前言 在智能科技不断渗透我们日常生活的今天&…

redis分布式锁和lua脚本

业务场景&#xff1a;多个线程对共同资源的访问&#xff1a;库存超卖/用户重复下单的原因 解决方法一&#xff1a;利用jvm内置锁&#xff0c;将非原子性操作变成原子性操作 Synchronized锁的是对象&#xff0c;对象必须是单例的。锁的是this,代表当前所在的类&#xff0c;这个…

“电轿三巨头”集齐,新车能否后浪拍前浪?

文/王俣祺 导语&#xff1a;纵观全年&#xff0c;要说哪款电车最火&#xff0c;那必然得是小米SU7。小米SU7在今年上半年上市以来&#xff0c;基本垄断了整个国产20万级电轿市场&#xff0c;甚至具备了和称霸电轿市场已久的特斯拉Model 3掰掰手腕的实力。那么&#xff0c;如今的…

Stream插件相关的用法

文章目录 1. 概念介绍2. 使用方法2.1 StreamController2.2 StreamBuilder 3. 示例代码 我们在上一章回中介绍了管理Stream事件流相关的内容&#xff0c;本章回中将介绍如何使用Stream事件流输入输出数据 。闲话休提&#xff0c;言归正传&#xff0c;让我们一起Talk Flutter吧。…

FPGA搭建XDMA中断模式的PCIE通信架构,简单读写测试,提供7套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案 3、PCIE基础知识4、工程详细设计方案工程设计原理框图XDMA配置及使用XDMA中断模块数据缓存架构用户逻辑Windows版本XDMA驱动安装Linux版本XDMA驱动安装测试应用程序工程源码架构PCIE上板调试注意事项 5、vivado工…

2024年了,软件测试已经饱和了?

这个年头找工作跟找对象一样难&#xff0c;咳咳&#xff0c;工作对象都木有&#xff0c;双重打击5555。 关于今年的就业市场&#xff0c;很多人表示特别惨淡&#xff0c;以往简历一投就有大批企业来联系&#xff0c;今年自己投递一大堆简历出去&#xff0c;可能全部都是已读不…

黑神话悟空现在有哪些结局?黑神话悟空攻略来啦!

结局 1:天命人戴上金箍&#xff0c;继承了大圣意志&#xff0c;成为了新大圣。 最终 Boss:孙悟空&#xff1a;玩家需经历两场遭遇战&#xff0c;‌每场都分为两个阶段。‌ 首战&#xff0c;‌玩家需独自对抗石猴;‌而在第二阶段&#xff0c;‌则要面对两位掌握不同元素力量的…

Nacos注册中心与OpenFeign远程调用

文章目录 一、注册中心原理二、Nacos注册中心三、服务注册四、服务发现五、OpenFeign 一、注册中心原理 在微服务当中必须有两个角色 服务提供者&#xff1a;提供接口供其它微服务访问 服务消费者&#xff1a;调用其它微服务提供的接口 在大型微服务项目中&#xff0c;服务提供…

3600+银行财务数据大全(1954-2022年)

3600银行财务数据&#xff0c;包括农村商业银行、村镇银行、外资银行、民营银行、股份制商业银行、城市商业银行、大型商业银行、农村合作银行、其他商业银行等。共计120个指标&#xff0c;银行基本信息、业务发展、财务指标、信贷资产、员工、负债等数据 一、数据介绍 数据名…

ChatTCP:一款离线TCP数据包分析macOS APP,致力于让分析TCP数据包像看聊天记录一样简单

ChatTCP是一款离线TCP数据包分析macOS APP&#xff0c;致力于让分析TCP数据包像看聊天记录一样简单&#xff01;已为UI交互方式申请专利&#xff0c;独家聊天会话方式分析TCP数据包&#xff0c;给你不一样的TCP数据包分析体验! ChatTCP是Easy TCP Analysis的离线版本&#xff…

【docker】了解什么是Docker

一、前言 最近&#xff0c;在学习如何部署项目的时候&#xff0c;老是出错误&#xff0c;然后朋友推荐了去学一下docker,然后自己就去学了【尚硅谷】的关于docker的教程视频&#xff0c;学完之后&#xff0c;感觉docker真的强&#xff0c;可以把我们做好的app的进行跨平台、快速…

vue3+ts项目引入vue-codemirror实现yaml代码编辑器

重要提示 重新安装依赖后一定要重启项目&#xff01;&#xff01;&#xff01; 网上搜到的案例拿过来都报错&#xff1f;那应该是插件的版本不一样&#xff0c;先弄清版本&#xff01;&#xff01;&#xff01; 本示例相关版本如下 npm i vue-codemirror6 // 按自己所需的…

QT学习之计算器

网格布局初尝试&#xff0c;快速构建计算器 项目结构&#xff1a; wident.h拖动建立界面&#xff0c;20个button&#xff0c;一个lineedit 布局好后整体网格布局调整&#xff0c;依次给每个案件输入文本&#xff0c;并改objectname方便后期辨识 为了在lineedit显示数字&…