Java笔记_21
一、网路编程
1.1、初始网络编程
什么是网络编程
在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
- 应用场景:即时通信、网游对战、金融证券、国际贸易、邮件、等等。不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输。
- Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。
常见的软件架构
BS架构的优缺点:
- 不需要开发客户端,只需要页面+服务端
- 用户不需要下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
CS架构的优缺点:
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务端
- 用户需要下载和更新的时候太麻烦
1.2、网络编程三要素
IP
- 设备在网络中的地址,是唯一的标识。
端口号
- 应用程序在设备中唯一的标识。
协议
- 数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。
1.3、IP
全称:Internet Protocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签。
通俗理解:上网设备在网络中的地址,是唯一的
IPv4
全称: Internet Protocol version 4,互联网通信协议第四版
采用32位地址长度,分成4组
- 目前的主流方案,最多有2^32次方个ip,目前已经用完了
lPv6
全称: Internet Protocol version 6,互联网通信协议第六版。
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而IPv4的模式下IP的总数是有限的。
采用128位地址长度,分成8组
- 最多有2^128次方个ip
lPv4的地址分类形式
- 公网地址(万维网使用)和私有地址(局域网使用)。
- 192.168.开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用,以此节省IP
特殊IP地址
127.0.0.1,也可以是localhost:
是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。
常用的CMD命令
ipconfig: 查看本机IP地址
ping: 检查网络是否连通
lnetAddress的使用
方法名称 | 说明 |
---|---|
static InetAddress getByName(String host) | 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 |
string getHostName( ) | 获取此IP地址的主机名 |
string getHostAddress() | 返回文本显示中的IP地址字符串 |
package threadPool.Dome3;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Dome {
public static void main(String[] args) throws UnknownHostException {
//确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
InetAddress address = InetAddress.getByName("Smulll");
System.out.println(address);
//获取主机名称
System.out.println(address.getHostName());
//获取主机ip地址
System.out.println(address.getHostAddress());
}
}
1.4、端口号
应用程序在设备中唯一的标识。
端口号:
- 由两个字节表示的整数,取值范围:0~65535
- 其中0~1023之间的端口号用于一些知名的网络服务或者应用。
- 我们自己使用1024以上的端口号就可以了。
注意:一个端口号只能被一个应用程序使用
1.5、协议
计算机网络中,连接和通信的规则被称为网络通信协议
- OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
- TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
UDP协议
- 用户数据报协议(User Datagram Protocol)
- UDP是面向无连接通信协议。
- 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
TCP协议
- 传输控制协议TCP(Transmission Control Protocol)
- TCP协议是面向连接的通信协议。
- 速度慢,没有大小限制,数据安全。
1.6、UDP协议
发送数据
- 找快递公司
创建发送端的DatagramSocket对象 - 打包礼物
数据打包 (DatagramPacket) - 快递公司发送包裹
发送数据 - 付钱走人
释放资源
package socketnet.Dome2;
import java.io.IOException;
import java.net.*;
public class dome {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket对象(快递公司)
//细节:
//绑定端口,以后我们就是通过这个端口往外发送
//空参:所有可用地端口随机一个进行使用
//有参:指定端口号进行绑定
DatagramSocket ds = new DatagramSocket();
//打包数据
String str = "你好啊。。。";
byte[] bytes = str.getBytes();
//发送的地址
InetAddress address = InetAddress.getByName("127.0.0.1");
//要发送的端口号
int port = 10086;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//发送数据
ds.send(dp);
//释放资源
ds.close();
}
}
1.7、UDP通讯程序(接受数据)
- 找快递公司
创建接收端的DatagramSocket对象 - 接收箱子
接收打包好的数据 - 从箱子里面获取礼物
解析数据包 - 签收走人
释放资源
package socketnet.Dome2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Dome2 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10086);
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
//解析数据包
byte[] data = dp.getData();
int len = dp.getLength();
InetAddress address = dp.getAddress();
int port = dp.getPort();
System.out.println("接收到的数据"+new String(data,0,len));
System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口发出的");
//释放资源
ds.close();
}
}
1.8、UDP练习(聊天室)
package socketnet.Dome3;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class dome2 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
//输入要打印的数据
while (true) {
System.out.println("输入你想说的话");
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
byte[] bytes = str.getBytes();
if (str.equals("不聊了")){
break;
}
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086;
//打包数据
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
}
//关闭
ds.close();
}
}
package socketnet.Dome3;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class dome1 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10086);
//接受数据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
while (true) {
ds.receive(dp);
//解析数据
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
byte[] data = dp.getData();
int len = data.length;
System.out.println("ip为:"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,len));
}
}
}
1.8、UDP的三种通信方式
- 单播
- 以前的代码就是单播
- 组播
- 组播地址:
224.0.0.0
~239.255.255.255
- 其中
224.0.0.0
~224.0.0.255
为预留的组播地址
组播使用MulticastSocket
方法来创建对象
package socketnet.Dome4;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class dome2 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket();
//打包数据
String str = "你好啊。。。";
byte[] bytes = str.getBytes();
//发送的地址
InetAddress address = InetAddress.getByName("224.0.0.1");
//要发送的端口号
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//发送数据
ms.send(dp);
//释放资源
ms.close();
}
}
package socketnet.Dome4;
import java.io.IOException;
import java.net.*;
public class dome1 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000);
//将当前主机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
ms.joinGroup(address);
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//该方法是堵塞的
//程序执行到这一步的时候,会在这里死等
//等发送端发送消息
ms.receive(dp);
//解析数据包
byte[] data = dp.getData();
int len = dp.getLength();
int port = dp.getPort();
System.out.println("接收到的数据"+new String(data,0,len));
System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口发出的");
//释放资源
ms.close();
}
}
package socketnet.Dome4;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class dome {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000);
//将当前主机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
ms.joinGroup(address);
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//该方法是堵塞的
//程序执行到这一步的时候,会在这里死等
//等发送端发送消息
ms.receive(dp);
//解析数据包
byte[] data = dp.getData();
int len = dp.getLength();
int port = dp.getPort();
System.out.println("接收到的数据"+new String(data,0,len));
System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口发出的");
//释放资源
ms.close();
}
}
- 广播
- 广播地址:
255.255.255.255
package socketnet.Dome5;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class dome {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket();
//打包数据
String str = "你好啊。。。";
byte[] bytes = str.getBytes();
//发送的地址
InetAddress address = InetAddress.getByName("255.255.255.255");
//要发送的端口号
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//发送数据
ms.send(dp);
//释放资源
ms.close();
}
}
1.9、TCP通信程序
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket
对象
通信之前要保证连接已经建立
通过Socket产生lO流来进行网络通信
客户端(Socket)
- 创建客户端的Socket对象(Socket)与指定服务端连接
Socket(String host , int port)
- 获取输出流,写数据
OutputStream getOutputstream()
- 释放资源
void close
服务器(ServerSocket)
-
创建服务器端的Socket对象(ServerSocket)
ServerSocket(int port)
-
监听客户端连接,返回一个Socket对象
Socket accept()
-
获取输入流,读数据,并把数据显示在控制台
InputStream getInputStream()
-
释放资源
void close
package socketnet.TCP.Dome1;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class dome2 {
public static void main(String[] args) throws IOException {
//创建Socket对象
//细节:在创建对象的同时会链接服务器
// 如果连接不上,代码会报错
Socket s = new Socket("127.0.0.1",10086);
OutputStream os = s.getOutputStream();
os.write("aaa".getBytes());
os.close();
s.close();
}
}
package socketnet.TCP.Dome1;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class dome {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
int b;
while ((b=is.read())!=-1){
System.out.print((char) b);
}
//释放资源
socket.close();
ss.close();
}
}
代码细节
1.10、TCP通信程序(三次握手和四次挥手)
- 三次握手
- 确保连接建立
- 确保连接建立
- 四次挥手
- 确保连接断开,且数据处理完毕
二、综合练习
2.1、多发多收
package socketnet.MyTest.Test1;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Dome2 {
public static void main(String[] args) throws IOException {
//创建对象
Socket socket = new Socket("127.0.0.1",10086);
//输入数据
OutputStream os = socket.getOutputStream();
while (true) {
System.out.println("请输入你要说的话(英文):");
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
if (s.equals("over")){
break;
}
os.write(s.getBytes());
}
//释放数据
socket.close();
}
}
package socketnet.MyTest.Test1;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Dome1 {
public static void main(String[] args) throws IOException {
//创建对象绑定端口
ServerSocket ss = new ServerSocket(10086);
//等待客户端来连接
Socket socket = ss.accept();
//读取数据
InputStreamReader is = new InputStreamReader(socket.getInputStream());
int len;
while ((len=is.read())!=-1){
System.out.print((char) len);
}
socket.close();
ss.close();
}
}
2.2、接受并反馈
package socketnet.MyTest.Test2;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Dome1 {//服务端
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
Socket Socket = ss.accept();
InputStreamReader is =new InputStreamReader(Socket.getInputStream());
//read方法会从连接通道中读取数据
//但是需要一个结束标记,此处的程序才会停止
//否则,程序就会一直停在read方法这里 等待读取下面的数据
int len;
while ((len=is.read())!=-1){
System.out.print((char) len);
}
//回写数据
OutputStream os = Socket.getOutputStream();
os.write("你也好啊".getBytes());
Socket.close();
ss.close();
}
}
package socketnet.MyTest.Test2;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class Dome2 {
public static void main(String[] args) throws IOException {
Socket Socket = new Socket("127.0.0.1", 10086);
OutputStream os = Socket.getOutputStream();
os.write("你好".getBytes());
//结束标记
Socket.shutdownOutput();
//接受回写的数据
InputStreamReader isr =new InputStreamReader(Socket.getInputStream());
int len;
while ((len=isr.read())!=-1){
System.out.print((char) len);
}
System.out.println();
Socket.close();
}
}
2.3、上传文件
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Dome2 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
//等待客户机连接
Socket socket = ss.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\Java\\IDEA\\代码文件\\Three\\src\\socketnet\\MyTest\\Test3\\a.jpg"));
System.out.println("=========接受数据=========");
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
System.out.println("=============数据接收完毕==============");
//回写数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
System.out.println("============返回信号=============");
bw.write("数据传输完毕");
bw.newLine();
bw.flush();
System.out.println("==================信号返回完毕============");
socket.close();
}
}
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.Socket;
public class Dome1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10086);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\20265\\Pictures\\DAVID TAO\\David Tao同名专辑.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//往服务器里写出结束标记
socket.shutdownOutput();
System.out.println("==========开始回收数据================");
//接受服务器的回写数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
System.out.println(line);
//释放资源
socket.close();
}
}
2.4、文件重名
- Java里面有个UUID类
- 可以使用该类生成一个随机的文件名
- 可以使用静态的
randomUUID
方法,返回一个UUID对象
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Dome2 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
//等待客户机连接
Socket socket = ss.accept();
String name = java.util.UUID.randomUUID().toString().replace("-", "");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\Java\\IDEA\\代码文件\\Three\\src\\socketnet\\MyTest\\Test3\\"+name+".jpg"));
System.out.println("=========接受数据=========");
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
System.out.println("=============数据接收完毕==============");
//回写数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
System.out.println("============返回信号=============");
bw.write("数据传输完毕");
bw.newLine();
bw.flush();
System.out.println("==================信号返回完毕============");
socket.close();
}
}
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.Socket;
public class Dome1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10086);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\20265\\Pictures\\DAVID TAO\\David Tao同名专辑.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//往服务器里写出结束标记
socket.shutdownOutput();
System.out.println("==========开始回收数据================");
//接受服务器的回写数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
System.out.println(line);
//释放资源
socket.close();
}
}
2.5、上传文件(多线程版)
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.Socket;
public class Dome1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10086);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\20265\\Pictures\\DAVID TAO\\David Tao同名专辑.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//往服务器里写出结束标记
socket.shutdownOutput();
System.out.println("==========开始回收数据================");
//接受服务器的回写数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
System.out.println(line);
//释放资源
socket.close();
}
}
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Dome2 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
//等待客户机连接
while (true){
Socket socket = ss.accept();
Thread thread = new Thread(new Mythread(socket));
thread.start();
}
}
}
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.Socket;
public class Mythread implements Runnable{
Socket socket;
public Mythread(Socket socket){
this.socket = socket;
}
public void run() {
try {
String name = java.util.UUID.randomUUID().toString().replace("-", "");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\Java\\IDEA\\代码文件\\Three\\src\\socketnet\\MyTest\\Test3\\"+name+".jpg"));
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//回写数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("数据传输完毕");
bw.newLine();
bw.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (socket!=null){
try {
socket.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
2.5、上传文件(线程池优化)
package socketnet.MyTest.Test3;
import java.io.*;
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 Dome2 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
//创建线程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,//核心线程数量
16,//最大线程数量
60,//线程存活时间
TimeUnit.SECONDS,//线程存活时间(单位)
new ArrayBlockingQueue<>(2),//创建线程队列
Executors.defaultThreadFactory(),//创建线程工厂
new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
);
//等待客户机连接
while (true){
Socket socket = ss.accept();
pool.submit(new Mythread(socket));
}
}
}
package socketnet.MyTest.Test3;
import java.io.*;
import java.net.Socket;
public class Dome1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10086);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\20265\\Pictures\\DAVID TAO\\David Tao同名专辑.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//往服务器里写出结束标记
socket.shutdownOutput();
System.out.println("==========开始回收数据================");
//接受服务器的回写数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
System.out.println(line);
//释放资源
socket.close();
}
}
2.7、接受浏览器的消息并打印
- 运行该代码然后直接在浏览器中打开该网站
- 打开网站之后会将数据返回到IDEA控制台中
package socketnet.MyTest.Test1;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Dome1 {
public static void main(String[] args) throws IOException {
//创建对象绑定端口
ServerSocket ss = new ServerSocket(10086);
//等待客户端来连接
Socket socket = ss.accept();
//读取数据
InputStreamReader is = new InputStreamReader(socket.getInputStream());
int len;
while ((len=is.read())!=-1){
System.out.print((char) len);
}
socket.close();
ss.close();
}
}
返回的数据:
GET / HTTP/1.1
Host: 127.0.0.1:10086
Connection: keep-alive
sec-ch-ua: "Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6