一、網(wǎng)絡(luò)編程
1.概述
- 可以讓設(shè)備中的程序與網(wǎng)絡(luò)上其他設(shè)備中的程序進(jìn)行數(shù)據(jù)交互(實(shí)現(xiàn)網(wǎng)絡(luò)通信的)。
- java.net,*包下提供了網(wǎng)絡(luò)編程的解決方案!
基本的通信架構(gòu)
基本的通信架構(gòu)有2種形式:CS架構(gòu)(Client客戶端/Server服務(wù)端)、BS架構(gòu)(Browser瀏覽器/Server服務(wù)端)。
網(wǎng)絡(luò)通信的關(guān)鍵三要素
IP地址
- IP(Internet Protocol):全稱”互聯(lián)網(wǎng)協(xié)議地址”,是分配給上網(wǎng)設(shè)備的唯一標(biāo)志。
- IP地址有兩種形式:IPV4、IPV6
- IPv6:共128位,號(hào)稱可以為地球每一粒沙子編號(hào)。
- IPV6分成8段表示,每段每四位編碼成一個(gè)十六進(jìn)制位表示,數(shù)之間用冒號(hào)(:)分開。
IP域名
- 公網(wǎng)IP:是可以連接互聯(lián)網(wǎng)的IP地址;內(nèi)網(wǎng)IP:也叫局域網(wǎng)IP,只能組織機(jī)構(gòu)內(nèi)部使用。
- 192.168.開頭的就是常見的局域網(wǎng)地址,范圍即為192.168.0.0–192.168.255.255,專門為組織機(jī)構(gòu)內(nèi)部使用。
特殊IP地址
127.0.0.1、localhost:代表本機(jī)IP,只會(huì)尋找當(dāng)前所在的主機(jī)。
IP常用命令:
ipconfig:查看本機(jī)IP地址。
ping IP地址:檢查網(wǎng)絡(luò)是否連通。
1.1 InetAddress
- 代表IP地址。
端口
- 標(biāo)記正在計(jì)算機(jī)設(shè)備上運(yùn)行的應(yīng)用程序的,被規(guī)定為一個(gè)16 位的二進(jìn)制,范圍是 0~65535
分類
- 周知端口:0~1023,被預(yù)先定義的知名應(yīng)用占用(如:HTTP占用 80,F(xiàn)TP占用21)
- 注冊(cè)端口:1024~49151,分配給用戶進(jìn)程或某些應(yīng)用程序。
- 動(dòng)態(tài)端口:49152到65535,之所以稱為動(dòng)態(tài)端口,是因?yàn)樗?一般不固定分配某種進(jìn)程,而是動(dòng)態(tài)分配。
- 注意:我們自己開發(fā)的程序一般選擇使用注冊(cè)端口,且一個(gè)設(shè)備中不能出現(xiàn)兩個(gè)程序的端口號(hào)一樣,否則出錯(cuò)。
通信協(xié)議
- 網(wǎng)絡(luò)上通信的設(shè)備,事先規(guī)定的連接規(guī)則,以及傳輸數(shù)據(jù)的規(guī)則被稱為網(wǎng)絡(luò)通信協(xié)議
開放式網(wǎng)絡(luò)互聯(lián)標(biāo)準(zhǔn):OSI網(wǎng)絡(luò)參考模型
- OSI網(wǎng)絡(luò)參考模型:全球網(wǎng)絡(luò)互聯(lián)標(biāo)準(zhǔn)。
- TCP/IP網(wǎng)絡(luò)模型:事實(shí)上的國(guó)際標(biāo)準(zhǔn)。
1.2 重要知識(shí)點(diǎn):傳輸層的2個(gè)通信協(xié)議
- UDP(User Datagram Protocol):用戶數(shù)據(jù)報(bào)協(xié)議;
- TCP(Transmission ControlProtocol):傳輸控制協(xié)議。
UDP協(xié)議
- 特點(diǎn):無(wú)連接、不可靠通信。
- 通訊效率高!語(yǔ)音通話 視頻直播
- 不事先建立連接,數(shù)據(jù)按照包發(fā),一包數(shù)據(jù)包含:自己的IP、程序端口,目的地IP、程序端口和數(shù)據(jù)(限制在64KB內(nèi))等。
- 發(fā)送方不管對(duì)方是否在線,數(shù)據(jù)在中間丟失也不管,如果接收方收到數(shù)據(jù)也不返回確認(rèn),故是不可靠的。
TCP協(xié)議
- 特點(diǎn):面向連接、可靠通信。
- 通信效率相對(duì)不高 網(wǎng)頁(yè) 文件下載 支付
- TCP的最終目的:要保證在不可靠的信道上實(shí)現(xiàn)可靠的傳輸。
- TCP主要有三個(gè)步驟實(shí)現(xiàn)可靠傳輸:三次握手建立連接,傳輸數(shù)據(jù)進(jìn)行確認(rèn),四次揮手?jǐn)嚅_連接。
- TCP協(xié)議:三次握手建立可靠連接
- 可靠連接:確定通信雙方,收發(fā)消息都是正常無(wú)問(wèn)題的!(全雙工)
- 傳輸數(shù)據(jù)會(huì)進(jìn)行確認(rèn),以保證數(shù)據(jù)傳輸?shù)目煽啃?img src="https://imgs.yssmx.com/Uploads/2024/04/850721-9.png" alt="Day19-【Java SE進(jìn)階】網(wǎng)絡(luò)編程,JAVA從入門到放棄,java,網(wǎng)絡(luò),php" referrerpolicy="no-referrer" />
- TCP協(xié)議:四次握手?jǐn)嚅_連接
- 目的:確保雙方數(shù)據(jù)的收發(fā)都已經(jīng)完成!
2. UDP通信-快速入門
UDP通信
- 特點(diǎn):無(wú)連接、不可靠通信。
- 不事先建立連接;發(fā)送端每次把要發(fā)送的數(shù)據(jù)(限制在64KB內(nèi))、接收端IP、等信息封裝成一個(gè)數(shù)據(jù)包,發(fā)出去就不管了。
- Java提供了一個(gè)java.net.DatagramSocket類來(lái)實(shí)現(xiàn)UDP通信。
import java.net.*;
public class Client {
public static void main(String[] args) throws Exception {
//1. 創(chuàng)建客戶端對(duì)象(發(fā)韭菜出去的人)
DatagramSocket socket = new DatagramSocket();
//2. 創(chuàng)建數(shù)據(jù)包對(duì)象封裝要發(fā)出去得數(shù)據(jù)(創(chuàng)建一個(gè)韭菜盒子)
/* public DatagramPacket(byte buf[], int length,InetAddress address,int port)
參數(shù)一:封裝要發(fā)出去的數(shù)據(jù)。
參數(shù)二:發(fā)送出去的數(shù)據(jù)大小(字節(jié)個(gè)數(shù))
參數(shù)三:服務(wù)端的IP地址(找到服務(wù)端主機(jī))
參數(shù)四:服務(wù)端程序的端口。
*/
byte[] bytes = "我是客戶端,向您發(fā)送數(shù)據(jù)!".getBytes();
DatagramPacket packet = new DatagramPacket(bytes,bytes.length,
InetAddress.getLocalHost(),6666);
//3. 開始正式發(fā)送這個(gè)數(shù)據(jù)包出去了
socket.send(packet);
System.out.println("客戶端數(shù)據(jù)發(fā)送完畢~~~");
socket.close();//釋放資源!
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws Exception {
//1. 創(chuàng)建一個(gè)服務(wù)端對(duì)象(創(chuàng)建一個(gè)接韭菜的人) 注冊(cè)端口
DatagramSocket socket = new DatagramSocket(6666);
//2. 創(chuàng)建一個(gè)數(shù)據(jù)包對(duì)象,用于接收數(shù)據(jù)的(創(chuàng)建一個(gè)韭菜盒子)
byte[] buf = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//3. 開始正式使用數(shù)據(jù)包來(lái)接收客戶端發(fā)來(lái)的數(shù)據(jù)
socket.receive(packet);
//4. 從字節(jié)數(shù)組中,把接收到的數(shù)據(jù)直接打印出來(lái)
// 接收多少就倒出多少 獲取本次數(shù)據(jù)包接收了多少數(shù)據(jù)
int len = packet.getLength();
String s = new String(buf, 0, len);
System.out.println(s);
String hostAddress = packet.getAddress().getHostAddress();
int port = packet.getPort();
System.out.println(hostAddress + ":" + port);
socket.close();//釋放資源
}
}
UDP通信 多發(fā)多收
edit configures->allow 多開 apply即可躲開client程序的
package com.jingwei;
import java.net.*;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception {
//1. 創(chuàng)建客戶端對(duì)象(發(fā)韭菜出去的人)
DatagramSocket socket = new DatagramSocket();//可以分配端口 或者不填寫自動(dòng)分配
//2. 創(chuàng)建數(shù)據(jù)包對(duì)象封裝要發(fā)出去得數(shù)據(jù)(創(chuàng)建一個(gè)韭菜盒子)
/* public DatagramPacket(byte buf[], int length,InetAddress address,int port)
參數(shù)一:封裝要發(fā)出去的數(shù)據(jù)。
參數(shù)二:發(fā)送出去的數(shù)據(jù)大小(字節(jié)個(gè)數(shù))
參數(shù)三:服務(wù)端的IP地址(找到服務(wù)端主機(jī))
參數(shù)四:服務(wù)端程序的端口。
*/
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("請(qǐng)說(shuō)");
String msg = sc.nextLine();
if("exit".equals(msg)) {
System.out.println("退出成功!");
socket.close();
break;
}
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes,bytes.length,
InetAddress.getLocalHost(),6666);
//3. 開始正式發(fā)送這個(gè)數(shù)據(jù)包出去了
socket.send(packet);
}
System.out.println("客戶端數(shù)據(jù)發(fā)送完畢~~~");
}
}
package com.jingwei;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws Exception {
//1. 創(chuàng)建一個(gè)服務(wù)端對(duì)象(創(chuàng)建一個(gè)接韭菜的人) 注冊(cè)端口
DatagramSocket socket = new DatagramSocket(6666);
//2. 創(chuàng)建一個(gè)數(shù)據(jù)包對(duì)象,用于接收數(shù)據(jù)的(創(chuàng)建一個(gè)韭菜盒子)
byte[] buf = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
//3. 開始正式使用數(shù)據(jù)包來(lái)接收客戶端發(fā)來(lái)的數(shù)據(jù)
socket.receive(packet);
//4. 從字節(jié)數(shù)組中,把接收到的數(shù)據(jù)直接打印出來(lái)
// 接收多少就倒出多少 獲取本次數(shù)據(jù)包接收了多少數(shù)據(jù)
int len = packet.getLength();
String s = new String(buf, 0, len);
System.out.println(s);
String hostAddress = packet.getAddress().getHostAddress();
int port = packet.getPort();
System.out.println(hostAddress + ":" + port);
System.out.println("-----------------------");
}
}
}
3. TCP通信
- 特點(diǎn):面向連接、可靠通信。
- 通信雙方事先會(huì)采用“三次握手”方式建立可靠連接,實(shí)現(xiàn)端到端的通信;底層能保證數(shù)據(jù)成功傳給服務(wù)端。
- Java提供了一個(gè)java.net.Socket類來(lái)實(shí)現(xiàn)TCP通信。
一發(fā)一收
package com.jingwei;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
public class SocketClient {
public static void main(String[] args) throws IOException {
System.out.println("服務(wù)端啟動(dòng)成功!");
//1. 創(chuàng)建ServerSocket的對(duì)象,同時(shí)為服務(wù)端注冊(cè)端口。
ServerSocket serverSocket = new ServerSocket(8888);
//2. 使用ServerSocket對(duì)象,調(diào)用accept方法,等待客戶端的連接請(qǐng)求。
Socket socket = serverSocket.accept();
//3. 從socket通信管道中得到一個(gè)字節(jié)輸入流
InputStream is = socket.getInputStream();
//4. 把原始的字節(jié)輸入流包裝成數(shù)據(jù)輸入流
DataInputStream dis = new DataInputStream(is);
//5. 使用數(shù)據(jù)輸入流讀取客戶端發(fā)送過(guò)來(lái)的消息
String s = dis.readUTF();
System.out.println(s);
//其實(shí)我們也可以獲取客戶端的IP地址
SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
System.out.println(remoteSocketAddress);
dis.close();
socket.close();
}
}
package com.jingwei;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) throws IOException {
//1. 創(chuàng)建Socket對(duì)象,并同時(shí)請(qǐng)求與服務(wù)器程序的連接。
Socket socket = new Socket("127.0.0.1", 8888);
//2. 從Socket通信管道中得到一個(gè)字節(jié)輸出流,用來(lái)發(fā)數(shù)據(jù)給服務(wù)端程序
OutputStream os = socket.getOutputStream();
//3. 把低級(jí)的字節(jié)輸出流包裝成數(shù)據(jù)輸出流
DataOutputStream dos = new DataOutputStream(os);
//4. 開始寫數(shù)據(jù)出去了
dos.writeUTF("在一起好嗎?");
dos.close();
socket.close();//釋放連接資源
}
}
多發(fā)多收
package com.jingwei;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class SocketServer {
public static void main(String[] args) throws IOException {
//1. 創(chuàng)建Socket對(duì)象,并同時(shí)請(qǐng)求與服務(wù)器程序的連接。
Socket socket = new Socket("127.0.0.1", 8888);
//2. 從Socket通信管道中得到一個(gè)字節(jié)輸出流,用來(lái)發(fā)數(shù)據(jù)給服務(wù)端程序
OutputStream os = socket.getOutputStream();
//3. 把低級(jí)的字節(jié)輸出流包裝成數(shù)據(jù)輸出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("請(qǐng)說(shuō):");
//4. 開始寫數(shù)據(jù)出去了
String msg = sc.nextLine();
if("exit".equals(msg)){
dos.close();
socket.close();
break;
}
dos.writeUTF(msg);
dos.flush();
}
// dos.close();
//
// socket.close();//釋放連接資源
}
}
package com.jingwei;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
public class SocketClient {
public static void main(String[] args) throws IOException {
System.out.println("服務(wù)端啟動(dòng)成功!");
//1. 創(chuàng)建ServerSocket的對(duì)象,同時(shí)為服務(wù)端注冊(cè)端口。
ServerSocket serverSocket = new ServerSocket(8888);
//2. 使用ServerSocket對(duì)象,調(diào)用accept方法,等待客戶端的連接請(qǐng)求。
Socket socket = serverSocket.accept();
//3. 從socket通信管道中得到一個(gè)字節(jié)輸入流
InputStream is = socket.getInputStream();
//4. 把原始的字節(jié)輸入流包裝成數(shù)據(jù)輸入流
DataInputStream dis = new DataInputStream(is);
while (true) {
//5. 使用數(shù)據(jù)輸入流讀取客戶端發(fā)送過(guò)來(lái)的消息
try {
String s = dis.readUTF();
System.out.println(s);
//其實(shí)我們也可以獲取客戶端的IP地址
SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
System.out.println(remoteSocketAddress);
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress()+"離線了!");
dis.close();
socket.close();
break;
}
}
// dis.close();
// socket.close();
}
}
目前我們開發(fā)的服務(wù)端程序,是否可以支持與多個(gè)客戶端同時(shí)通信?
- 不可以的。
- 因?yàn)榉?wù)端現(xiàn)在只有一個(gè)主線程,只能處理一個(gè)客戶端的消息,
package com.jingwei;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class SocketServer {
public static void main(String[] args) throws IOException {
//1. 創(chuàng)建Socket對(duì)象,并同時(shí)請(qǐng)求與服務(wù)器程序的連接。
Socket socket = new Socket("127.0.0.1", 8888);
//2. 從Socket通信管道中得到一個(gè)字節(jié)輸出流,用來(lái)發(fā)數(shù)據(jù)給服務(wù)端程序
OutputStream os = socket.getOutputStream();
//3. 把低級(jí)的字節(jié)輸出流包裝成數(shù)據(jù)輸出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("請(qǐng)說(shuō):");
//4. 開始寫數(shù)據(jù)出去了
String msg = sc.nextLine();
if("exit".equals(msg)){
dos.close();
socket.close();
break;
}
dos.writeUTF(msg);
dos.flush();
}
// dos.close();
//
// socket.close();//釋放連接資源
}
}
package com.jingwei;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketClient {
public static void main(String[] args) throws IOException {
System.out.println("服務(wù)端啟動(dòng)成功!");
//1. 創(chuàng)建ServerSocket的對(duì)象,同時(shí)為服務(wù)端注冊(cè)端口。
ServerSocket serverSocket = new ServerSocket(8888);
//2. 使用ServerSocket對(duì)象,調(diào)用accept方法,等待客戶端的連接請(qǐng)求。
while (true) {
Socket socket = serverSocket.accept();
System.out.println("有人上線了"+socket.getRemoteSocketAddress());
new ServerReaderThread(socket).start();
}
// dis.close();
// socket.close();
}
}
package com.jingwei;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
while (true){
try {
String msg = dataInputStream.readUTF();
System.out.println(msg);
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress()+"下線了");
dataInputStream.close();
socket.close();
break;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
TCP通信-綜合案例
- 即時(shí)通信-群聊
- 實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的BS架構(gòu)
題目:要求從瀏覽器中訪問(wèn)服務(wù)器
并立即讓服務(wù)器響應(yīng)一個(gè)很簡(jiǎn)單的網(wǎng)頁(yè)給瀏覽器展示
網(wǎng)頁(yè)內(nèi)容就是“我666”
注意:服務(wù)器必須給瀏覽器響應(yīng)HTTP協(xié)議規(guī)定的數(shù)據(jù)格式,否則瀏覽器不識(shí)別返回的數(shù)據(jù)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-850721.html
package com.jingwei;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketClient {
public static void main(String[] args) throws IOException {
System.out.println("服務(wù)端啟動(dòng)成功!");
//1. 創(chuàng)建ServerSocket的對(duì)象,同時(shí)為服務(wù)端注冊(cè)端口。
ServerSocket serverSocket = new ServerSocket(8888);
//2. 使用ServerSocket對(duì)象,調(diào)用accept方法,等待客戶端的連接請(qǐng)求。
while (true) {
Socket socket = serverSocket.accept();
System.out.println("有人上線了"+socket.getRemoteSocketAddress());
// new ServerReaderThread(socket).start();
new ServerWriterThread(socket).start();
}
// dis.close();
// socket.close();
}
}
package com.jingwei;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ServerWriterThread extends Thread {
private Socket socket;
public ServerWriterThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.println("Http/1.1 200 OK");
printStream.println("Content-Type: text/html;charset=utf-8");
printStream.println();
printStream.println("<!DOCTYPE html>");
printStream.println("<html>");
printStream.println("<head>");
printStream.println("<title>Server Writer</title>");
printStream.println("</head>");
printStream.println("<body>");
printStream.println("<h1>Server Writer</h1>");
printStream.println("</body>");
printStream.println("</html>");
printStream.flush();
printStream.close();
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
拓展知識(shí)
每次請(qǐng)求都開一個(gè)新線程,到底好不好?
高并發(fā)時(shí),容易宕機(jī)!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-850721.html
package com.day19;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class SocketClient {
public static void main(String[] args) throws IOException {
System.out.println("服務(wù)端啟動(dòng)成功!");
//1. 創(chuàng)建ServerSocket的對(duì)象,同時(shí)為服務(wù)端注冊(cè)端口。
ServerSocket serverSocket = new ServerSocket(8888);
//創(chuàng)建出一個(gè)線程池,負(fù)責(zé)處理通信管道的任務(wù)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(20 * 2, 20 * 2, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(8), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
//2. 使用ServerSocket對(duì)象,調(diào)用accept方法,等待客戶端的連接請(qǐng)求。
while (true) {
Socket socket = serverSocket.accept();
System.out.println("有人上線了"+socket.getRemoteSocketAddress());
// new ServerReaderThread(socket).start();
//3、把這個(gè)客戶端對(duì)應(yīng)的socket通信管道,交給一個(gè)獨(dú)立的線程負(fù)責(zé)處理。
threadPoolExecutor.execute(new ServerWriterRunnable(socket));
}
// dis.close();
// socket.close();
}
}
package com.day19;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ServerWriterRunnable implements Runnable {
private Socket socket;
public ServerWriterRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.println("Http/1.1 200 OK");
printStream.println("Content-Type: text/html;charset=utf-8");
printStream.println();
printStream.println("<!DOCTYPE html>");
printStream.println("<html>");
printStream.println("<head>");
printStream.println("<title>Server Writer</title>");
printStream.println("</head>");
printStream.println("<body>");
printStream.println("<h1>Server Writer</h1>");
printStream.println("</body>");
printStream.println("</html>");
printStream.flush();
printStream.close();
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
到了這里,關(guān)于Day19-【Java SE進(jìn)階】網(wǎng)絡(luò)編程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!