天天看點

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通信.其他的外網機器不行.

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

3)      Port Restricted Cone

這種NAT内部的機器A連接配接過外網的機器C後,NAT打開一個端口.然後C可以用原來的端口和A通信.其他的外網機器不行.

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穿透。