為了解決這題,可以具體看看下面這個討論。
這個說法應該比較可信的.
那么為什么呢?最本質上UDP的優勢還是帶寬的利用。這一切要回歸到99~03年的網絡狀況,當時網絡的特點就是接入帶寬很窄而且抖動特別厲害。所謂抖動可能是多方面的,例如延時突發性地暴增、也有可能是由於路由層面的變化突然導致路由黑洞,還各種等等等等的問題。TCP因為擁塞控制、保證有序等原因,在這種網絡狀態上對帶寬的利用是非常低的。而且因為網絡抖動的原因,應用層心跳超時(一般不依靠keepalive)應用層主動斷掉socket之后TCP需要三次握手才能重新建立鏈接,一旦出現頻繁的小抖動就會使得帶寬利用更低。而等待四次揮手的時間,也會占用服務器上寶貴的資源。
總結來說,當網絡差到一定程度了,TCP的優勢反而會成為劣勢。
這時候我們再看看UDP在這種情況下的表現。使用UDP對抗網絡抖動,說到底就是在應用層比TCP更快地探測和重傳,一旦超過一定的時間沒有收到回復,客戶端可以選擇馬上重試或者換一個IP:PORT重試(假如你的服務像QQ一樣有多個接入),在服務器端則可以果斷地斷掉socket。而可以應用UDP的時候,往往是你的應用層協議本身已經具備了一定的面向連接的特性。如果你應用層的協議已經達到了一定程度的消息冪等,客戶端可以幾乎無腦地進行重傳,這樣就可以 盡可能地降低網絡抖動的影響,同時也可以 盡可能地利用整個帶寬。而剛好QQ的協議,就具備類似的特點。
簡單來說就是我們可以使用UDP實現一個面向連接協議,這個協議可以很好地適應當時的網絡狀況和QQ本身的業務。但凡事都有成本,成本就是你的應用層協議本身需要去實現抵抗網絡異常帶來的問題。例如亂序、例如業務數據的分片和重組、例如網絡狀態探測等等等等。。。
而現在UDP也應用在很多跨運營商、跨地域、跨機房之間的服務調用當中。原因無它,就是網絡爛到一定程度了。
即使是UDP協議,完全通過服務器中轉、信息傳輸加密(用戶到服務器之間的,= =)、保存聊天內容協助警方等都是錢多用戶傻之后的事了。次早期的QQ官方客戶端提供了默認不勾選的“通過服務器中轉”選項,可見那時信息還是允許客戶端和客戶端之間直接發送的。
至於UDP穿牆之類的優勢,國內最常見的NAT共享網絡又不會影響客戶端主動發起TCP鏈接,應該不是使用UDP的主要原因。
[1] http://en.wikipedia.org/wiki/C10k_problem
1.登陸過程,客戶端client 采用TCP協議向服務器server發送信息,HTTP協議下載信息。登陸之后,會有一個TCP連接來保持在線狀態。
2.和好友發消息,客戶端client采用UDP協議,但是需要通過服務器轉發。騰訊為了確保傳輸消息的可靠,采用上層協議來保證可靠傳輸。如果消息發送失敗,客戶端會提示消息發送失敗,並可重新發送。
3.如果是在內網里面的兩個客戶端傳文件,QQ采用的是P2P技術,不需要服務器中轉。
QQ既有UDP也有TCP!
不管UDP還是TCP,最終登陸成功之后,QQ都會有一個TCP連接來保持在線狀態。這個TCP連接的遠程端口一般是80,采用UDP方式登陸的時候,端口是8000。
UDP協議是無連接方式的協議,它的效率高,速度快,占資源少,但是其傳輸機制為不可靠傳送,必須依靠輔助的算法來完成傳輸控制。QQ采用的通信協議以UDP為主,輔以TCP協議。由於QQ的服務器設計容量是海量級的應用,一台服務器要同時容納十幾萬的並發連接,因此服務器端只有采用UDP協議與客戶端進行通訊才能保證這種超大規模的服務。
QQ客戶端之間的消息傳送也采用了UDP模式,因為國內的網絡環境非常復雜,而且很多用戶采用的方式是通過代理服務器共享一條線路上網的方式,在這些復雜的情況下,客戶端之間能彼此建立起來TCP連接的概率較小,嚴重影響傳送信息的效率。而UDP包能夠穿透大部分的代理服務器,因此QQ選擇了UDP作為客戶之間的主要通信協議。
采用UDP協議,通過服務器中轉方式。因此,現在的IP偵探在你僅僅跟對方發送聊天消息的時候是無法獲取到IP的。大家都知道,UDP 協議是不可靠協議,它只管發送,不管對方是否收到的,但它的傳輸很高效。但是,作為聊天軟件,怎么可以采用這樣的不可靠方式來傳輸消息呢?於是,騰訊采用了上層協議來保證可靠傳輸:如果客戶端使用UDP協議發出消息后,服務器收到該包,需要使用UDP協議發回一個應答包。如此來保證消息可以無遺漏傳輸。之所以會發生在客戶端明明看到“消息發送失敗”但對方又收到了這個消息的情況,就是因為客戶端發出的消息服務器已經收到並轉發成功,但客戶端由於網絡原因沒有收到服務器的應答包引起的。
盡管UDP協議遠沒TCP協議那么龐大、復雜,但是,要想將UDP描述清楚,用好UDP卻要比TCP難不少,於是文章從下筆寫,到最終寫成,斷斷續續拖了好幾個月。
說起網絡socket,大家自然會想到TCP,用的最多也是TCP,UDP在大家的印象中是作為TCP的補充而存在,是無連接、不可靠、無序、無流量控制的傳輸層協議。UDP的無連接性已經深入人心,協議上的無連接性指的是一個UDP的Endpoint1(IP,PORT),可以向多個UDP的Endpointi(IP,PORT)發送數據包,也可以接收來自多個UDP的Endpointi(IP,PORT)的數據包。
實現上,需要考慮這樣一個特殊情況:UDP Client 在Endpoint_C1只往UDP Server的Endpoint_S1發送數據包,並且只接收來自Endpoint_S1的數據包,把UDP通信雙方都固定下來,這樣不就形成一條單向的虛”連接”了么?
1. UDP的”連接性”估計很多同學認為UDP的連接性只是將UDP通信雙方都固定下來了,一對一只是多對多的一個特例而已,這樣UDP連接不連接到無所謂了。果真如此嗎?其實不然,UDP的連接性可以帶來以下兩個好處:
1.1 高效率、低消耗我們知道Linux系統有用戶空間(用戶態)和內核空間(內核態)之分,對於x86處理器以及大多數其它處理器,用戶空間和內核空間之前的切換是比較耗時(涉及到上下文的保存和恢復,一般3種情況下會發生用戶態到內核態的切換:發生系統調用時、產生異常時、中斷時)。
那么對於一個高性能的服務應該減少頻繁不必要的上下文切換,如果切換無法避免,那么盡量減少用戶空間和內核空間的數據交換,減少數據拷貝。熟悉socket編程的同學對下面幾個系統調用應該比較熟悉了,由於UDP是基於用戶數據報的,只要數據包准備好就應該調用一次send或sendto進行發包,當然包的大小完全由應用層邏輯決定的。
細看兩個系統調用的參數便知道,sendto比send的參數多2個,這就意味着每次系統調用都要多拷貝一些數據到內核空間。同時,參數到內核空間后,內核還需要初始化一些臨時的數據結構來存儲這些參數值(主要是對端Endpoint_S的地址信息),在數據包發出去后,內核還需要在合適的時候釋放這些臨時的數據結構。進行UDP通信的時候,如果首先調用connect綁定對端Endpoint_S的后,那么就可以直接調用send來給對端Endpoint_S發送UDP數據包了。
用戶在connect之后,內核會永久維護一個存儲對端Endpoint_S的地址信息的數據結構,內核不再需要分配/刪除這些數據結構,只需要查找就可以了,從而減少了數據的拷貝。這樣對於connect方而言,該UDP通信在內核已經維護這一個“連接”了,那么在通信的整個過程中,內核都能隨時追蹤到這個“連接”。

1.2 錯誤提示
相信大家寫UDP Socket程序的時候,有時候在第一次調用sendto給一個unconnected UDP socket發送UDP數據包時,接下來調用recvfrom()或繼續調sendto的時候會返回一個ECONNREFUSED錯誤。對於一個無連接的UDP是不會返回這個錯誤的,之所以會返回這個錯誤,是因為你明確調用了connect去連接遠端的Endpoint_S了。那么這個錯誤是怎么產生的呢?沒有調用connect的UDP Socket為什么無法返回這個錯誤呢?
點擊全文鏈接(體驗更佳哦~):從UDP的”連接性”說起
騰訊優測(http://utest.qq.com)是專業的移動雲測試平台,提供【兼容性自動化測試】【雲手機】【漏洞檢測】等多維度測試服務。
使用UDP進行交互通信的好處在於,延遲較短,對數據丟失的處理比較簡單。同時,TCP是一個全雙工協議,需要建立連接,所以網絡開銷也會相對大。如果使用QQ語音和QQ視頻的話,UDP的優勢就更為突出了,首先延遲較小。最重要的一點是不可靠傳輸,這意味着如果數據丟失的話,不會有重傳。因為用戶一般來說可以接受圖像稍微模糊一點,聲音稍微不清晰一點,但是如果在幾秒鍾以后再出現之前丟失的畫面和聲音,這恐怕是很難接受的。
另外,QQ應該是優先采用UDP協議,如果不通的話會自動轉為TCP
如果說不用TCP是效率方面使用不方便的話。當年馬化騰想4000元把QQ賣掉,難道當初開發的開始的時候還會想到有億級的用戶?
網站HTTP那么多用戶,不也基於TCP協議?
說什么兩個客戶端之間用UDP通信來解決兩個局域網內的用戶連接的話,那真是。。。。
曾經,或許是,但現在絕對不是,難道QQ如今發送消息是兩個客戶端直接發的?不需要QQ服務器的中轉,監控,屏蔽?
用udp的原因:
1 節省創業成本。udp比tcp開銷少,意味着一台服務器能服務的用戶更多,並且用udp更容易普遍使用p2p,不用服務器中轉,更是大大節省中央服務器的開銷。
2 靈活。形象的說,tcp就是在udp基礎上實現的一套用起來更簡單更傻瓜的協議。用更底層的方式可以構建更高效靈活並符合自己需求的協議,當然是更優的,但提高了開發成本,最基本的,離開局域網后udp丟包概率大,收到包時候的次序可能都是亂的,包括對方還有沒有網絡,這些全都需要自己去維護,而tcp的數據准確性那都是tcp協議就幫程序員維護好的,對方斷線你就知道收到通知了。
3 udp打洞能更容易在不同品牌型號的路由情況下實現p2p,無論聊天文本、語音視頻、文件收發都可以實現,對upnp等的支持,很多年了路由器都沒有統一,但udp打洞來實現p2p基本上都沒問題。
4 后來隨着得到投資,以及盈利增加,資金實力強了,服務器成本不再是大問題,才逐步增加了不同功能中tcp的使用比例,這都是后來的事了。
QQ最早為什么使用UDP我不知道,我猜測是開發者偷懶,用UDP發包收包多簡單啊,早期也沒有丟包重傳(據說后面被投訴多了,才在應用層上加了丟包重傳)。
至於上面有回答說,用UDP模擬實現了TCP的功能,就現在的情況我可以說,是沒有的。
目前都是在應用層實現丟包重傳(1秒間隔,最多n次重傳),因為這個導致業務服務器都需要做去重與重傳,負擔很重。
mac os
$ lsof -i -n |grep -i qq QQPlatfor 555 **** 15u IPv4 0xe36af4996ef57975 0t0 TCP *:49969 (LISTEN) QQPlatfor 555 **** 18u IPv4 0xe36af4996ef567d5 0t0 TCP 127.0.0.1:49969->127.0.0.1:49242 (ESTABLISHED) QQPlatfor 555 **** 19u IPv4 0xe36af49973dd9975 0t0 TCP 127.0.0.1:49969->127.0.0.1:49586 (ESTABLISHED) QQ 5910 **** 21u IPv4 0xe36af49974edb2c5 0t0 UDP 127.0.0.1:5800 QQ 5910 **** 24u IPv4 0xe36af49982299245 0t0 TCP 192.168.0.107:63614->183.60.49.182:https (ESTABLISHED) QQ 5910 **** 33u IPv4 0xe36af49976641635 0t0 TCP 127.0.0.1:49586->127.0.0.1:49969 (ESTABLISHED) QQ 5910 **** 44u IPv4 0xe36af49980abf3e5 0t0 TCP 10.20.156.64:60963->59.37.109.170:http-alt (CLOSE_WAIT) QQ 5910 **** 45u IPv4 0xe36af49982021975 0t0 TCP 192.168.0.107:63989->59.37.108.45:http-alt (CLOSE_WAIT) QQ 5910 **** 46u IPv4 0xe36af4997202db15 0t0 TCP 10.20.156.64:61282->59.37.108.42:http-alt (CLOSE_WAIT) QQ 5910 **** 48u IPv4 0xe36af499816e8245 0t0 TCP 10.20.156.64:61283->14.215.154.175:http-alt (CLOSE_WAIT)
TCP或HTTP理論上是可靠連接,但是在網絡不好的時候,其實根本不可靠。反而程序員會因為TCP理論上的可靠而不去做底層的重發機制。
那么在網絡不好時,用TCP和UDP的區別僅僅是,程序員會收到一個TCP錯誤,用UDP則會在沉默中丟失數據。
但是如果程序員不手動處理TCP錯誤,只是“鐺”的彈個對話框,把錯誤報告給用戶,那么其實對用戶來說一點用都沒有。
另一方面,要想在上層手動處理TCP錯誤,根本做不到嘛。因為應用層重發請求常常導致服務器重復多次處理相同請求的bug。
我們可以看到,網絡卡的時候,或者電信網通互相訪問的時候,玩個游戲就會頻繁掉線。這表現出TCP不適應中國國情。
具體的說,TCP丟包時會退避,然后就會超時。但是,在中國丟包往往是因為ISP的路由器丟你的包,而不是你本地帶寬不足。對於ISP這種行為,對用戶最有利的解決辦法應該是暴力重發,搶占更多帶寬,而不是主動退避嘛。
TCP是個爛協議,基本上是人盡皆知的常識。我建議能夠選擇自定義協議的場合,盡量改用谷歌的QUIC代替TCP協議。
那么,不得不使用TCP怎么辦呢?
我在前東家做網頁游戲時,Flash Player只支持TCP。我的辦法是,每隔一兩秒就發一個心跳包,對端只要收不到心跳包就暴力建立新TCP連接,而不是文質彬彬去退避。我把這個做法稱為BCP(Brutal Control Protocol,殘暴控制協議):
歡迎使用!
2、由於采用P2P的方式進行通信,服務器只是匯總在線信息,而P2P要考慮兩個內網穿透的問題,那么TCP就不合適了,所以選用UDP協議的原因是為了內網通信穿透的考慮。
例如:
A在某個內網,B在某個內網,兩者進行相連通信的話,只能用UDP實現了。
而MSN之類的非P2P的,就是通過A和B都連接到MSN的服務器,再由MSN的服務器進行中轉來實現。