P2P中NAT穿越方案(UDP/TCP)(轉)

轉自:P2P中NAT穿越方案(UDP/TCP)_udp反向鏈接-CSDN博客

同:P2P中NAT穿越方案(UDP/TCP) - 知乎 (zhihu.com)

本文介紹了傳統基于udp的打洞方式,更進一步闡述了tcp打洞的原理,是對于打洞原理最完善的講解。

————————————
?

1、P2P簡介

對等網絡,即對等計算機網絡,是一種在對等者(Peer)之間分配任務和工作負載的分布式應用架構,是對等計算模型在應用層形成的一種組網或網絡形式。因此,從字面上,P2P可以理解為對等計算或對等網絡。

在P2P網絡環境中,彼此連接的多臺計算機之間都處于對等的地位,各臺計算機有相同的功能,無主從之分,一臺計算機既可作為服務器,設定共享資源供網絡中其他計算機所使用,又可以作為工作站,整個網絡一般來說不依賴專用的集中服務器,也沒有專用的工作站。網絡中的每一臺計算機既能充當網絡服務的請求者,又對其它計算機的請求做出響應,提供資源、服務和內容。通常這些資源和服務包括:信息的共享和交換、計算資源(如CPU計算能力共享)、存儲共享(如緩存和磁盤空間的使用)、網絡共享、打印機共享等。P2P網絡具有分散性、可擴展性、健壯性等特點,這使得P2P技術在信息共享、實時通信、協同工作、分布式計算、網絡存儲等領域都有廣闊的應用。

2、NAT簡介

NAT技術是一種把內部網絡(簡稱為內網)私有IP地址轉換為外部網絡(簡稱為外網)公共IP地址的技術,它使得一定范圍內的多臺主機只利用一個公共IP地址連接到外網,可以在很大程度上緩解了公網IP地址緊缺的問題。

3、NAT對P2P通信的影響

NAT技術雖然在一定程度上解決了IPv4地址短缺的問題,在構建防火墻、保證網絡安全方面都發揮了一定的作用,卻破壞了端到端的網絡通信。NAT阻礙主機進行P2P通信的主要原因是NAT不允許外網主機主動訪問內網主機,因為NAT設備上沒有相關轉發表項,要在NAT網絡環境中進行有效的P2P通信,就必須尋找相應的解決方案。本文就著重介紹幾種常見的解決方案。

4、P2P穿越NAT的方案

4.1 反向鏈接技術

當通信的雙方中只有一方位于NAT之后時,它們可以利用反向鏈接技術來進行P2P通信。圖3中Client A(擁有內網IP地址10.0.0.1)位于NAT之后,它通過TCP端口1234連接到服務器(擁有外網IP地址)的TCP端口1235上,NAT設備(擁有外網IP地址155.99.25.11)為這個連接重新分配了TCP端口62000。Client B(擁有外網IP地址138.76.29.7)也通過TCP端口1234連接到服務器端口1235上。Client A和Client B從服務器處獲知的對方的外網地址二元組{IP地址:端口號}分別為{138.76.29.7:1234}和{155.99.25.11:62000},它們在各自的本地端口上進行偵聽。

由于Client B 擁有外網IP地址,所以Client A要發起與Client B的通信,那么它可以直接通過TCP連接到Client B。但如果Client B嘗試通過TCP連接到Client A進行P2P通信,則會失敗,原因是Client A位于NAT設備后,雖然Client B發出的TCP SYN請求能夠到達NAT設備的端口62000,但NAT設備會拒絕這個連接請求。要想與Client A通信,Client B要通過服務器給Client A轉發一個連接請求,反過來請求Client A連接到Client B(即進行反向鏈接),從而建立起它們之間的TCP連接。

4.2 UDP打洞技術

如果兩個P2P客戶端都位于NAT設備后面,想要進行P2P通信,那又該如何解決呢?UDP打洞技術就是為解決這個問題而應運而生的,它能夠通過中間服務器實現P2P客戶端互連。

4.2.1 集中服務器

打洞技術假定客戶端A和客戶端B都可以與公網內的已知集中服務器建立UDP連接,一個客戶端在集中服務器上登陸的時候,服務器記錄下該客戶端的兩對地址二元組信息{IP地址:UDP端口},一對是該客戶端與集中服務器進行通信的自身的IP地址和端口號,另一對是集中服務器記錄下的由服務器“觀察”到的該客戶端實際與自己通信所使用的IP地址和端口號。我們可以把前一對地址二元組看作是客戶端的內網IP地址和端口號,把后一對地址二元組看作是客戶端的內網IP地址和端口號經過NAT轉換后的外網IP地址和端口號。集中服務器可以從客戶端的登陸消息中得到該客戶端的內網相關信息,還可以通過登陸消息的IP頭和UDP頭得到該客戶端的外網相關信息。如果該客戶端不是位于NAT設備后面,那么采用上述方法得到的兩對地址二元組信息是完全相同的。

4.2.2 建立P2P的SESSION

假定客戶端A要發起對客戶端B的直接連接,具體的“打洞”過程如下:

(1)客戶端A最初不知道如何向客戶端B發起連接,于是客戶端A向集中服務器發送消息,請求集中服務器幫助建立與客戶端B的UDP連接。

(2)集中服務器將含有客戶端B的外網和內網的地址二元組發給客戶端A,同時,集中服務器將包含有客戶端A的外網和內網的地址二元組信息的消息也發給客戶端B。這樣一來,客戶端A與客戶端B就都知道對方外網和內網的地址二元組信息了。

(3)當客戶端A收到由集中服務器發來的包含客戶端B的外網和內網的地址二元組信息后,客戶端A開始向客戶端B的地址二元組發送UDP數據包,并且客戶端A會自動鎖定第一個給出響應的客戶端B的地址二元組。同理,當客戶端B收到由集中服務器發來的客戶端A的外網和內網地址二元組信息后,也會開始向客戶端A的外網和內網的地址二元組發送UDP數據包,并且自動鎖定第一個得到客戶端A回應的地址二元組。由于客戶端A與客戶端B互相向對方發送UDP數據包的操作是異步的,所以客戶端A和客戶端B發送數據包的時間先后并沒有時序要求。

下面來看下這三者之間是如何進行UDP打洞的。在這我們分三種具體情景來討論:

第一種是最簡單的一種情景,兩個客戶端都位于同一個NAT設備后面,即位于同一內網中;

第二種是最普遍的一種情景,兩個客戶端分別位于不同的NAT設備后面,分屬不同的內網;

第三種是客戶端位于兩層NAT設備之后,通常最上層的NAT是由網絡提供商提供的,第二層NAT是家用的NAT路由器之類的設備提供的。

4.2.3 P2P的兩個客戶端位于同一個NAT設備后面

首先假設兩個客戶端位于同一個NAT設備后面,并且位于內網,如圖4所示。客戶端A與集中服務器建立了UDP連接,經過NAT轉換后,A的公網端口被映射為62000。客戶端B同樣與集中服務器建立了UDP連接,公網端口映射為62005。

假設客戶端A想通過集中服務器,發起對客戶端B的連接。客戶端A向集中服務器發出消息請求與客戶端B進行連接,集中服務器將客戶端B的外網地址二元組以及內網地址二元組發給客戶端A,同時把客戶端A的外網以及內網的地址二元組信息發給客戶端B。客戶端A和客戶端B發往對方公網地址二元組信息的UDP數據包不一定會被對方收到,這取決于當前的NAT設備是否支持不同端口之間的UDP數據包能否到達即Hairpin轉換特性,無論如何客戶端A與客戶端B發往對方內網的地址二元組信息的UDP數據包是一定可以到達的,內網數據包不需要路由,且速度更快。客戶端A與客戶端B推薦采用內網的地址二元組信息進行常規的P2P通信。

假定NAT設備支持Hairpin轉換,具體的Hairpin轉換見4.2.5章節,應用程序也應忽略與內網地址二元組的連接,如果客戶端A、客戶端B采用外網的地址二元組做為P2P通信的連接,這勢必會造成數據包無謂地經過NAT設備,這是一種對資源的浪費。就目前的網絡情況而言,應用程序在“打洞”的時候,最好還是把外網和內網的地址二元組都嘗試一下。如果都能成功,優先以內網地址進行連接。

4.2.4 P2P客戶端位于不同的NAT設備后面

假定客戶端A與客戶端B在不同的NAT設備后面,分屬不同的內網,如圖5所示。客戶端A與客戶端B都經由各自的NAT設備與集中服務器建立了UDP連接,客戶端A與客戶端B的本地端口號均為4321,集中服務器的公網端口號為1234。在向外的會話中,客戶端A的外網IP被映射為155.99.25.11,外網端口為62000,客戶端B的外網IP被映射為138.76.29.7,外網端口為31000。

如下所示:

客戶端A——>本地IP:10.0.0.1,本地端口:4321,外網IP:155.99.25.11,外網端口:62000

客戶端B——>本地IP:10.1.1.3,本地端口:4321,外網IP:138.76.29.7,外網端口:31000

在客戶端A向服務器發送的登陸消息中,包含有客戶端A的內網地址二元組信息,即10.0.0.1:4321;服務器會記錄下客戶端A的內網地址二元組信息,同時會把自己觀察到的客戶端A的外網地址二元組信息記錄下來,即155.99.25.11:62000。同理,服務器也會記錄下客戶端B的內網地址二元組信息為10.1.1.3:4321和由服務器觀察到的客戶端B的外網地址二元組信息,138.76.29.7:31000。無論A與B二者中的任何一方向服務器發送P2P連接請求,服務器都會將其記錄下來的上述的外網和內網地址二元組發送給A或B。

A、B分屬不同的內網,它們彼此的內網地址在外網中是沒有路由的,所以發往各自內網地址的UDP數據包會發送到錯誤的主機或者根本不存在的主機上。現在假定A的第一個消息將發往B的外網地址,如圖5所示。該消息途經A的NAT設備,并在該設備上生成一個會話表項,該會話的源地址二元組信息是{10.0.0.1:4321},該地址二元組信息和客戶端A與服務器建立連接的時候NAT生成的源地址二元組信息一樣,但它的目的地址不同。如果A的NAT設備給出的響應是OK的,那么A的NAT設備將保留A的內網地址二元組信息,并且所有來自A的源地址二元組信息為{10.0.0.1:4321}的數據包都沿用A與集中服務器事先建立起來的會話,外網地址二元組信息均為{155.99.25.11:62000}。

A向B的外網地址發送消息的過程就是“打洞”的過程,從A的內網的角度來看應為從{10.0.0.1:4321}發往{138.76.29.7:31000},從A在其NAT設備上建立的會話來看,是從{155.99.25.11:62000}發到{138.76.29.7:31000}。

如果A發給B的外網地址二元組的消息包在B向A發送消息包之前到達B的NAT設備,B的NAT設備會認為A發過來的消息是未經授權的外網消息,會丟棄掉該數據包。B發往A的消息包與上述的過程一樣,會在B的NAT設備上建立一個{10.1.1.3:4321,155.99.25.11:62000}的會話(通常也會沿用B與集中服務器連接時建立的會話,只是該會話現在不僅接受由服務器發給B的消息,還可以接受從A的NAT設備155.99.25.11:6200發來的消息),一旦A與B都向對方的NAT設備在外網上的地址二元組發送了數據包,就打開了A與B之間的“洞”,A與B向對方的外網地址發送數據,等效為向對方的客戶端直接發送UDP數據包了。一旦應用程序確認已經可以通過往對方的外網地址發送數據包的方式讓數據包到達NAT后面的目的應用程序,程序會自動停止繼續發送用于“打洞”的數據包,轉而開始真正的P2P數據傳輸。

4.2.5 P2P客戶端位于多層NAT設備后面

有的網絡拓撲結構包含了多個NAT設備,如果沒有掌握該拓撲結構的詳細信息,兩個客戶端之間是無法建立“最優化”的P2P路由的。現在我們來討論最后一種情況,如圖6所示。假定NAT C是由ISP(Internet Service Provider)提供的NAT設備,NAT C提供將多個用戶節點映射到有限的幾個公網IP的服務,NAT A和NAT B作為NAT C的內網節點將把用戶的家庭網絡或內部網絡接入NAT C的內網,然后用戶的內部網絡就可以經由NAT C訪問公網了。從這種拓撲結構上來看,只有服務器與NAT C是真正擁有公網可路由IP地址的設備,而NAT A和NAT B所使用的公網IP地址,實際上是由ISP服務提供商設定的(相對于NAT C而言)內網地址(本文的后續部分把這個由ISP提供的內網地址相對于NAT C稱之為“偽”公網地址),同理隸屬于NAT A與NAT B的客戶端,相對與NAT A,NAT B而言,它們處于NAT A,NAT B的內網,以此類推,客戶端可以放到到多層NAT設備后面。客戶端A和客戶端B發起對服務器S的連接的時候,就會依次在NAT A和NAT B上建立向外的Session,而NAT A、NAT B要聯入公網的時候,會在NAT C上再建立向外的Session。

現在假定客戶端A和B希望通過UDP“打洞”完成兩個客戶端的P2P直連。最優化的路由策略是客戶端A向客戶端B的“偽公網”IP上發送數據包,即ISP服務提供商指定的內網IP,NAT B的“偽”公網地址二元組,{10.0.1.2:55000}。由于從服務器的角度只能觀察到真正的公網地址,也就是NAT A,NAT B在NAT C建立session的真正的公網地址{155.99.25.11:62000}以及{155.99.25.11:62005},非常不幸的是客戶端A與客戶端B是無法通過服務器知道這些

“偽”公網的地址,而且即使客戶端A和B通過某種手段可以得到NAT A和NAT B的“偽”公網地址,我們仍然不建議采用上述的“最優化”的打洞方式,這是因為這些地址是由ISP服務提供商提供的或許會存在與客戶端本身所在的內網地址重復的可能性(例如:NAT A的內網的IP地址域恰好與NAT A在NAT C的“偽”公網IP地址域重復,這樣就會導致打洞數據包無法發出的問題)。

因此客戶端別無選擇,只能使用由公網服務器觀察到的A,B的公網地址二元組進行“打洞”操作,用于“打洞”的數據包將由NAT C進行轉發。

當客戶端A向客戶端B的公網地址二元組{155.99.25.11:62005}發送UDP數據包的時候,NAT A首先把數據包的源地址二元組由A的內網地址二元組{10.0.0.1:4321}轉換為“偽”公網地址二元組{10.0.1.1:45000},現在數據包到了NAT C,NAT C應該可以識別出來該數據包是要發往自身轉換過的公網地址二元組,如果NAT C可以給出“合理”響應的話,NAT C將把該數據包的源地址二元組改為{155.99.25.11:62000},目的地址二元組改為{10.0.1.2:55000},即NAT B的“偽”公網地址二元組,NAT B最后會將收到的數據包發往客戶端B。同樣,由B發往A的數據包也會經過類似的過程。目前也有很多NAT設備不支持類似這樣的“Hairpin轉換”,但是已經有越來越多的NAT設備商開始加入對該轉換的支持中來。

4.2.6 UDP在空閑狀態下的超時問題

由于UDP轉換協議提供的“洞”不是絕對可靠的,多數NAT設備內部都有一個UDP轉換的空閑狀態計時器,如果在一段時間內沒有UDP數據通信,NAT設備會關掉由“打洞”操作打出來的“洞”,作為應用程序來講如果想要做到與設備無關,就最好在穿越NAT以后設定一個穿越的有效期。

很遺憾目前沒有標準有效期,這個有效期與NAT設備內部的配置有關,某些設備上最短的只有20秒左右。在這個有效期內,即使沒有P2P數據包需要傳輸,應用程序為了維持該“洞”可以正常工作,也必須向對方發送“打洞”心跳包。這個心跳包是需要雙方應用程序都發送的,只有一方發送不會維持另一方的Session正常工作。除了頻繁發送“打洞”心跳包以外,還有一個方法就是在當前的“洞”超時之前,P2P客戶端雙方重新“打洞”,丟棄原有的“洞”,這也不失為一個有效的方法。

4.3 TCP打洞問題

建立穿越NAT設備的P2P的TCP連接只比UDP復雜一點點,TCP協議的”“打洞”從協議層來看是與UDP的“打洞”過程非常相似的。盡管如此,基于TCP協議的打洞至今為止還沒有被很好的理解,這也造成了的對其提供支持的NAT設備不是很多。在NAT設備支持的前提下,基于TCP的“打洞”技術實際上與基于UDP的“打洞”技術一樣快捷、可靠。實際上,只要NAT設備支持的話,基于TCP的P2P技術的健壯性將比基于UDP技術的更強一些,因為TCP協議的狀態機給出了一種標準的方法來精確的獲取某個TCP session的生命期,而UDP協議則無法做到這一點。

4.3.1 套接字和TCP端口的重用

實現基于TCP協議的P2P打洞過程中,最主要的問題不是來自于TCP協議,而是來自于應用程序的API接口。這是由于標準的伯克利(Berkeley)套接字的API是圍繞著構建客戶端/服務器程序而設計的,API允許TCP流套接字通過調用connect()函數來建立向外的連接,或者通過listen()和accept函數接受來自外部的連接,但是,API不提供類似UDP那樣的,同一個端口既可以向外連接,又能夠接受來自外部的連接。而且更糟的是,TCP的套接字通常僅允許建立1對1的響應,即應用程序在將一個套接字綁定到本地的一個端口以后,任何試圖將第二個套接字綁定到該端口的操作都會失敗。

為了讓TCP“打洞”能夠順利工作,我們需要使用一個本地的TCP端口來監聽來自外部的TCP連接,同時建立多個向外的TCP連接。幸運的是,所有的主流操作系統都能夠支持特殊的TCP套接字參數,通常叫做“SO_REUSEADDR”,該參數允許應用程序將多個套接字綁定到本地的一個地址二元組(只要所有要綁定的套接字都設置了SO_REUSEADDR參數即可)。BSD系統引入了SO_REUSEPORT參數,該參數用于區分端口重用還是地址重用,在這樣的系統里面,上述所有的參數必須都設置才行。

4.3.2 打開P2P的TCP流

假定客戶端A希望建立與B的TCP連接。我們像通常一樣假定A和B已經與公網上的已知服務器建立了TCP連接。服務器記錄下來每個接入的客戶端的公網和內網的地址二元組,如同為UDP服務的時候一樣。從協議層來看,TCP“打洞”與UDP“打洞”是幾乎完全相同的過程。

  • 客戶端A使用其與服務器的連接向服務器發送請求,要求服務器協助其連接客戶端B;
  • 服務器將B的公網和內網的TCP地址的二元組信息返回給A,同時,服務器將A的公網和內網的地址二元組也發送給B;
  • 客戶端A和B使用連接服務器的端口異步地發起向對方的公網、內網地址二元組的TCP連接,同時監聽各自的本地TCP端口是否有外部的連接聯入;
  • A和B開始等待向外的連接是否成功,檢查是否有新連接聯入。如果向外的連接由于某種網絡錯誤而失敗,如:“連接被重置”或者“節點無法訪問”,客戶端只需要延遲一小段時間(例如延遲一秒鐘),然后重新發起連接即可,延遲的時間和重復連接的次數可以由應用程序編寫者來確定;
  • TCP連接建立起來以后,客戶端之間應該開始鑒權操作,確保目前聯入的連接就是所希望的連接。如果鑒權失敗,客戶端將關閉連接,并且繼續等待新的連接聯入。客戶端通常采用“先入為主”的策略,只接受第一個通過鑒權操作的客戶端,然后將進入P2P通信過程不再繼續等待是否有新的連接聯入。

與UDP不同的是,因為使用UDP協議的每個客戶端只需要一個套接字即可完成與服務器的通信,而TCP客戶端必須處理多個套接字綁定到同一個本地TCP端口的問題,如圖7所示。現在來看實際中常見的一種情景,A與B分別位于不同的NAT設備后面,如圖5所示,并且假定圖中的端口號是TCP協議的端口號,而不是UDP的端口號。圖中向外的連接代表A和B向對方的內網地址二元組發起的連接,這些連接或許會失敗或者無法連接到對方。如同使用UDP協議進行“打洞”操作遇到的問題一樣,TCP的“打洞”操作也會遇到內網的IP與“偽”公網IP重復造成連接失敗或者錯誤連接之類的問題。

客戶端向彼此公網地址二元組發起連接的操作,會使得各自的NAT設備打開新的“洞”允許A與B的TCP數據通過。如果NAT設備支持TCP“打洞”操作的話,一個在客戶端之間的基于TCP協議的流通道就會自動建立起來。如果A向B發送的第一個SYN包發到了B的NAT設備,而B在此前沒有向A發送SYN包,B的NAT設備會丟棄這個包,這會引起A的“連接失敗”或“無法連接”問題。而此時,由于A已經向B發送過SYN包,B發往A的SYN包將被看作是由A發往B的包的回應的一部分,所以B發往A的SYN包會順利地通過A的NAT設備,到達A,從而建立起A與B的P2P連接。

4.3.3 從應用程序的角度來看TCP打洞

從應用程序的角度來看,在進行TCP“打洞”的時候都發生了什么呢?假定A首先向B發出SYN包,該包發往B的公網地址二元組,并且被B的NAT設備丟棄,但是B發往A的公網地址二元組的SYN包則通過A的NAT到達了A,然后,會發生以下的兩種結果中的一種,具體是哪一種取決于操作系統對TCP協議的實現:

(1)A的TCP實現會發現收到的SYN包就是其發起連接并希望聯入的B的SYN包,通俗一點來說就是“說曹操,曹操到”的意思,本來A要去找B,結果B自己找上門來了。A的TCP協議棧因此會把B作為A向B發起連接connect的一部分,并認為連接已經成功。程序A調用的異步connect()函數將成功返回,A的listen()等待從外部聯入的函數將沒有任何反映。此時,B聯入A的操作在A程序的內部被理解為A聯入B連接成功,并且A開始使用這個連接與B開始P2P通信。

由于收到的SYN包中不包含A需要的ACK數據,因此,A的TCP將用SYN-ACK包回應B的公網地址二元組,并且將使用先前A發向B的SYN包一樣的序列號。一旦B的TCP收到由A發來的SYN-ACK包,則把自己的ACK包發給A,然后兩端建立起TCP連接。簡單的說,第一種,就是即使A發往B的SYN包被B的NAT丟棄了,但是由于B發往A的包到達了A。結果是,A認為自己連接成功了,B也認為自己連接成功了,不管是誰成功了,總之連接是已經建立起來了。

(2)另外一種結果是,A的TCP實現沒有像(1)中所講的那么“智能”,它沒有發現現在聯入的B就是自己希望聯入的。就好比在機場接人,明明遇到了自己想要接的人卻不認識,誤認為是其他的人,安排別人給接走了,后來才知道是自己錯過了機會,但是無論如何,人已經接到了任務已經完成了。然后,A通過常規的listen()函數和accept()函數得到與B的連接,而由A發起的向B的公網地址二元組的連接會以失敗告終。盡管A向B的連接失敗,A仍然得到了B發起的向A的連接,等效于A與B之間已經聯通,不管中間過程如何,A與B已經連接起來了,結果是A和B的基于TCP協議的P2P連接已經建立起來了。

第一種結果適用于基于BSD的操作系統對于TCP的實現,而第二種結果更加普遍一些,多數Linux和Windows系統都會按照第二種結果來處理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72978.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72978.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72978.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法 之 樹形dp 樹的中心、重心

文章目錄 重心實踐題目小紅的陡峭值 在樹的算法中,求解樹的中心和重心是一類十分重要的算法 求解樹的重心 樹的重心的定義:重心是樹中的一個節點,如果將這個點刪除后,剩余各個連通塊中點數的最大值最小,那么這個節點…

游戲引擎學習第146天

音高變化使得對齊讀取變得不可能,我們可以支持循環聲音了。 我們今天的目標是完成之前一段時間所做的音頻代碼。這個項目并不依賴任何引擎或庫,而是一個教育項目,目的是展示從頭到尾運行一個游戲所需要的全部代碼。無論你對什么方面感興趣&a…

深入理解MySQL主從原理

導讀 高鵬(網名八怪),《深入理解MySQL主從原理》系列文的作者。 本系列通過GTID、Event、主庫、從庫、案例分析,五大塊來詳細講解主從原理。 這篇文章重在學習筆記整理! 在學習《深入理解MySQL主從原理》一書時&…

前端數據模擬利器 Mock.js 深度解析

前端數據模擬利器 Mock.js 深度解析 一、Mock.js 核心價值 1.1 為何需要數據模擬 前后端并行開發加速接口文檔驅動開發異常場景模擬測試演示環境數據構造 1.2 Mock.js 核心能力 // 典型數據生成示例 Mock.mock(/api/user, {"users|5-10": [{"id|1": 1…

Phi-4-multimodal:圖、文、音頻統一的多模態大模型架構、訓練方法、數據細節

Phi-4-Multimodal 是一種參數高效的多模態模型,通過 LoRA 適配器和模式特定路由器實現文本、視覺和語音/音頻的無縫集成。訓練過程包括多階段優化,確保在不同模式和任務上的性能,數據來源多樣,覆蓋高質量網絡和合成數據。它的設計…

前后端數據加密傳輸【最佳方案】

AES和RSA區別 算法類型安全性密鑰長度/輸出長度速度應用場景AES對稱加密高128位、192位、256位快適用于大規模數據加密,入HTTPS協議的數據傳輸RSA非對稱加密高1024位、2048位、4096位較慢適用于數據安全傳輸、數字簽名和身份驗證 綜上:兼顧安全性和性能…

Unity--Cubism Live2D模型使用

了解LIVE2D在unity的使用--前提記錄 了解各個組件的作用 Live2D Manuals & Tutorials 這些文件都是重要的控制動畫參數的 Cubism Editor是編輯Live2D的工具,而導出的數據的類型,需要滿足以上的條件 SDK中包含的Cubism的Importer會自動生成一個Pref…

Linux | Vim 鼠標不能右鍵粘貼、跨系統復制粘貼

注:本文為 “ Vim 中鼠標右鍵粘貼、跨系統復制粘貼問題解決方案” 相關文章合輯。 未整理去重。 Linux 入門:vim 鼠標不能右鍵粘貼、跨系統復制粘貼 foryouslgme 發布時間 2016 - 09 - 28 10:24:16 Vim基礎 命令模式(command-mode)插入模式(insert-m…

Flink-DataStreamAPI-執行模式

一、概覽 DataStream API支持不同的運行時執行模式,我們可以根據用例的要求和作業的特征進行選擇。 STREAMING執行模式:被稱為“經典”執行模式為,主要用于需要持續增量處理并且預計無限期保持在線的無界作業BATCH執行模式:類似…

解決VScode 連接不上問題

問題 :VScode 連接不上 解決方案: 1、手動殺死VS Code服務器進程,然后重新嘗試登錄 打開xshell ,遠程連接服務器 ,查看vscode的進程 ,然后全部殺掉 [cxqiZwz9fjj2ssnshikw14avaZ ~]$ ps ajx | grep vsc…

C#類型轉換基本概念

一、基本定義? C# 類型轉換是將數據從一種類型轉換為另一種類型的過程,分為 ?隱式轉換? 和 ?顯式轉換? 兩類?。 強類型語言特性?:C# 要求變量類型在編譯時確定,類型轉換需滿足兼容性或顯式規則?。目的?:處理不同數據類…

使用阿里云操作系統控制臺排查內存溢出

引言 操作系統控制臺是阿里云最新推出的一款智能運維工具,專為提升運維效率、優化服務器管理而設計。它集成了多種運維管理功能,包括操作系統助手、插件管理器以及其他實用工具,為用戶提供一站式的運維解決方案。無論是個人開發者還是企業運…

(C/S)架構、(B/S)架構

客戶機/服務器(C/S)架構 理論描述: 客戶機/服務器架構是一種網絡架構風格,其中任務被分配給網絡中的不同計算機,以提高效率和靈活性。這種架構由兩部分組成:客戶端(Client)和服務器&…

混合存儲HDD+SSD機型磁盤陣列,配上SSD緩存功能,性能提升300%

企業日常運行各種文件無處不在,文檔、報告、視頻、應用數據......面對成千上萬的文件,團隊之間需要做到無障礙協作,員工能夠即時快速訪問、共享處理文件。隨著業務增長,數字化辦公不僅需要大容量,快速高效的文件訪問越…

C 語言異常處理方式全面解析

引言? 在 C 語言編程領域,穩健的錯誤處理機制對于保障程序的可靠性、穩定性以及安全性至關重要。異常處理作為錯誤處理的進階形式,雖然并非 C 語言標準庫原生支持的特性,但通過巧妙運用語言特性和編程技巧,開發者能夠實現有效的…

【每日學點HarmonyOS Next知識】狀態欄控制、片段按鈕點擊回調、繪制組件、取消按鈕與輸入框對齊、父調子組件方法

1、HarmonyOS 狀態欄怎么控制顯示于隱藏,設置狀態欄顏色,子顏色等控制? 顯示與隱藏 可以設置沉浸式,隱藏的話可以退出沉靜式,在子窗口打開的頁面 aboutToAppear 方法中設置沉浸式 aboutToAppear(): void {// 設置沉浸…

二級Python通關秘籍:字符串操作符/函數/方法全解析與實戰演練

第一章 字符串基礎概念與運算符速通 1.1 字符串的不可變性特性 在Python中,字符串被設計為immutable類型,任何修改操作都會生成新對象。這一特性直接影響字符串拼接的性能表現,建議使用join()方法代替多次操作。 1.2 基礎操作符全掌握 pyt…

GStreamer —— 2.6、Windows下Qt加載GStreamer庫后運行 - “教程6:媒體格式和Pad功能“(附:完整源碼)

運行效果 簡介 上一個教程演示了GUI 工具包集成(gtk)。本教程介紹媒體格式和Pad功能。Pad Capabilities 是 GStreamer 的一個基本元素,盡管大多數它們不可見,因為框架會處理它們 自然而然。這個有點理論性的教程展示了: ? 什么是 Pad 功能。…

【前綴和與差分 C/C++】洛谷 P8218 求區間和

2025 - 03 - 09 - 第 72 篇 Author: 鄭龍浩 / 仟濹 【前綴和與差分 C/C】 文章目錄 洛谷 P8218 求區間和題目描述輸入格式輸出格式輸入輸出樣例 #1輸入 #1輸出 #1 說明/提示思路代碼 洛谷 P8218 求區間和 題目描述 給定 n n n 個正整數組成的數列 a 1 , a 2 , ? , a n a_…

初識Bert

在學習Bert之前我們先了解“遞歸神經網絡(RNN Recurrent neural network)” 和 “長短期記憶(LSTM Long short-term memory)” 我們如果僅僅識別每個字的含義,那么在一句話中沒有相同的字還是可以的但是如果一句話中有相同的字,那…