Android基礎(chǔ)(18)網(wǎng)絡(luò)總結(jié)

常見(jiàn)問(wèn)題:
1)描述一次網(wǎng)絡(luò)請(qǐng)求的流程
2)HttpUrlConnection 和 okHttp 關(guān)系 (4.4 以后 HttpUrlConnection內(nèi)部采用 okHttp)
3)Android代碼中實(shí)現(xiàn)WAP方式聯(lián)網(wǎng)
https://blog.csdn.net/asce1885/article/details/7844159

4)服務(wù)器只提供數(shù)據(jù)接收接口,在多線(xiàn)程或多進(jìn)程條件下,如何保證數(shù)據(jù)的有序到達(dá)?
5)網(wǎng)絡(luò)框架對(duì)比和源碼分析。
6)Https請(qǐng)求慢的解決辦法
現(xiàn)在下載速度很慢,試從網(wǎng)絡(luò)協(xié)議的角度分析原因,并優(yōu)化(提示:網(wǎng)絡(luò)的5層都可以涉及)。
7)自己去設(shè)計(jì)網(wǎng)絡(luò)請(qǐng)求框架,怎么做?
8)okHttp源碼。網(wǎng)絡(luò)請(qǐng)求緩存處理,okHttp如何處理網(wǎng)絡(luò)緩存的。CacheInterceptor

一. UDP和TCP簡(jiǎn)介

1.1 UDP的特點(diǎn)

  • 面向非連接
  • 不維護(hù)連接狀態(tài),支持同時(shí)向多個(gè)客戶(hù)端傳輸相同的消息
  • 數(shù)據(jù)包報(bào)頭只有8個(gè)字節(jié),額外開(kāi)銷(xiāo)較小
  • 吞吐量只受限于數(shù)據(jù)生成速率、傳輸速率以及機(jī)器性能
  • 盡最大努力交付,不保證可靠交付,不需要維持復(fù)雜的鏈接狀態(tài)表
  • 面向報(bào)文,不對(duì)應(yīng)用程序提交的報(bào)文信息進(jìn)行拆分或者合并

1.2 TCP和UDP的區(qū)別

  • 面向連接 vs 無(wú)連接
  • 可靠性
  • 有序性
  • 速度
  • 量級(jí)

1.3 TCP的滑動(dòng)窗口
調(diào)整讀寫(xiě)緩沖區(qū)的大小。
過(guò)程動(dòng)畫(huà)展示:
https://v.youku.com/v_show/id_XNDg1NDUyMDUy.html

TCP使用滑動(dòng)窗口做流量控制與亂序重排

  • 保證TCP的可靠性
  • 保證TCP的流量控制特性
    連接兩端各有發(fā)送窗口與接收窗口。


窗口數(shù)據(jù)的計(jì)算過(guò)程
接收端大小:AdvertisedWindow = MaxRcvBuffer - (LastByteRcvd - LaskByteRead)
客戶(hù)端發(fā)送大小為:LastByteSent - LastByteAcked
有效窗口大?。篍ffectiveWindow =  AdvertisedWindow - (LastByteSent - LastByteAcked)

二. TCP 三次握手與四次揮手
2.1 TCP Flags解讀

URG:緊急指針標(biāo)志
ACK:確認(rèn)序號(hào)標(biāo)志
SYN:同步序號(hào),用于建立連接過(guò)程
PSH:push標(biāo)志
RST:重置連接標(biāo)志
FIN:finish標(biāo)志,用于釋放連接

2.2 三次握手

第一次,client 端發(fā)送SYN包到服務(wù)器并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn)。SYN = 1, seq = x。

第二次是服務(wù)器收到SYN包,必須確認(rèn)客戶(hù)端的SYN(ack = x+1),同時(shí)自己也發(fā)送一個(gè)SYN包,即SYN+ACK包,服務(wù)器進(jìn)入SYN_RECV狀態(tài)。server端, SYN =1, ACK=1, seq=y, ack =x + 1

第三次是client端, 客戶(hù)端收到ACK+SYN包,想服務(wù)器發(fā)送確認(rèn)包ACK。ACK=1, seq=x+1, ack=y+1。 客戶(hù)端和服務(wù)器端進(jìn)入ESTABLISHED 狀態(tài),完成三次握手。

為什么需要三次握手才能建立起連接呢?
答:為了初始化 Sequence Number 的初始值。

首次握手的隱患——SYN超時(shí)

  • Server收到Client的SYN,回復(fù)SYN-ACK的時(shí)候未收到ACK確認(rèn)
  • Server不斷重試直至超時(shí),Linux默認(rèn)等待63秒才斷開(kāi)連接
    針對(duì)SYN Flood的防護(hù)措施
  • SYN隊(duì)列滿(mǎn)后,通過(guò)tcp_syncookies參數(shù)回發(fā)SYN Cookie
  • 若為正常連接則Client會(huì)回發(fā)SYN Cookie,直接建立連接

建立連接后,Client出現(xiàn)故障怎么辦
保活機(jī)制

  • 向?qū)Ψ桨l(fā)送?;钐綔y(cè)報(bào)文,如果未收到響應(yīng)則繼續(xù)發(fā)送
  • 嘗試次數(shù)達(dá)到保活探測(cè)數(shù)仍未收到響應(yīng)則中斷連接
2.3 TCP的四次揮手

TCP連接必須經(jīng)過(guò)事件 2MSL 后才真正釋放掉。
“揮手”是為了終止連接。
第一次揮手:Client發(fā)送一個(gè)FIN,用來(lái)關(guān)閉Client 到Server的數(shù)據(jù)傳送,Client進(jìn)入 FIN_WAIT_1狀態(tài)。
第二次揮手:Server收到FIN后,發(fā)送一個(gè)ACK給Client,確認(rèn)序號(hào)為收到序號(hào)+1(與SYN相同,一個(gè)FIN占用一個(gè)序號(hào)),Server進(jìn)入 CLOSE_WAIT狀態(tài);Client進(jìn)入 FIN_WAIT_2。
第三次揮手:Server發(fā)送一個(gè)FIN,用來(lái)關(guān)閉Server到Client的數(shù)據(jù)傳送,Server進(jìn)入 LAST_ACK狀態(tài);
第四次揮手:Client 收到FIN后,Client 進(jìn)入 TIME_WAIT 狀態(tài),接著發(fā)送一個(gè) ACK 給 Server,確認(rèn)序號(hào)為收到序號(hào)+1,Server進(jìn)入CLOSED狀態(tài),完成四次揮手。

為什么會(huì)有TIME_WAIT狀態(tài)?

  • 確保有足夠的事件讓對(duì)方收到ACK包
  • 避免新舊連接混淆

為什么需要四次握手才能斷開(kāi)連接?
因?yàn)槿p工,發(fā)送方和接收方都需要FIN報(bào)文和ACK報(bào)文。

服務(wù)器出現(xiàn)大量CLOSE_WAIT狀態(tài)的原因
對(duì)方關(guān)閉socket連接,我方忙于讀或?qū)懀瑳](méi)有及時(shí)關(guān)閉連接

  • 檢查代碼,特別是釋放資源的代碼
  • 檢查配置,特別是處理請(qǐng)求的線(xiàn)程配置
三. 一次網(wǎng)絡(luò)請(qǐng)求的過(guò)程

我們來(lái)表述一個(gè)瀏覽器發(fā)出HTTP請(qǐng)求的過(guò)程:
首先,我們?cè)跒g覽器輸入了URL(例 :www.baidu.com),按下回車(chē),開(kāi)始我們的HTTP請(qǐng)求

3.1 通過(guò)URL找IP

首先我們的瀏覽器是不認(rèn)識(shí)baidu.com這個(gè)域名的,(注意:是baidu.com,不是www.baidu.com。 因?yàn)閣ww是服務(wù)器的名字,而baidu.com是域名,相當(dāng)于這個(gè)服務(wù)器的地址,com是公司的意義,baidu是公司名,www是公司的一個(gè)服務(wù)器名稱(chēng)),要將這個(gè)服務(wù)器的IP地址找到。

如何去找IP地址呢,首先先是本地的緩存,一般是以Hosts文件的形式存在,維持著一個(gè)帶域名的服務(wù)器地址對(duì)IP的對(duì)應(yīng)關(guān)系,路由器緩存(也算是DNS服務(wù)器緩存)

如果沒(méi)有結(jié)果,則會(huì)向上層DNS服務(wù)器詢(xún)問(wèn),上層DNS服務(wù)器的本地緩存中如果沒(méi)有該記錄,則再向上層詢(xún)問(wèn),一直到DNS根服務(wù)器。

在根域名服務(wù)器中雖然沒(méi)有每個(gè)域名的具體信息,但儲(chǔ)存了負(fù)責(zé)每個(gè)域(如COM、NET、ORG等)的解析的域名服務(wù)器的地址信息。根域名服務(wù)器會(huì)將其管轄范圍內(nèi)頂級(jí)域名(如.com)服務(wù)器IP告訴本地DNS服務(wù)器,這樣你的域名查詢(xún)請(qǐng)求會(huì)進(jìn)入到相應(yīng)的頂級(jí)域名服務(wù)器。頂級(jí)域名服務(wù)器收到請(qǐng)求后查看區(qū)域文件記錄,若找到則將其管轄范圍內(nèi)主域名(不帶任何前綴的域名,如 baidu.com)服務(wù)器的IP地址告訴本地DNS服務(wù)器。如果還是沒(méi)有找到,則進(jìn)入到下一級(jí)域名服務(wù)器進(jìn)行查找。如此重復(fù),直到找到正確的結(jié)果為止,返回 IP地址結(jié)果給本地DNS服務(wù)器。

本地DNS服務(wù)器緩存結(jié)果,設(shè)置(Time-To-Live)即一條域名解析記錄在DNS服務(wù)器上緩存時(shí)間,關(guān)于TTL如果IP經(jīng)常改變,那么TTL設(shè)的短一點(diǎn)長(zhǎng)一點(diǎn)都沒(méi)有太大的 影響,而如果IP經(jīng)常不變,可以把TTL時(shí)間拉長(zhǎng),這樣有利于提高命中率。

3.2 對(duì)IP結(jié)果建立TCP連接

自己主機(jī)IP端口的對(duì)目標(biāo)IP的端口(例:http://www.baidu.com http協(xié)議所占用的TCP端口為80端口)三次握手建立TCP連接。

3.3 向服務(wù)器發(fā)送數(shù)據(jù)

瀏覽器將網(wǎng)絡(luò)請(qǐng)求封裝成HTTP報(bào)文,把HTTP報(bào)文通過(guò)TCP的分包,分成一個(gè)個(gè)TCP數(shù)據(jù)包。
IP層把上層傳輸層數(shù)據(jù)包打包成IP層數(shù)據(jù)包,并把該數(shù)據(jù)包發(fā)送到更低層數(shù)據(jù)鏈路層,相反,IP層也把從低層接收來(lái)的數(shù)據(jù)包傳送到更高層TCP或UDP層。(補(bǔ):IP數(shù)據(jù)包是不可靠的,因?yàn)镮P并沒(méi)有做任何事情來(lái)確認(rèn)數(shù)據(jù)包是否按順序發(fā)送的或者有沒(méi)有被破壞,IP數(shù)據(jù)包中含有發(fā)送它的主機(jī)的地址(源地址)和接收它的主機(jī)的地址(目的地址))

通過(guò)這套封裝包過(guò)程,發(fā)送到服務(wù)器端,服務(wù)器端則是一個(gè)拆包的過(guò)程,IP層是不可靠的,所以沒(méi)有確認(rèn)的機(jī)制,而在上層的TCP層則會(huì)對(duì)數(shù)據(jù)包的可靠性進(jìn)行驗(yàn)證,丟失則會(huì)重傳數(shù)據(jù)。保證傳輸?shù)目煽啃?。服?wù)器最終解包會(huì)拼接成一個(gè)完整的HTTP報(bào)文,完成整個(gè)數(shù)據(jù)的發(fā)送。

3.4 服務(wù)器解析,并返回

對(duì)HTTP報(bào)文進(jìn)行解析,根據(jù)HTTP報(bào)文決定它請(qǐng)求了什么。將處理的結(jié)果組裝成響應(yīng)報(bào)文(如www.baidu.com , 請(qǐng)求報(bào)文為GET,要獲取的是缺省值默認(rèn)的index.html這個(gè)主頁(yè),則返回網(wǎng)頁(yè)的源碼,將網(wǎng)頁(yè)源碼添加到響應(yīng)報(bào)文正文中),其中比較關(guān)鍵的是狀態(tài)碼(200OK表示成功沒(méi)毛?。?,然后將響應(yīng)報(bào)文,通過(guò)之前的過(guò)程返還給咱們的主機(jī)IP。

3.5 總結(jié)過(guò)程
  • DNS解析
  • TCP連接
  • 發(fā)送HTTP請(qǐng)求
  • 服務(wù)器處理請(qǐng)求并返回HTTP報(bào)文
  • 瀏覽器解析渲染頁(yè)面
  • 連接結(jié)束
四. HTTP

4.1 簡(jiǎn)介

  • 支持客戶(hù)/服務(wù)器模式
  • 簡(jiǎn)單快速
  • 靈活
  • 無(wú)連接
  • 無(wú)狀態(tài)

4.2 請(qǐng)求和響應(yīng)報(bào)文

HTTP請(qǐng)求結(jié)構(gòu)

HTTP響應(yīng)結(jié)構(gòu)

4.3 請(qǐng)求/響應(yīng)的步驟

  • 客戶(hù)端連接到Web服務(wù)器
  • 發(fā)送HTTP請(qǐng)求
  • 服務(wù)器端接收請(qǐng)求并返回HTTP響應(yīng)
  • 釋放TCP連接
  • 客戶(hù)端瀏覽器解析HTML內(nèi)容

4.4 HTTP狀態(tài)碼

  • 1xx:指示消息——表示請(qǐng)求已接收,繼續(xù)處理
  • 2xx:成功——表示請(qǐng)求已被成功接收、理解、接收
  • 3xx:重定向——要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作
  • 4xx:客戶(hù)端錯(cuò)誤——請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)
  • 5xx:服務(wù)器端錯(cuò)誤——服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求

4.5 GET和POST區(qū)別

  • HTTP報(bào)文層面:GET將請(qǐng)求信息放在URL,POST放在報(bào)文體中
  • 數(shù)據(jù)庫(kù)層面:GET符合冪等性和安全性,POST不符合
  • 其他層面:GET可以被緩存、被存儲(chǔ),而POST不行

4.6 Cookie和Session的區(qū)別
Cookie的設(shè)置以及發(fā)送過(guò)程
Web Client 1)HTTP Request 向 Web Server
2)HTTP Response + Set-Cookie 回
3)HTTP Request + Cookie 向
4)HTTP Response 回
Session簡(jiǎn)介

  • 服務(wù)器端的機(jī)制,在服務(wù)器上保存的信息
  • 解析客戶(hù)端請(qǐng)求并操作session id,按需保存狀態(tài)信息
    可是使用Cookie實(shí)現(xiàn)。

Cookie和Session 的區(qū)別

  • Cookie數(shù)據(jù)存放在客戶(hù)的瀏覽器上,Session數(shù)據(jù)放在服務(wù)器上
  • Session相對(duì)于Cookie更安全
  • 若考慮減輕服務(wù)器負(fù)擔(dān),應(yīng)當(dāng)使用Cookie
五. Android常見(jiàn)網(wǎng)絡(luò)框架對(duì)比
六. Https請(qǐng)求慢的解決辦法

DNS,攜帶數(shù)據(jù),直接訪問(wèn)IP

七. HTTP和HTTPS

HTTP、TCP、IP
HTTP、SSL/TLS、TCP、IP 后者比前者多了一層即 SSL/TLS
加密方式

  • 對(duì)稱(chēng)加密:加密和解密用的是同一個(gè)密鑰
  • 非對(duì)稱(chēng)加密:加密使用的密鑰和解密使用的密鑰是不相同的
  • 哈希算法:將任意長(zhǎng)度的信息轉(zhuǎn)換為固定長(zhǎng)度的值,算法不可逆
  • 數(shù)字簽名:證明某個(gè)消息或者文件是某人發(fā)出/認(rèn)同的

區(qū)別

  • HTTPS需要到CA申請(qǐng)證書(shū),HTTP不需要
  • HTTPS密文傳輸,HTTP明文傳輸
  • 連接方式不同,HTTPS默認(rèn)使用443端口,HTTP使用80端口
  • HTTPS=HTTP+加密+認(rèn)證+完整性保護(hù),較HTTP安全

SSL(Security Sockets Layer,安全套接層)

  • 為網(wǎng)絡(luò)通信提供安全及數(shù)據(jù)完整性的一種安全協(xié)議
  • 是操作系統(tǒng)對(duì)外的API,SSL3.0后更名為T(mén)LS
  • 采用身份認(rèn)證和數(shù)據(jù)加密保證網(wǎng)絡(luò)通信的安全和數(shù)據(jù)的完整性

HTTPS數(shù)據(jù)傳輸流程

  • 瀏覽器將支持的加密算法信息發(fā)送給服務(wù)器
  • 服務(wù)器選擇一套瀏覽器支持的加密算法,以證書(shū)的形式回發(fā)瀏覽器
  • 瀏覽器驗(yàn)證證書(shū)的合法性,并結(jié)合證書(shū)公鑰加密信息發(fā)送給服務(wù)器
  • 服務(wù)器使用私鑰解密信息,驗(yàn)證哈希,加密響應(yīng)信息回發(fā)瀏覽器
  • 瀏覽器解密響應(yīng)信息,并對(duì)消息進(jìn)行驗(yàn)證,之后進(jìn)行加密交互數(shù)據(jù)

HTTPS夠安全嗎?

瀏覽器默認(rèn)填充htpp://,請(qǐng)求需要進(jìn)行跳轉(zhuǎn),有被劫持的風(fēng)險(xiǎn)
可以使用HSTS(HTTP Strict Transport Security)優(yōu)化

八. Socket

Socket是對(duì)TCP/IP 協(xié)議的抽象,是操作系統(tǒng)對(duì)外開(kāi)放的接口


8.1 Socket通信流程
8.2 UDP Demo

UDP Server

public class UDPServer {
    public static void main(String[] args) throws Exception {
        // 服務(wù)端接受客戶(hù)端發(fā)送的數(shù)據(jù)報(bào)
        DatagramSocket socket = new DatagramSocket(65001); // 監(jiān)聽(tīng)的端口號(hào)
        byte[] buff = new byte[100];// 存儲(chǔ)從客戶(hù)端接收到的內(nèi)容
        DatagramPacket packet = new DatagramPacket(buff, buff.length);
        //接收客戶(hù)端發(fā)送來(lái)的內(nèi)容,并將內(nèi)容封裝進(jìn)DatagramPacket對(duì)象中
        socket.receive(packet);

        byte[] data = packet.getData(); // 從DatagramPacket對(duì)象中獲取到真正存儲(chǔ)的數(shù)據(jù)
        // 將數(shù)據(jù)從二進(jìn)制轉(zhuǎn)換成字符串形式
        String content = new String(data, 0, packet.getLength());
        System.out.println(content);
        // 將要發(fā)送給庫(kù)護(hù)短的數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制
        byte[] sendedContent = String.valueOf(content.length()).getBytes();
        // 服務(wù)端給客戶(hù)端發(fā)送數(shù)據(jù)報(bào)
        // 從DatagramPacket兌現(xiàn)中獲取到數(shù)據(jù)的來(lái)源地址與端口號(hào)
        DatagramPacket packetToClient = new DatagramPacket(sendedContent, sendedContent.length, packet.getAddress(), packet.getPort());
        socket.send(packetToClient); // 發(fā)送數(shù)據(jù)給客戶(hù)端
    }
}

UDPClient

public class UDPClient {
    public static void main(String[] args) throws Exception {
        // 客戶(hù)端發(fā)數(shù)據(jù)報(bào)給服務(wù)端
        DatagramSocket socket = new DatagramSocket();
        // 要發(fā)送給服務(wù)端的數(shù)據(jù)
        byte[] buf = "Hellow world".getBytes();
        // 將IP地址封裝成InetAddress對(duì)象
        InetAddress address = InetAddress.getByName("127.0.0.1");
        // 將要發(fā)送給服務(wù)端的數(shù)據(jù)封裝成DatagramPacket對(duì)象 需要天蝎上ip地址與端口號(hào)
        DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 65001);
        // 發(fā)送數(shù)據(jù)給服務(wù)端
        socket.send(packet);

        // 客戶(hù)端接收服務(wù)端發(fā)送過(guò)來(lái)的數(shù)據(jù)
        byte[] data = new byte[100];
        // 創(chuàng)建DatagramPacket對(duì)象用來(lái)存儲(chǔ)服務(wù)端發(fā)送過(guò)來(lái)的數(shù)據(jù)
        DatagramPacket receivedPacket = new DatagramPacket(data, data.length);
        // 將接收到的數(shù)據(jù)存儲(chǔ)到DatagramPacket對(duì)象中
        socket.receive(receivedPacket);
        // 將服務(wù)器發(fā)送過(guò)來(lái)的數(shù)據(jù)取出來(lái)并打印到控制臺(tái)
        String content = new String(receivedPacket.getData(), 0, receivedPacket.getLength());
        System.out.println(content);
    }
}
8.3 TCP Demo

TCP server

public class TCPServer {
    public static void main(String[] args) throws Exception {
        // 創(chuàng)建Socket,并將socket綁定到65000端口
        ServerSocket ss = new ServerSocket(65000);
        // 死循環(huán),使得socket一直等待并處理客戶(hù)端發(fā)送過(guò)來(lái)的請(qǐng)求
        while (true) {
            // 監(jiān)聽(tīng)65000端口,直到客戶(hù)端返回連接信息后才返回
            Socket socket = ss.accept();
            // 獲取客戶(hù)端的請(qǐng)求信息后,執(zhí)行相關(guān)業(yè)務(wù)邏輯
            new LengthCalculator(socket).start();
        }
    }
}
public class LengthCalculator extends Thread {

    private Socket socket;

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

    @Override
    public void run() {
        try {
            // 獲取socket的輸出流
            OutputStream os = socket.getOutputStream();
            // 獲取socket的輸入流
            InputStream is = socket.getInputStream();
            int ch = 0;
            byte[] buff = new byte[1024];
            // buff主要用來(lái)讀取輸入的內(nèi)容,存成byte數(shù)組,ch主要用來(lái)獲取讀取數(shù)組的額大小
            ch = is.read(buff);
            // 將接收流的byte數(shù)組轉(zhuǎn)換成字符串,這里獲取的內(nèi)容是客戶(hù)端發(fā)送過(guò)來(lái)的字符
            String content = new String(buff, 0, ch);
            System.out.println(content);

            // 往輸出流里寫(xiě)入獲得的字符串的長(zhǎng)度,回發(fā)給客戶(hù)端
            os.write(String.valueOf(content.length()).getBytes());
            // 不要忘記關(guān)閉輸入輸出流以及socket
            is.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


TCP client

public class TCPClient {
    public static void main(String[] args) throws Exception {
        // 創(chuàng)建Socket,并指定連接的是本機(jī)的端口號(hào)65000的服務(wù)端socket
        Socket socket = new Socket("127.0.0.1", 65000);
        // 獲取輸出流
        OutputStream os = socket.getOutputStream();
        // 獲取輸入流
        InputStream is = socket.getInputStream();
        // 將要傳遞給server的字符串參數(shù)轉(zhuǎn)換成byte數(shù)組,并數(shù)組寫(xiě)入到輸出流中
        os.write(new String("helloworld").getBytes());
        int ch = 0;
        byte[] buff = new byte[1024];
        // buff主要用來(lái)讀取輸入的內(nèi)容,存成byte數(shù)組,ch主要用來(lái)獲取讀取數(shù)組的長(zhǎng)度
        ch = is.read(buff);
        // 將接收流的byte數(shù)組轉(zhuǎn)換成字符串,這里是從服務(wù)端回發(fā)回來(lái)的字符串參數(shù)的長(zhǎng)度
        String content = new String(buff, 0, ch);
        System.out.println(content);
        // 不要忘記關(guān)閉輸入輸出流以及socket
        is.close();
        os.close();
        socket.close();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容