1. 程式人生 > >QQ 通訊原理分析

QQ 通訊原理分析

下面有4個基本的問答:

問題一:為什麼只要可以連上網際網路的計算機都可以用QQ相互建立通訊,而不需要固定IP?
也就是這個QQ使用者端是怎樣找到另一個QQ使用者的,而使用者在每次使用時他可能用的是不同的計算機,有著不同的IP地址。
伺服器端不會以qq使用者端的ip作為唯一標識,伺服器端會以qq賬號作為唯一標識,所以這個賬號肯定是唯一的,一個賬號登陸時每次都可以有不同的ip地址,但賬號卻相同,當賬號a登陸伺服器,伺服器會記錄下賬號a的ip地址,去通知a的好友,告訴他們,a上線了和現在的ip地址,a的好友就可以跟他通訊了
問題二:是不是QQ在通訊時根本不適用IP,QQ客戶端先是訪問QQ伺服器端,然後QQ伺服器端再為要建立連線的QQ客戶端建立連線?
只要是網路層的通訊,都會涉及到ip/tcp協議,就肯定需要ip,qq客戶端登陸qq伺服器,伺服器只是記錄登陸狀態,不會一直和qq保持通訊,只會每隔一段時間傳送心跳資料包,來確實qq客戶端是否還在網路上。當qq客戶端a上線後,伺服器會告訴a,目前a的線上好友的最新ip地址,當a需要與任意好友通訊時,直接使用ip地址就ok了。qq客戶端a與qq客戶端b通訊,可以兩種方式,第一就是qq伺服器有轉發的伺服器,第二是,a與b直接通訊,不會告訴qq伺服器
問題三:QQ客戶端可以訪問QQ伺服器端,然後伺服器端獲取QQ客戶端的IP建立通訊,是不是這樣的過程。。。如果是,這個過程是怎麼處理的呢?
是這樣的過程,qq客戶端請求一個連線給伺服器,伺服器接收後,知道qq端a上線,把qq端a的賬號跟目前的ip會記錄下來,放在線上列表裡或者其他的地方,然後每隔幾分鐘或者幾秒鐘給qq端a傳送心跳包,問他是否還線上,來確保qq端a的最新狀態。這裡客戶端與伺服器的通訊方式是udp。而不會時時刻刻都在用tcp連線。
問題四:QQ客戶端雖然IP地址不固定,但是在建立與QQ伺服器端的通訊時,必須提供自己的IP被伺服器獲取,然後才能建立他們之間的通訊,進而在建立客戶端之間的通訊。也就是,只要能上網就有IP,只不過客戶端的IP,是被QQ客戶端獲取了,然後才建立通訊的。(這是自己的猜測,不知對否。。。)
恩,伺服器不會以ip作為唯一標識,會以賬號作為唯一標識,但與賬號通訊的時候會用到賬號目前所對應的ip,客戶端與客戶端通訊也如此

QQ有兩種登陸模式
一種是比較不常用的:直接登陸伺服器,所有資訊由伺服器轉發,這種登陸模式有個特點就是你會發現你使用獲取IP版本的QQ無法獲取對方的IP~ (這個我不清楚有沒有,但是肯定可以)
另一種是普通的:首先連線登陸伺服器,在給對發發訊息的時候,首先嚐試與對方進行打洞連線,如果可以打通訊息直接傳送給對方,如果不能打通,則訊息轉發伺服器,由伺服器轉發.(傳檔案會優先P2P,不行再選擇中轉,不知道聊天是不是優先P2P的,還是聊天文字是中轉的?圖片呢?會員表情?這個的確要問tx了,技術上的都是可以實現,選擇什麼只能問tx了)

如果上面的東西輕鬆搞定,那麼你可以繼續看了,如果不知道,那麼下面就不用看了

 

先貼一點資料

一、登陸。

不管UDP還是TCP,最終登陸成功之後,QQ都會有一個TCP連線來保持線上狀態。這個TCP連線的遠端埠一般是80,採用UDP方式登陸的時候,埠是8000。因此,假如你所在的網路開放了80埠(80埠是最常用埠。。就是通常訪問Web的埠,禁掉它的話,你的網路對你來說價值已經不大了),但沒有遮蔽騰訊的伺服器IP,恭喜你,你是可以登陸成功QQ的。
二、聊天訊息通訊。
採用UDP協議,通過伺服器中轉方式。因此,現在的IP偵探在你僅僅跟對方傳送聊天訊息的時候是無法獲取到IP的。大家都知道,UDP 協議是不可靠協議,它只管傳送,不管對方是否收到的,但它的傳輸很高效。但是,作為聊天軟體,怎麼可以採用這樣的不可靠方式來傳輸訊息呢?於是,騰訊採用了上層協議來保證可靠傳輸:如果客戶端使用UDP協議發出訊息後,伺服器收到該包,需要使用UDP協議發回一個應答包。如此來保證訊息可以無遺漏傳輸。之所以會發生在客戶端明明看到“訊息傳送失敗”但對方又收到了這個訊息的情況,就是因為客戶端發出的訊息伺服器已經收到並轉發成功,但客戶端由於網路原因沒有收到伺服器的應答包引起的。
三、檔案/自定義表情傳送。
大家都知道,QQ可以傳送檔案,可以傳送自定義表情。先說官方表情。官方表情實際傳送的是命令字,而沒有傳送表情。客戶端收到命令字後,會自動解釋為對應的表情。因此,QQ2008正式版的客戶端發出的新版表情,在2007beta4及以前的版本無法找到相對應的表情,就無法解釋,看到的就會是空白資訊,但查聊天記錄就會有[表情]字樣。
自定義表情的傳送是以檔案傳輸方式進行的。
下面說檔案傳輸方式:A要向B傳送一個檔案,於是發出一個檔案傳送請求。伺服器收到這個檔案傳送請求後,轉發給B,同時或者在B應答後,將A的IP地址同時傳送給B。B這個時候就得到了A的真實IP。這裡的IP是你的本機IP。也就是說,如果A處在內網,B得到的地址就是一個內網地址。B得到了A的地址之後,就會嘗試去連線A。如果B也處於內網,那麼,顯然A跟B之間的連線是無法建立的。這個時候,客戶端就會請求伺服器進行檔案中轉。因為伺服器具有公網 IP,處在內網的A跟B都是可以連線到伺服器的,於是,A跟B的檔案傳送就通過伺服器中轉的方式,順利進行。(注:伺服器檔案中轉使用443埠)

其實紅字部分是不正確的,QQ的檔案傳輸採用的是P2P,也就是為什麼在相同區域網下,兩個人用QQ傳檔案會非常快,這裡用到的是NAT打洞技術,下面我會詳細的說明

無論是傳檔案還是聊天文字技術上都可以使用P2P,P2P 都可以用UDP實現,而UDP在NAT打洞上面更加方便和成熟,所以騰訊應該是優先UDP,但是使用UDP為了增加可靠性,尤其是傳檔案,就要用到UDP模擬TCP ,也就是他所謂的新TCP,看來在UDP安全通訊方面,騰訊應該很牛逼了

下面只說的技術,具體QQ是不是這樣的只能問騰訊了

(TCP與UDP的打洞技術過程基本相同,支援TCP打洞的nat裝置不多,洞其實就是socket,udp和tcp的socket api的問題,具體以後寫文章研究一下)

* 注:什麼是內網、公網
內網、公網是兩種Internet的接入方式。
內網接入方式:上網的計算機得到的IP地址是Inetnet上的保留地址,保留地址有如下3種形式:
10.x.x.x(學校內網)
172.16.x.x至172.31.x.x
192.168.x.x(自用路由)
內網的計算機以NAT(網路地址轉換)協議,通過一個公共的閘道器訪問Internet。
內網的計算機可向Internet上的其他計算機發送連線請求,但Internet上其他的計算機無法向內網的計算機發送連線請求。
公網接入方式:上網的計算機得到的IP地址是Inetnet上的非保留地址。公網的計算機和Internet上的其他計算機可隨意互相訪問。

*注:Nat技術基礎

NAT(Network Address Translators),網路地址轉換:網路地址轉換是在IP地址日益缺乏的情況下產生的,它的主要目的就是為了能夠地址重用。NAT分為兩大類,基本的NAT和NAPT(Network Address/Port Translator)。

最開始NAT是執行在路由器上的一個功能模組。

最先提出的是基本的NAT,它的產生基於如下事實:一個私有網路(域)中的節點中只有很少的節點需要與外網連線(呵呵,這是在上世紀90年代中期提出的)。那麼這個子網中其實只有少數的節點需要全球唯一的IP地址,其他的節點的IP地址應該是可以重用的。
因此,基本的NAT實現的功能很簡單,在子網內使用一個保留的IP子網段,這些IP對外是不可見的。子網內只有少數一些IP地址可以對應到真正全球唯一的IP地址。如果這些節點需要訪問外部網路,那麼基本NAT就負責將這個節點的子網內IP轉化為一個全球唯一的IP然後傳送出去。(基本的NAT會改變IP包中的原IP地址,但是不會改變IP包中的埠)
關於基本的NAT可以參看RFC 1631

另外一種NAT叫做NAPT,從名稱上我們也可以看得出,NAPT不但會改變經過這個NAT裝置的IP資料報的IP地址,還會改變IP資料報的TCP/UDP埠。基本NAT的裝置可能我們見的不多(呵呵,我沒有見到過),NAPT才是我們真正討論的主角。

Client A
10.0.0.1:1234

A是其中的一臺計算機,這個網路的閘道器(一個NAT裝置)的外網IP是155.99.25.11(應該還有一個內網的IP地址,比如10.0.0.10)。

如果Client A中的某個程序(這個程序建立了一個UDP Socket,這個Socket繫結1234埠)想訪問外網主機18.181.0.31的1235埠,那麼當資料包通過NAT時會發生什麼事情呢?

首先NAT會改變這個資料包的原IP地址,改為155.99.25.11。

接著NAT會為這個傳輸建立一個Session(Session是一個抽象的概念,如果是TCP,也許Session是由一個SYN包開始,以一個FIN包結束。而UDP呢,以這個IP的這個埠的第一個UDP開始,結束呢,呵呵,也許是幾分鐘,也許是幾小時,這要看具體的實現了)並且給這個Session分配一個埠,比如62000,然後改變這個資料包的源埠為62000。所以本來是(10.0.0.1:1234->18.181.0.31:1235)的資料包到了網際網路上變為了(155.99.25.11:62000->18.181.0.31:1235)。

一旦NAT建立了一個Session後,NAT會記住62000埠對應的是10.0.0.1的1234埠,以後從18.181.0.31傳送到62000埠的資料會被NAT自動的轉發到10.0.0.1上。(注意:這裡是說18.181.0.31傳送到62000埠的資料會被轉發,其他的IP傳送到這個埠的資料將被NAT拋棄)這樣Client A就與Server S1建立以了一個連線。

首先如果兩個機子全部在外網,也就是他們可以直接相連,那麼P2P一點問題也沒有

第二如果兩個機子一個是內網A,一個是外網B

1.如果內網的主動想外網的請求連線,那麼連線就像上面的解釋一樣

2.但是洞只能有內網來打,洞是有方向性的(session儲存這個資訊),所以當外網的想主動和內網的連線時,就需要中介伺服器,伺服器通知內網A向B打洞來建立連線

第三如果兩個機子一個是內網A,另一個是另外一個內網B

網路環境描述:
內網1NAT:NAT1/218.7.32.28
內網1中一臺主機A:ClientA/192.168.1.128
內網2NAT:NAT2/218.7.31.221
內網2中一臺主機B:ClientB/192.168.0.5
公網伺服器:Server

 

首先讓ClientA和ClientB登入到伺服器Server(假如兩臺主機都採用2347埠),此時NAT1和NAT2會分別為ClientA和 ClientB開啟一個指向Server的洞(NAT1上218.7.32.28:26756和NAT2上218.7.31.221:27550)。伺服器應改記錄這兩個客戶端的資訊(關鍵是那兩個洞的資訊)。當ClientA與ClientB要建立會話時,ClientA首先用2347埠向NAT2的洞傳送一個數據包,當然這個資料包會被NAT2所丟棄,但是由於這是從NAT1內部向外部發送資料,所以NAT1為ClientA打開了一個指向NAT2 的洞。而且這個新洞與原來NAT1上指向Server的舊洞的是同一個洞(因為是同一個埠26756),所以這裡可以說這個洞具有了兩個方向(關鍵),同時指向 Server和NAT2。這時ClientA應該通知Server,告訴ClientB,現在可以向NAT1的那個洞 (218.7.32.28:26756)傳送資料包了。當ClientB向NAT1的那個洞傳送資料以後,NAT2也為ClientB打了一個指向 NAT1的洞,這是可以說ClientA與ClientB的會話就建立完成了,他們可以不依賴Server進行通訊了。如果以後ClientA和 ClientB還需要建立其他會話 ,那麼這個牽線的“媒人”可以不是Server,而可以是ClientA或ClientB了。

第四如果兩個機子都是同一個內網

用上面的方法肯定可以,那麼如果NAT支援loopback(就是本地到本地的轉換),A,B可以連線,但是比較浪費頻寬和NAT,一般的時候都不會用loopback,會直接內網P2P(我覺得QQ客戶端可以做一下判斷以選擇內網直接P2P)

注:

NAT對session的處理

以下分析NAPT是依據什麼策略來判斷是否要為一個請求發出的UDP資料包建立Session的.主要有一下幾個策略:

A. 源地址(內網IP地址)不同,忽略其它因素, 在NAPT上肯定對應不同的Session

B. 源地址(內網IP地址)相同,源埠不同,忽略其它的因素,則在NAPT上也肯定對應不同的Session

C. 源地址(內網IP地址)相同,源埠相同,目的地址(公網IP地址)相同,目的埠不同,則在NAPT上肯定對應同一個Session

D. 源地址(內網IP地址)相同,源埠相同,目的地址(公網IP地址)不同,忽略目的埠,則在NAPT上是如何處理Session的呢?(這個要根據下面NAT的種類區別,Cone相同,Symmetic不同)

NAT分類

根據Stun協議(RFC3489),NAT大致分為下面四類

1)      Full Cone

這種NAT內部的機器A連線過外網機器C後,NAT會開啟一個埠.然後外網的任何發到這個開啟的埠的UDP資料報都可以到達A.不管是不是C發過來的.

例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88

A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)

任何傳送到 NAT(202.100.100.100:8000)的資料都可以到達A(192.168.8.100:5000)

2)      Restricted Cone

這種NAT內部的機器A連線過外網的機器C後,NAT開啟一個埠.然後C可以用任何埠和A通訊.其他的外網機器不行.

例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88

A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)

任何從C傳送到 NAT(202.100.100.100:8000)的資料都可以到達A(192.168.8.100:5000)

3)      Port Restricted Cone

這種NAT內部的機器A連線過外網的機器C後,NAT開啟一個埠.然後C可以用原來的埠和A通訊.其他的外網機器不行.

例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88

A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)

C(202.88.88.88:2000)傳送到 NAT(202.100.100.100:8000)的資料都可以到達A(192.168.8.100:5000)

以上三種NAT通稱Cone NAT.我們只能用這種NAT進行UDP打洞.

4)      Symmetic

 

 

對於這種NAT.連線不同的外部目標.原來NAT開啟的埠會變化.而Cone NAT不會.雖然可以用埠猜測.但是成功的概率很小.因此放棄這種NAT的UDP打洞.

 

 

第一種情況, 雙方都是Symmetric NAPT:

此情況應給不存在什麼問題,肯定是不支援UDP穿透。

第二種情況, 雙方都是Cone NAPT:

此情況是我們需要的,可以進行UDP穿透。

第三種情況, 一個是Symmetric NAPT, 一個是Cone NAPT:

這個行不行呢,這個問題留給大家吧

出處http://softpalace.co.de/?p=279