【JAVA基础之网络编程】UDP和TCP协议以及三次握手和四次挥手的过程

🔥作者主页:小林同学的学习笔录

🔥mysql专栏:小林同学的专栏

目录

1. 网络编程

1.1  概述

1.2  网络编程的三要素

1.2.1  IP地址

1.2.2  InetAddress

1.2.3  端口和协议

1.3  UDP协议

1.3.1  UDP发送数据

1.3.2  UDP接收数据

1.4  TCP协议

1.4.1  TCP协议实例

1.4.2  三次握手,四次挥手


1. 网络编程

1.1  概述

概述:在网络通信协议下,不同计算机上运行的程序,进行数据的传输

java.net包中可以看见常见的网络应用程序API

常见的软件架构:

C/S:Client / Server   客户端 / 服务器

  • 需要用户下载并安装客户端程序,在远程有一个服务器程序
  • 优缺点:
    • 画面可以做的比较精美,用户体验好(不需要网络传输,数据来源于安装包)
    • 需要开发客户端,也需要开发服务端
    • 用户需要下载和更新的时候太麻烦 

B/S:Browser / Server  浏览器 /  服务器

  • 只需要一个浏览器,通过访问不同的网址实现操作程序,客户访问不同的服务器
  • 优缺点:
    • 不需要开发客户端,只需要页面 + 服务器
    • 用户不需要下载,打开浏览器就能使用
    • 如果应用过大,用户体验将受到影响(因为数据进行网络传输效率比较低)

1.2  网络编程的三要素

IP:设备在网络中的地址,是唯一标识

端口号:应用程序在设备中的唯一标识

协议:数据在网络中的传输规则,常见的协议有UDP,TCP,HTTP,HTTPS,FTP

1.2.1  IP地址

IP地址分为两大类:

  • IPv4:是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了。为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“.”分隔不同的字节。于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多,最多有2^32次方个IP

  • IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,每一组用分号隔开,这样就解决了网络地址资源数量不够的问题,最多有2^128次方个IP、

DOS常用命令:

  • ipconfig:查看本机IP地址

  • ping IP地址:检查网络与目标主机是否能连通

特殊IP地址:

  • 127.0.0.1:是回送地址,可以代表本机地址LocalHost,一般用来测试使用

疑问:假设192.168.1.100是我的电脑IP,那么这个IP跟127.0.0.1是一样吗?

不一样,192.168.1.100和127.0.0.1不是一样的IP地址。192.168.1.100是局域网内的私有IP地址,用于在局域网中标识设备。而127.0.0.1是本地回环地址,用于在同一台设备内部进行通信。当你的计算机尝试连接127.0.0.1时,它实际上是在尝试与自己通信,而不是与网络上的其他设备通信。

疑问:公网地址(万维网使用)和私有地址(局域网使用)的区别?

公网地址和私有地址之间的主要区别在于它们的可访问性和范围。公网地址是全球唯一的IP地址,用于在互联网上唯一标识设备和进行通信。私有地址则是在局域网内使用的地址,不会在互联网上进行路由,因此不能直接从互联网上访问。私有地址用于在局域网内部进行通信,而通过路由器进行网络地址转换(NAT),可以允许多个设备共享单个公网IP地址来访问互联网。

1.2.2  InetAddress

InetAddress 是 Java 编程语言中用于表示 IP 地址的类。它提供了一种将 IP 地址和主机名相互转换的方式。通过 InetAddress 类,可以实现网络通信中的主机名解析、IP 地址解析等功能。

成员方法:

1.2.3  端口和协议

  • 端口

    • 设备上应用程序的唯一标识

  • 端口号

    • 用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败

  • 协议

    • 计算机网络中,连接和通信的规则被称为网络通信协议

  • UDP协议

    • 用户数据报协议(User Datagram Protocol)

    • UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

    • 由于使用UDP协议消耗系统资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输

    • 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据

    • 例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议

  • TCP协议

    • 传输控制协议 (Transmission Control Protocol)

    • TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”

    • 速度慢,没有大小限制,数据安全

    • 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠

      第一次握手,客户端向服务器端发出连接请求,等待服务器确认

      第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求

      第三次握手,客户端再次向服务器端发送确认信息,确认连接

    • 完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等

1.3  UDP协议

1.3.1  UDP发送数据

构造方法:

成员方法:

发送数据的步骤

  • 创建发送端的Socket对象(DatagramSocket)

  • 创建数据,并把数据打包(DatagramPacket)

  • 调用DatagramSocket对象的方法发送数据(send)

  • 关闭发送端

代码演示:

public class Send {
    public static void main(String[] args) throws IOException {
        /**
         * 创建发送端的Socket对象(DatagramSocket)
         * 创建数据,并把数据打包(DatagramPacket)
         * 调用DatagramSocket对象的方法发送数据(send)
         * 关闭发送端
         */
        //这里参数如果没有端口号,系统会自动分配一个端口号
        DatagramSocket socket = new DatagramSocket(10000);

        String str = "龙颜大怒666";
        byte[] bytes = new byte[1024];
        bytes = str.getBytes();

        DatagramPacket packet = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("127.0.0.1"),10086);
        socket.send(packet);

        socket.close();
    }
}

1.3.2  UDP接收数据

构造方法:

成员方法:

接收数据的步骤

  • 创建接收端的Socket对象(DatagramSocket)

  • 创建一个数据包,用于接收数据(DatagramPacket)

  • 调用DatagramSocket对象的方法接收数据(receive)

  • 解析数据包,并把数据在控制台显示

  • 关闭接收端

代码演示:

public class Receive {
    public static void main(String[] args) throws IOException {
        /**
         * 创建接收端的Socket对象(DatagramSocket)
         * 创建一个数据包,用于接收数据(DatagramPacket)
         * 调用DatagramSocket对象的方法接收数据(receive)
         * 解析数据包,并把数据在控制台显示
         * 关闭接收端
         */

        //注意:这里的端口号一定要与发送端中的数据包端口一致,不然会收不到数据
        DatagramSocket socket = new DatagramSocket(10086);

        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes,bytes.length);

        //这个方法会一直等待发送端发送信息过来,直到拿到数据才会取消阻塞
        socket.receive(packet);

        byte[] data = packet.getData();
        InetAddress address = packet.getAddress();
        int port = packet.getPort();
        System.out.println("数据:" + new String(data,0,packet.getLength()) + " 主机IP:" + address + " 端口号:" + port);

        socket.close();
    }
}

输出结果:

数据:龙颜大怒666 主机IP:/127.0.0.1 端口号:10000

1.4  TCP协议

1.4.1  TCP协议实例

代码演示:

public class Client {
    public static void main(String[] args) throws IOException {
        //创建socket对象
        //细节:在创建对象同时会连接服务端
        //如果连接不上代码会报错
        Socket socket = new Socket("127.0.0.1",10000);
        //创建socket的输出流通道
        OutputStream outputStream = socket.getOutputStream();
        //写入数据
        outputStream.write("你好呀".getBytes());
        //关闭资源
        socket.close();
        outputStream.close();
    }
}
public class Server {
    public static void main(String[] args) throws IOException {
        //这里的端口号要跟客户端的Socket保持一致
        ServerSocket serverSocket = new ServerSocket(10000);
        //这里会阻塞等待客户端发送信息
        Socket socKet = serverSocket.accept();
        //通过socket获取输入流通道
        InputStream inputStream = socKet.getInputStream();
        //解决中文乱码问题
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        int len;
        while ((len = bufferedReader.read()) != -1) {
            System.out.print((char) len);
        }
        //关闭资源
        serverSocket.close();
        socKet.close();
    }
}

1.4.2  三次握手,四次挥手

三次握手:为了确保连接的建立

四次挥手:确保连接断开,且数据处理完毕

1.5  综合练习

1.5.1  多发多送

public class Test01 {
    public static void main(String[] args) throws IOException {
        /**
         * 客户端:多次发送数据
         * 服务端:接收多次数据,并打印
         */
        Socket socket = new Socket("127.0.0.1",10002);

        OutputStream outputStream = socket.getOutputStream();
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("请输入你要发送的信息:");
            String str = scanner.nextLine();
            //用户输入886表示退出
            if("886".equals(str)){
                break;
            }
            outputStream.write(str.getBytes());
        }
        //关闭资源
        outputStream.close();
        socket.close();
    }
}




public class TestServer01 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10002);

        Socket socket = serverSocket.accept();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len;
        while((len = bufferedReader.read()) != -1){
            System.out.print((char)len);
        }
        //关闭资源
        socket.close();
        serverSocket.close();
    }
}

1.5.2  接收并反馈

public class Test02 {
    public static void main(String[] args) throws IOException {
        /**
         * 客户端:发送一条数据,接收服务端反馈的消息并打印
         * 服务端:接收数据并打印,再给客户端反馈信息
         */
        Socket socket = new Socket(InetAddress.getLocalHost(),10003);
        Scanner scanner = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();

        System.out.println("请输入要发给服务端的信息:");
        String str = scanner.nextLine();
        os.write(str.getBytes());

        //细节:这里需要一个结束标记,服务端那边读取才知道结束
        socket.shutdownOutput();

        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int len;
        while ((len = isr.read()) != -1){
            System.out.print((char)len);
        }
        
        socket.close();
    }
}



public class TestServer02 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10003);

        Socket socket = serverSocket.accept();

        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int len;
        //细节:
        //read方法从连接通道读取数据
        //但是需要一个结束标记循环才会停止
        //否则,程序就会一直停在read方法这里,等待读取下面的数据
        while ((len = isr.read()) != -1){
            System.out.print((char)len);
        }

        OutputStream os = socket.getOutputStream();
        os.write("收到客户端的信息".getBytes());

        socket.close();
        serverSocket.close();
    }
}

1.5.3  上传练习

public class Test03 {
    public static void main(String[] args) throws IOException {
        /**
         * 案例需求:
         * 客户端:数据来自于本地文件,接收服务器反馈
         * 服务器:接收到的数据写入本地文件,给出反馈
         */
        Socket socket = new Socket("127.0.0.1", 10000);

        byte[] bytes = new byte[1024];
        int len;

        //这种方式效率比较低
        //FileInputStream fis = new FileInputStream("D:\\img\\0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg");
        //OutputStream os = socket.getOutputStream();

        //缓存流可以降低磁盘IO次数
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("source/0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        //发送数据
        while ((len = bis.read(bytes)) != -1){
            bos.write(bytes,0,len);
        }

        //设置结束标记
        socket.shutdownOutput();

        //接收数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        while ((len = isr.read()) != -1){
            System.out.print((char)len);
        }

        socket.close();
    }
}




public class TestServer03 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10000);

        Socket socket = serverSocket.accept();
        InputStream is = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len;

        //效率低
        //FileOutputStream fos = new FileOutputStream(new File("D:\\test\\a.jpg"));


        //这里需要解决文件名重复问题,导致原先的文件会被后面的覆盖,用UUID来解决
        //System.out.println(UUID.randomUUID());
        //72e165ae-98ad-4cd4-80e9-c9f86b910461,我们一般看到的效果是没有"-"的,需要处理一下
        String name = UUID.randomUUID().toString().replace("-", "");
        //BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\a.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\" + name + ".jpg"));

        //边读边写
        while((len = is.read(bytes)) != -1){
            bos.write(bytes,0,len);
        }

        //发送数据
        OutputStream os = socket.getOutputStream();
        os.write("收到数据啦".getBytes());

        socket.close();
        serverSocket.close();
    }
}

1.5.4  服务器改写成多线程,以及线程优化

服务器只能处理一个客户端请求,接收完一个图片之后,服务器就关闭了。

优化方案一:使用循环

弊端:第一个用户正在上传数据,第二个用户就来访问了,此时第二个用户是无法成功上传的。

所以,使用多线程改进

优化方案二:使用循环 + 多线程

每来一个用户,就开启多线程处理

public class Test04 {
    public static void main(String[] args) throws IOException {
        /**
         * 案例需求:
         * 客户端:数据来自于本地文件,接收服务器反馈
         * 服务器:接收到的数据写入本地文件,给出反馈
         */
        Socket socket = new Socket("127.0.0.1", 10000);

        byte[] bytes = new byte[1024];
        int len;

        //这种方式效率比较低
        //FileInputStream fis = new FileInputStream("D:\\img\\0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg");
        //OutputStream os = socket.getOutputStream();

        //缓存流可以降低磁盘IO次数
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("source/0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        //发送数据
        while ((len = bis.read(bytes)) != -1){
            bos.write(bytes,0,len);
        }

        //设置结束标记
        socket.shutdownOutput();

        //接收数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        while ((len = isr.read()) != -1){
            System.out.print((char)len);
        }

        socket.close();
    }
}



public class TestServer04 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10000);
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                3,//核心线程数量
                16,//线程池总大小
                60,//空闲时间
                TimeUnit.SECONDS,//空闲时间(单位)
                new ArrayBlockingQueue<>(2),//队列
                Executors.defaultThreadFactory(),//线程工厂,让线程池如何创建线程对象
                new ThreadPoolExecutor.AbortPolicy()//阻塞队列
        );

        while (true) {
            //等待客户端连接
            Socket socket = serverSocket.accept();

            //一个用户对应一条线程
            //new Thread(new MyRunnable(socket)).start();

            //线程池进行优化
            poolExecutor.submit(new MyRunnable(socket));
        }
    }
}



public class MyRunnable implements Runnable {
    private Socket socket;

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

    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len;

            //效率低
            //FileOutputStream fos = new FileOutputStream(new File("D:\\test\\a.jpg"));


            //这里需要解决文件名重复问题,导致原先的文件会被后面的覆盖,用UUID来解决
            //System.out.println(UUID.randomUUID());
            //72e165ae-98ad-4cd4-80e9-c9f86b910461,我们一般看到的效果是没有"-"的,需要处理一下
            String name = UUID.randomUUID().toString().replace("-", "");
            //BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\a.jpg"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\" + name + ".jpg"));

            //边读边写
            while ((len = is.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }

            //发送数据
            OutputStream os = socket.getOutputStream();
            os.write("上传成功".getBytes());

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Terminal Web终端基础(Web IDE 技术探索 二)

Terminal是web终端技术&#xff0c;类似cmd命令窗口&#xff0c;Webcontainer 中推荐使用的是Xterm.js&#xff0c;这里就不细说Xterm.js 的使用了&#xff0c;我们使用第三方库来实现&#xff08;原生确实有点难用&#xff09;。 vue-web-terminal 一个由 Vue 构建的支持多内容…

基础5 探索JAVA图形编程桌面:字符操作组件详解

在繁华都市的一个角落&#xff0c;卧龙和凤雏相聚在他们常去的台球厅。灯光洒在绿色的台球桌上&#xff0c;彩色的台球整齐地排列着&#xff0c;仿佛在等待着一场激烈的角逐。 卧龙轻轻地拿起球杆&#xff0c;微微瞄准&#xff0c;然后用力一击&#xff0c;白球带着一股强大的力…

Vue.js - Vue 的安装 以及 常用的 Vue 指令 【0基础向 Vue 基础学习】

文章目录 Vue 快速上手1、Vue.js 官网 & Vue.js 的获取2、创建 Vue 实例&#xff0c;初始化渲染3、插值表达式 安装 Vue 开发者工具&#xff1a;装插件调试 Vue 应用Vue 指令1、v-show 指令2、v-if3、v-else & v-else-if4、v-onv-on 调用传参 5、v-bindv-bind 对于样式…

类和对象(下篇)(未完结)!

文章目录 在谈构造函数1.构造函数体赋值2.初始化列表尽量使用初始化列表&#xff1f;初始化列表的初始化顺序&#xff1f;成员变量声明处的缺省值构造函数支持类型转换3.explicit关键字 static成员 在谈构造函数 1.构造函数体赋值 class Date{public:Date(int year, int mont…

Python设计模式之适配器模式

目录 一、适配器模式 适配器模式的组成部分 适配器模式的种类 应用场景 实现步骤 二、测试例子 一、适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过将一个现有接口转换为另一个期望的接口来让不兼容的接口能够合作…

香港服务器负载过高的原因和应对办法

保持网站正常运行看似简单&#xff0c;但事实上&#xff0c;有许多问题会影响网站和应用程序的性能&#xff0c;并可能导致停机。其中一个问题就是服务器过载。而香港服务器作为一种常见的服务器类型&#xff0c;有时会出现负载过高的情况。为了帮助您确保在香港服务器过载不会…

跨境电商投放Facebook广告推广攻略!

在出海浪潮中&#xff0c;跨境电商已经成为企业连接不同市场、拓展国际业务的重要途径。Facebook&#xff0c;作为全球最大的社交平台之一&#xff0c;拥有超过20亿的活跃用户&#xff0c;为跨境卖家提供了一个无与伦比的营销舞台。有效利用Facebook广告&#xff0c;不仅能帮助…

捕捉二氧化碳也能赚钱?深入探索CCUS技术与商业前景

引言 随着全球变暖和气候变化的加剧&#xff0c;如何有效减少二氧化碳&#xff08;CO2&#xff09;排放成为各国亟待解决的问题。近日&#xff0c;全球最大的二氧化碳捕集工厂在冰岛正式运营&#xff0c;这一消息引起了广泛关注。本文将深入探讨捕集二氧化碳技术&#xff08;C…

海康威视NVR通过ehome协议接入视频监控平台,视频浏览显示3011超时错误的问题解决,即:The request timeout! 【3011】

目录 一、问题描述 二、问题分析 2.1 初步分析 2.2 查看日志 2.3 问题验证 1、查看防火墙 2、查看安全组 3、问题原因 三、问题解决 3.1 防火墙开放相关端口 3.2 安全组增加规则 3.3 测试 1、TCP端口能够联通的情况 2、TCP端口不能够联通的情况 四、验证 五、云…

JWT使用方法

目录 基础概念 依赖 生成令牌 工具类 控制层 解析令牌 工具类 网关过滤器 效果 基础概念 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准&#xff08;(RFC 7519).该token被设计为紧凑且安全的&#xff0c;特别适用于分布式站点…

Hsql每日一题 | day03

前言 就一直向前走吧&#xff0c;沿途的花终将绽放~ 题目&#xff1a;打折日期交叉问题 如下为平台商品促销数据&#xff1a;字段为品牌&#xff0c;打折开始日期&#xff0c;打折结束日期 brand stt edt oppo,2021-06-05,2021-06-09 oppo,2021-06-11,2021-06-21 vivo,…

共享经济中的创新演示:打造案例分析PPT,让想法流动起来

在当今这个看图说话的时代&#xff0c;无论是在职场打拼还是学术殿堂&#xff0c;一份牛气冲天的案例分析PPT无疑是你专业形象的加分项。 不管你是刚出道的小鲜肉&#xff0c;还是已经混迹江湖多年的老鸟&#xff0c;一份有深度、有力度的PPT都能帮你在人群中脱颖而出&#xf…

IT行业已经饱和?2024年报考计算机类专业还有出路吗?

&#x1f446;点击关注 获取更多编程干货&#x1f446; “高薪”光环加持&#xff0c;IT行业一直是不少人心仪的职业选择&#xff0c;计算机专业一度成为最热门的本科专业。 然而&#xff0c;正因报考计算机专业、想要入行IT行业的人越来越多&#xff0c;“行业饱和”、“人才…

Nodejs 第七十三章(网关层)

什么是网关层(getway)&#xff1f; 技术选型fastify 速度快适合网关层 fastify教程上一章有讲 网关层是位于客户端和后端服务之间的中间层&#xff0c;用于处理和转发请求。它充当了请求的入口点&#xff0c;并负责将请求路由到适当的后端服务&#xff0c;并将后端服务的响应…

免费的八字软件

无敌八字排盘软件完全免费使用&#xff0c;即使用不需要付费且无任何限制。同时推出手机版电脑版&#xff0c;两版本数据互通互用&#xff0c;即电脑版的数据可以备份到手机版上导入&#xff0c;手机版的数据也可以备份到电脑版上恢复导入&#xff0c;方便手机和电脑共用的朋友…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(十九)- JUC(5)

synchronized优化原理 轻量级锁 如果一个对象有多个线程访问&#xff0c;但多线程访问的时间是错开的&#xff08;没有竞争&#xff09;&#xff0c;可以用轻量级锁优化 Slf4j(topic "c.ExerciseTransfer")public class Test {​static final Object obj new Obj…

AI爆文写作:如果你有一篇文章爆了,正确的做法是:自己抄袭自己,重复发,还可以继续爆!

爆款总是相似的&#xff0c;如果你有一篇文章爆了&#xff0c;正确的做法&#xff0c;就是重复发&#xff0c;让它继续爆下去。 以前我在小红书看到一个人&#xff0c;将一篇自己火的笔记&#xff0c;连续发了5次&#xff0c;每次点赞数据都不错。 公众号文章也是一样的。 我…

Halcon 极坐标转换图像

一、概述 先看效果 将圆形的用极坐标转换成矩性然后再进行识别或者其他缺陷检测&#xff0c;最后在还圆到原图中 二、原理&#xff1a; halcon 圆环类缺陷检测的一种方法&#xff08;极坐标变换法&#xff09;_halcon缺口检测-CSDN博客 图像极坐标变换与反变换&#xff08;…

谈恋爱没经验?那就来刷谈恋爱经验宝宝吧

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

IDEA连接MySQL后如何管理数据库

上一节讲解了IDEA如何连接MySQL数据库管理系统&#xff0c;接下来我们就可以在IDEA里使用MySQL来管理数据库了。那么如果我们现在还没有创建需要的数据库怎么办&#xff1f;本节就来教大家如何在IDEA连接MySQL后管理数据库(创建/修改/删除数据库、创建/修改/删除表、插入/更新/…