网络编程、UDP、TCP、三次握手、四次挥手

news2024/11/25 6:34:25

一、初识网络编程

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

应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等。

不管是什么场景,都是计算机和计算机之间通过网络进行数据传输。

Java中可以使用java.net包下的技术开发出常见的网络应用程序。

二、常见的软件架构

(一)B/S架构

概念:只需要一个浏览器,用户通过不同的网址,可以访问不同的服务器。例如京东和淘宝。

优缺点:

  1. 不需要开发客户端,只需要开发服务端
  2. 用户不需要下载,打开浏览器就能使用
  3. 如果应用过大,用户体验受到影响

(二)C/S架构 

概念:在用户本地需要下载并安装客户端程序,在远程有一个服务端程序。例如QQ、Steam。

优缺点:

  1. 画面可以做的非常精美,用户体验好
  2. 需要开发客户端,也需要开发服务端
  3. 用户需要下载和更新的时候太麻烦

有些软件,例如京东和淘宝,既又C/S架构,也有B/S架构。

三、网络编程三要素

(一)IP

        IP:(Internet Protocol)是互联网协议地址,也称IP地址,是设备在网络中的地址,是唯一的标识。常见的IP分为:IPv4、IPv6

1.IPv4

        IPv4:(Internet Protocol version4)是互联网通信协议第四版。 采用32为地址长度,分成4组,每组取值范围是0~255,一共有42亿多,为了方便记忆,最后采用点分十进制表示法,例如:192.168.1.66。但是ipv4已经分配完毕了,所以需要ipv6进行补充。

        IPv4的地址分类形式:

  • 公网地址(万维网使用)和私有地址(局域网使用)。
  • 192.168.开头的就是私有地址,范围是192.168.0.0--192.168.255.255,专门为组织机构内部使用,以此节省IP。

        特殊IP地址:127.0.0.1,也可以是localhost:是回送地址,也称本地回环地址,又称本机IP,永远只会寻找当前所在本机。

        检查网络常用的CMD命令:

  • ipconfig:查看本机IP地址
  • ping:检查网络是否连通

2.IPv6

        IPv6:(Internet Protocol version6)是互联网通信协议第六版。采用128位地址长度,分成8组。IPv6一共有2^128次方个IP,采用冒分十六进制表示法:

目前也有很多APP支持IPv6。

3.InetAddress的使用

public class MyInetAddressDemo1 {
    public static void main(String[] args) throws UnknownHostException {
    /*
       static InetAddress getByName(String host)   确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
       String getHostName()                        获取此IP地址的主机名
       String getHostAddress()                     返回文本显示中的IP地址字符串
    */
        // 1.获取InetAddress的对象
        // IP的对象 一台电脑的对象
        InetAddress address = InetAddress.getByName("PC-20240723RWZC");
        System.out.println(address); // PC-20240723RWZC/192.168.0.4

        String hostName = address.getHostName();
        System.out.println(hostName); // PC-20240723RWZC

        String hostAddress = address.getHostAddress();
        System.out.println(hostAddress); // 192.168.0.4
    }
}

(二)端口号

        端口号:是应用程序在设备中唯一的标识。一个端口号只能被一个应用程序使用。

        由两个字节表示的整数,取值范围:0~65535。其中0~1023的端口号用于一些知名的网络服务或者应用,我们使用1024以上的端口号即可。

        以下是一些常见服务使用的端口号列表:这些端口号被IANA(Internet Assigned Numbers Authority)分配给特定的服务,并且广为人知。它们在网络通信中扮演着重要的角色,确保数据能够准确地发送到正确的服务。

  • 21端口:FTP 文件传输服务。
  • 22端口:SSH 远程连接服务。
  • 23端口:TELNET 终端仿真服务。
  • 25端口:SMTP 简单邮件传输服务。
  • 53端口:DNS 域名解析服务。
  • 80端口:HTTP 超文本传输服务。
  • 110端口:POP3(E-mail)。
  • 123端口:NTP(网络时间协议)。
  • 135、137、138、139端口:局域网相关默认端口。
  • 161端口:SNMP(简单网络管理协议)。
  • 389端口:LDAP(轻量级目录访问协议)。
  • 443端口:HTTPS服务器。
  • 465端口:SMTP(简单邮件传输协议)。
  • 873端口:rsync。
  • 989端口:FTPS。
  • 993端口:IMAPS。
  • 995端口:POP3S。
  • 1080端口:SOCKS代理协议服务器常用端口号。
  • 1433端口:MS SQL*SERVER数据库server。
  • 1521端口:Oracle 数据库。
  • 3306端口:MYSQL数据库端口。
  • 3389端口:WIN2003远程登录。
  • 5432端口:postgresql数据库端口。
  • 6379端口:Redis数据库端口。
  • 8080端口:TCP服务端默认端口、JBOSS、TOMCAT。      

(三)协议

1.协议概述

        协议:是指数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。

2.UDP协议

2.1UDP协议介绍

UDP协议又叫用户数据报协议(User Datagram Protocol),是面向无连接通信协议,不管是否已经连接成功,都会直接发送数据。

特点是:速度块,有大小限制,一次最多发送64K,数据不安全,易丢失数据。

UDP协议适用场景:网络会议、语音通话、在线视频,丢失数据没有太大的影响。

2.2使用UDP协议发送数据

步骤:

  1. 创建发送端的DatagramSocket对象
  2. 数据打包(DatagramPacket)
  3. 发送数据
  4. 释放资源

代码实现UDP协议发送数据:

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

public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        // UDP协议发送数据
        // 1.创建DatagramSocket对象
        // 细节:绑定端口,以后就是通过这个端口往外发送
        // 空参:所有可用的端口中随机一个进行使用
        // 有参:指定端口号进行绑定
        DatagramSocket datagramSocket = new DatagramSocket();

        // 2.打包数据
        String str = "hello world";
        byte[] bytes = str.getBytes();
        InetAddress address = InetAddress.getByName("127.0.0.1");
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, 10086);
        // 3.发送数据
        datagramSocket.send(datagramPacket);
        // 4.释放资源
        datagramSocket.close();
    }
}
2.3使用UDP协议接收数据

步骤:

  1. 创建接收端的DatagramSocket对象

  2. 接收打包好的数据

  3. 解析数据包

  4. 释放资源 

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;

public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        // UDP协议接收数据
        // 1.创建DatagramSocket对象
        // 细节:在接收的时候,一定要绑定端口,而且绑定的端口一定要跟发送的端口保持一致
        DatagramSocket datagramSocket = new DatagramSocket(10086);

        // 2.接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);

        // 该方法是阻塞的,程序执行到这一步的时候,会在这里等待发送端发送消息
        datagramSocket.receive(datagramPacket);

        // 3.解析数据包
        byte[] data = datagramPacket.getData();
        InetAddress address = datagramPacket.getAddress();
        int length = datagramPacket.getLength();
        int port = datagramPacket.getPort();
        SocketAddress socketAddress = datagramPacket.getSocketAddress();
        int offset = datagramPacket.getOffset();

        System.out.println("接收到的数据:" + new String(data, 0, length));
        System.out.println("该数据是从:" + address + "这台电脑中的" + port + "端口发出的");
        System.out.println(socketAddress);
        System.out.println("数据偏移量:" + offset);

        // 4.释放资源
        datagramSocket.close();
    }
}

实现过程:

先启动接收程序,再启动发送程序,运行结果:

2.4使用UDP协议实现聊天室
  • 案例需求

    UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束

    UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建对象DatagramSocket的对象
        DatagramSocket datagramSocket = new DatagramSocket();

        // 2.打包数据
        Scanner scanner = new Scanner(System.in);
        InetAddress address = InetAddress.getByName("127.0.0.1");
        while (true) {
            System.out.println("请输入消息:");
            String str = scanner.nextLine();
            if ("886".equals(str)) {
                System.out.println("程序终止!");
                break;
            }
            byte[] bytes = str.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, 10086);
            // 3.发送数据
            datagramSocket.send(datagramPacket);
        }
        // 4.释放资源
        datagramSocket.close();
    }
}
public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建对象DatagramSocket的对象
        DatagramSocket datagramSocket = new DatagramSocket(10086);

        // 2.接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);

        while (true) {
            datagramSocket.receive(datagramPacket);

            // 3.解析数据包
            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            String ip = datagramPacket.getAddress().getHostAddress();
            String hostName = datagramPacket.getAddress().getHostName();
            int port = datagramPacket.getPort();

            // 4.打印数据
            System.out.println(hostName + "电脑的" + ip + ":" + port + "发送消息:" + new String(data, 0, length));
        }
    }
}

运行结果: 

        这里的hostName是activate.netsarang.com的原因是:在某些情况下,如果系统或网络环境中的 hosts 文件(在Windows中位于C:\Windows\System32\drivers\etc\hosts,在Unix/Linux系统中通常位于/etc/hosts)中有相应的条目,那么系统会直接从 hosts 文件中获取主机名,而不是去查询DNS。

        我本地的host文件:找到第一个主机名返回

还可以设置多窗口聊天: 

2.5UDP的三种通信方式
2.5.1单播——一对一通信(One-to-One)

        在这种模式下,一个UDP套接字(客户端)向另一个UDP套接字(服务器)发送数据。客户端知道服务器的IP地址和端口号,可以直接向服务器发送数据包。服务器监听指定的端口,接收来自客户端的数据包。这种模式是最简单的UDP通信方式,适用于客户端和服务器之间的直接通信。

2.5.2组播——一对多通信(One-to-Many)

        在一对多通信中,一个服务器向多个客户端发送数据。服务器使用相同的数据包发送给所有已知客户端的IP地址和端口号。这种模式常用于广播服务,如网络广播、在线游戏或多媒体流服务。服务器不需要为每个客户端维护一个单独的连接,而是向所有客户端广播数据。

        组播地址:224.0.0.0~239.255.255.255

                          其中224.0.0.0~224.0.0.255为预留的组播地址

组播发送端代码:

public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        //创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket();

        // 创建DatagramPacket对象
        String s = "hello world !";
        byte[] bytes = s.getBytes();
        InetAddress address = InetAddress.getByName("224.0.0.1");
        int port = 10000;

        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, port);

        // 调用MulticastSocket发送数据方法发送数据
        ms.send(datagramPacket);

        // 释放资源
        ms.close();
    }
}

组播接收端代码:

public class ReceiveMessageDemo1 {
    public static void main(String[] args) throws IOException {
        // 1. 创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket(10000);

        // 2. 将当前本机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        ms.joinGroup(address);

        // 3. 创建DatagramPacket数据包对象
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

        // 4. 接收数据
        ms.receive(dp);

        // 5. 解析数据
        byte[] data = dp.getData();
        int len = dp.getLength();
        String ip = dp.getAddress().getHostAddress();
        String name = dp.getAddress().getHostName();

        System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));
        // ip为:192.168.0.4,主机名为:PC-20240723RWZC的人,发送了数据:hello world !

        // 6. 释放资源
        ms.close();
    }
}

        接收端可以创建多个,但要保证每一个接收端都要将当前本机,添加到224.0.0.1的这一组当中。这样,发送端发送数据,多个接收端就可以同时接收到了。 

2.5.3广播——多对多通信(Many-to-Many)

        在多对多通信中,多个客户端之间可以直接相互通信,而不需要通过一个中心服务器。每个客户端都可以发送和接收来自其他客户端的数据包。这种模式适用于需要点对点通信的应用,如即时消息、文件共享或P2P网络。在这种模式下,每个客户端都扮演着发送者和接收者的角色。

        广播地址:255.255.255.255 

// 发送端
public class ClientDemo {
    public static void main(String[] args) throws IOException {
      	// 1. 创建发送端Socket对象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket();
		// 2. 创建存储数据的箱子,将广播地址封装进去
        String s = "广播 hello";
        byte[] bytes = s.getBytes();
        InetAddress address = InetAddress.getByName("255.255.255.255");
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
		// 3. 发送数据
        ds.send(dp);
		// 4. 释放资源
        ds.close();
    }
}

// 接收端
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建接收端的Socket对象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket(10000);
        // 2. 创建一个数据包,用于接收数据
        DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
        // 3. 调用DatagramSocket对象的方法接收数据
        ds.receive(dp);
        // 4. 解析数据包,并把数据在控制台显示
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data,0,length));
        // 5. 关闭接收端
        ds.close();
    }
}

3.TCP协议

3.1TCP协议介绍

TCP协议:又叫传输控制协议(Transmission Control Protocol),是面向连接的通信协议。是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通过Socket产生IO流来进行网络通信,通信之前要保证连接已经建立。

特点是:速度慢,没有大小限制,数据安全。

TCP协议适用场景:对于数据有非常高的要求,不能丢失任何数据,例如下载软件、文字聊天、发送邮件。

3.2使用TCP协议发送和接收数据
public class Client {
    public static void main(String[] args) throws IOException {
        // TCP协议,发送数据

        // 1.创建Socket对象
        // 细节:在创建对象的同时会连接服务端;如果连接不上,代码会报错
        Socket socket = new Socket("127.0.0.1", 10001);

        // 2.可以从连接通道中获取输出流
        OutputStream os = socket.getOutputStream();
        // 写出数据
        os.write("hello world".getBytes());
        
        // 3.释放资源
        os.close();
        socket.close();
    }
}

public class Server {
    public static void main(String[] args) throws IOException {
        // TCP协议,接收数据

        // 1.创建对象ServerSocket
        ServerSocket serverSocket = new ServerSocket(10001);

        // 2.监听客户端的连接
        Socket socket = serverSocket.accept();

        // 3.从连接通道中获取输入流读取数据
        InputStream is = socket.getInputStream();
        int len;
        while ((len = is.read()) != -1) {
            System.out.print((char) len);
        }

        // 4.释放资源
        is.close();
        socket.close();
    }
}

先运行Server服务器,再运行Client客户端,运行结果:

3.3解决TCP传输过程中的中文乱码问题

上面的代码使用的是字节流传输,在传输中文时会产生乱码,我们可以使用BufferReader来接收:

public class Server2 {
    public static void main(String[] args) throws IOException {
        // TCP协议,接收数据

        // 1.创建对象ServerSocket
        ServerSocket serverSocket = new ServerSocket(10001);

        // 2.监听客户端的连接
        Socket socket = serverSocket.accept();

        // 3.从连接通道中获取输入流读取数据
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len;
        while ((len = br.read()) != -1) {
            System.out.print((char) len);
        }

        // 4.释放资源
        is.close();
        socket.close();
    }
}

运行结果:

3.4三次握手

3.5四次挥手

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

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

相关文章

在 Jupyter Notebook 中使用 Matplotlib 进行交互式可视化的教程

在 Jupyter Notebook 中使用 Matplotlib 进行交互式可视化的教程 引言 数据可视化是数据分析的重要组成部分,能够帮助我们更直观地理解数据。Matplotlib 是 Python 中最流行的绘图库之一,而 Jupyter Notebook 则是进行数据分析和可视化的理想环境。本文…

[单例模式]

[设计模式] 设计模式是软件工程中的一种常见做法, 它可以理解为"模板", 是针对一些常见的特定场景, 给出的一些比较好的固定的解决方案. 不同语言适用的设计模式是不一样的. 这里我们接下来要谈到的是java中典型的设计模式. 而且由于设计模式比较适合有一定编程经…

STM32软件开发 —— STM32CudeMX使用优点

目 录 STM32CudeMX使用思路步骤详细 STM32CudeMX 在图形化工具STM32CudeMX出现之前,开发者通常是参考库驱动文件中的例程来配置芯片的,进行拷贝和修改等,为了提高开发效率,ST公司开发了STM32CudeMX工具,通过它简化了芯…

江西省补贴性线上职业技能培训管理平台(刷课系统)

江西省补贴性线上职业技能培训管理平台(刷课系统) 目的是为了刷这个网课 此系统有两个版本一个是脚本运行,另外一个是可视化界面运行 可视化运行 技术栈:flask、vue3 原理: 通过分析网站接口,对某些接口加密的参数进行逆向破解,从而修改请求…

Golang | Leetcode Golang题解之第546题移除盒子

题目: 题解: func removeBoxes(boxes []int) int {dp : [100][100][100]int{}var calculatePoints func(boxes []int, l, r, k int) intcalculatePoints func(boxes []int, l, r, k int) int {if l > r {return 0}if dp[l][r][k] 0 {r1, k1 : r, k…

es自动补全(仅供自己参考)

elasticssearch提供了CompletionSuggester查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询效率,对于文档中字段的类型有一些约束: 查询类型必须是:completion 字段内容是多个补全词条形成的数组 P…

ANDROIDWORLD: A Dynamic Benchmarking Environment for Autonomous Agents论文学习

这个任务是基于androidenv的。这个环境之前学过,是一个用来进行强化学习的线上环境。而这篇文章的工作就是要给一些任务加上中间的奖励信号。这种训练环境的优点就是动态,与静态的数据集(比如说我自己的工作)不同,因此…

VBA10-处理Excel的动态数据区域

一、end获取数据边界 1、基本语法 1-1、示例: 2、配合row和column使用 2-1、示例1 2-2、示例2 此时,不管这个有数值的区域,怎么增加边界,对应的统计数据也会跟着变的! 二、end的缺陷 若是数据区域不连贯,则…

【FFmpeg】FFmpeg 函数简介 ③ ( 编解码相关函数 | FFmpeg 源码地址 | FFmpeg 解码器相关 结构体 和 函数 )

文章目录 一、FFmpeg 解码器简介1、解码流程分析2、FFmpeg 编解码器 本质3、FFmpeg 编解码器 ID 和 名称 二、FFmpeg 解码器相关 结构体 / 函数1、AVFormatContext 结构体2、avcodec_find_decoder 函数 - 根据 ID 查找 解码器3、avcodec_find_decoder_by_name 函数 - 根据 名称…

Linux完结

学习视频笔记均来自B站UP主" 泷羽sec",如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 【linux基础之病毒编写(完结)】 https://www.bilibili.com/video…

分享三个python爬虫案例

一、爬取豆瓣电影排行榜Top250存储到Excel文件 近年来,Python在数据爬取和处理方面的应用越来越广泛。本文将介绍一个基于Python的爬虫程序,用于抓取豆瓣电影Top250的相关信息,并将其保存为Excel文件。 获取网页数据的函数,包括以…

【计网】数据链路层笔记

【计网】数据链路层 数据链路层概述 数据链路层在网络体系结构中所处的地位 链路、数据链路和帧 链路(Link)是指从一个节点到相邻节点的一段物理线路(有线或无线),而中间没有任何其他的交换节点。 数据链路(Data Link)是基于链路的。当在一条链路上传送数据时&a…

docker 拉取MySQL8.0镜像以及安装

目录 一、docker安装MySQL镜像 搜索images 拉取MySQL镜像 二、数据挂载 在/root/mysql/conf中创建 *.cnf 文件 创建容器,将数据,日志,配置文件映射到本机 检查MySQL是否启动成功: 三、DBeaver数据库连接 问题一、Public Key Retrieval is not allowed 问题…

【c++篇】:栈、队列、优先队列:容器世界里的秩序魔法 - stack,queue与priority_queue探秘

✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:c篇–CSDN博客 文章目录 前言一.容器stack1.介绍2.成员函数3.模拟实现4.注意事项 二.容器qu…

实现uniapp-微信小程序 搜索框+上拉加载+下拉刷新

pages.json 中的配置 { "path": "pages/message", "style": { "navigationBarTitleText": "消息", "enablePullDownRefresh": true, "onReachBottomDistance": 50 } }, <template><view class…

无人机培训机型有哪些?CAAC考证选3类还是4类

无人机培训是一个涵盖多个方面的综合性过程&#xff0c;旨在培养具备无人机操作技能和相关知识的人才。 无人机培训机型 无人机培训通常涵盖多种机型&#xff0c;以满足不同领域和应用场景的需求。常见的无人机培训机型包括&#xff1a; 1. 多旋翼无人机&#xff1a;也称为多…

95.【C语言】数据结构之双向链表的头插,头删,查找,中间插入,中间删除和销毁函数

目录 1.双向链表的头插 方法一 方法二 2.双向链表的头删 3.双向链表的销毁 4.双向链表的某个节点的数据查找 5.双向链表的中间插入 5.双向链表的中间删除 6.对比顺序表和链表 承接94.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删文章 1.双向链表的头插 方法…

[极客大挑战 2019]PHP 1

[极客大挑战 2019]PHP 1 审题 猜测备份在www.zip中&#xff0c;输入下载文件。 知识点 反序列化 解题 查看代码 看到index.php中包含了class.php,直接看class.php中的代码 查看条件 当usernameadmin&#xff0c;password100时输出flag 构造反序列化 输入select中&#…

C++面试基础知识:排序算法 C++实现

上周实习面试&#xff0c;手撕代码快排没写出来&#xff0c;非常丢人&#xff0c;把面试官都给逗笑了。 基础不牢&#xff0c;地动山摇&#xff0c;基础的算法还是要牢记于心的。 插入排序 分为有序区和无序区&#xff0c;每次从无序区中选出一个&#xff0c;放到有序区域中。…

yarn报错`warning ..\..\package.json: No license field`:已解决

出现这个报错有两个原因 1、项目中没有配置许可证 在项目根目录package.json添加 {"name": "next-starter","version": "1.0.0",# 添加这一行"license": "MIT", }或者配置私有防止发布到外部仓库 {"priv…