騰訊IVWEB團隊:WebRTC 點對點直播
WebRTC 全稱為:Web Real-Time Communication
。它是為了解決 Web 端無法捕獲音視訊的能力,並且提供了 peer-to-peer(就是瀏覽器間)的視訊互動。實際上,細分看來,它包含三個部分:
- MediaStream:捕獲音視訊流
- RTCPeerConnection:傳輸音視訊流(一般用在 peer-to-peer 的場景)
- RTCDataChannel: 用來上傳音視訊二進位制資料(一般用到流的上傳)
但通常,peer-to-peer 的場景實際上應用不大。對比與去年火起來的直播
業務,這應該才是 WebRTC 常常應用到的地方。那麼對應於 Web 直播來說,我們通常需要兩個端:
- 主播端:錄製並上傳視訊
- 觀眾端:下載並觀看視訊
這裡,我就不談觀眾端了,後面另寫一篇文章介紹(因為,這是在是太多了)。這裡,主要談一下會用到 WebRTC 的主播端。
簡化一下,主播端應用技術簡單可以分為:錄製視訊,上傳視訊。大家先記住這兩個目標,後面我們會通過 WebRTC 來實現這兩個目標。
WebRTC 基本瞭解
WebRTC 主要由兩個組織來制定。
- Web Real-Time Communications (WEBRTC) W3C 組織:定義瀏覽器 API
- Real-Time Communication in Web-browsers (RTCWEB) IETF 標準組織:定義其所需的協議,資料,安全性等手段。
當然,我們初級目標是先關心基本瀏覽器定義的 API 是啥?以及怎麼使用?
然後,後期目標是學習期內部的相關協議,資料格式等。這樣循序漸進來,比較適合我們的學習。
WebRTC 對於音視訊的處理,主要是交給 Audio/Vidoe Engineering 處理的。處理過程為:
- 音訊:通過物理裝置進行捕獲。然後開始進行
降噪
,消除迴音
,抖動/丟包隱藏
,編碼
。 - 視訊:通過物理裝置進行捕獲。然後開始進行
影象增強
,同步
,抖動/丟包隱藏
,編碼
。
最後通過 mediaStream Object 暴露給上層 API 使用。也就是說 mediaStream 是連線 WebRTC API 和底層物理流的中間層。所以,為了下面更好的理解,這裡我們先對 mediaStream 做一些簡單的介紹。
MediaStream
MS(MediaStream)是作為一個輔助物件存在的。它承載了音視訊流的篩選,錄製許可權的獲取等。MS 由兩部分構成: MediaStreamTrack 和 MediaStream。
- MediaStreamTrack 代表一種單型別資料流。如果你用過
會聲會影
的話,應該對軌道
這個詞不陌生。通俗來講,你可以認為兩者就是等價的。 - MediaStream 是一個完整的音視訊流。它可以包含 >=0 個
MediaStreamTrack
。它主要的作用就是確保幾個軌道是同時播放的。例如,聲音需要和視訊畫面同步。
這裡,我們不說太深,講講基本的 MediaStream
物件即可。通常,我們使用例項化一個 MS 物件,就可以得到一個物件。
// 裡面還需要傳遞 track,或者其他 stream 作為引數。
// 這裡只為演示方便
let ms = new MediaStream();
我們可以看一下 ms
上面帶有哪些物件屬性:
- active[boolean]:表示當前 ms 是否是活躍狀態(就是可播放狀態)。
- id[String]: 對當前的 ms 進行唯一標識。例如:"f61641ec-ee78-4317-9415-58acac066a4d"
- onactive: 當 active 為 true 時,觸發該事件
- onaddtrack: 當有新的 track 新增時,觸發該事件
- oninactive: 當 active 為 false 時,觸發該事件
- onremovetrack: 當有 track 移除時,觸發該事件
它的原型鏈上還掛在了其他方法,我挑幾個重要的說一下。
- clone(): 對當前的 ms 流克隆一份。該方法通常用於對該 ms 流有操作時,常常會用到。
前面說了,MS 還可以其他篩選的作用,那麼它是如何做到的呢?
在 MS 中,還有一個重要的概念叫做: Constraints
。它是用來規範當前採集的資料是否符合需要。因為,我們採集視訊時,不同的裝置有不同的引數設定。常用的為:
{
"audio": true, // 是否捕獲音訊
"video": { // 視訊相關設定
"width": {
"min": "381", // 當前視訊的最小寬度
"max": "640"
},
"height": {
"min": "200", // 最小高度
"max": "480"
},
"frameRate": {
"min": "28", // 最小幀率
"max": "10"
}
}
}
那我怎麼知道我的裝置支援的哪些屬性的調優呢?
這裡,可以直接使用 navigator.mediaDevices.getSupportedConstraints()
來獲取可以調優的相關屬性。不過,這一般是對 video 進行設定。瞭解了 MS 之後,我們就要開始真正接觸 WebRTC 的相關 API。我們先來看一下 WebRTC 基本API。
WebRTC 的常用 API 如下,不過由於瀏覽器的緣故,需要加上對應的 prefix:
W3C Standard Chrome Firefox
--------------------------------------------------------------
getUserMedia webkitGetUserMedia mozGetUserMedia
RTCPeerConnection webkitRTCPeerConnection RTCPeerConnection
RTCSessionDescription RTCSessionDescription RTCSessionDescription
RTCIceCandidate RTCIceCandidate RTCIceCandidate
不過,你可以簡單的使用下列的方法來解決。不過嫌麻煩的可以使用 adapter.js 來彌補
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia
這裡,我們循序漸進的來學習。如果想進行視訊的相關互動,首先應該是捕獲音視訊。
捕獲音視訊
在 WebRTC 中捕獲音視訊,只需要使用到一個 API,即,getUserMedia()
。程式碼其實很簡單:
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var constraints = { // 設定捕獲的音視訊設定
audio: false,
video: true
};
var video = document.querySelector('video');
function successCallback(stream) {
window.stream = stream; // 這就是上面提到的 mediaStream 例項
if (window.URL) {
video.src = window.URL.createObjectURL(stream); // 用來建立 video 可以播放的 src
} else {
video.src = stream;
}
}
function errorCallback(error) {
console.log('navigator.getUserMedia error: ', error);
}
// 這是 getUserMedia 的基本格式
navigator.getUserMedia(constraints, successCallback, errorCallback);
詳細 demo 可以參考:WebRTC。不過,上面的寫法比較古老,如果使用 Promise 來的話,getUserMedia 可以寫為:
navigator.mediaDevices.getUserMedia(constraints).
then(successCallback).catch(errorCallback);
上面的註釋大概已經說清楚基本的內容。需要提醒的是,你在捕獲視訊的同時,一定要清楚自己需要捕獲的相關引數。
有了自己的視訊之後,那如何與其他人共享這個視訊呢?(可以理解為直播的方式)
在 WebRTC 中,提供了 RTCPeerConnection
的方式,來幫助我們快速建立起連線。不過,這僅僅只是建立起 peer-to-peer 的中間一環。這裡包含了一些複雜的過程和額外的協議,我們一步一步的來看下。
WebRTC 基本內容
WebRTC 利用的是 UDP 方式來進行傳輸視訊包。這樣做的好處是延遲性低,不用過度關注包的順序。不過,UDP 僅僅只是作為一個傳輸層協議而已。WebRTC 還需要解決很多問題
- 遍歷 NATs 層,找到指定的 peer
- 雙方進行基本資訊的協商以便雙方都能正常播放視訊
- 在傳輸時,還需要保證資訊保安性
整個架構如下:
上面那些協議,例如,ICE/STUN/TURN 等,我們後面會慢慢講解。先來看一下,兩者是如何進行資訊協商的,通常這一階段,我們叫做 signaling
。
signaling 任務
signaling 實際上是一個協商過程。因為,兩端進不進行 WebRTC 視訊交流之間,需要知道一些基本資訊。
- 開啟/關閉連線的指令
- 視訊資訊,比如解碼器,解碼器的設定,頻寬,以及視訊的格式等。
- 關鍵資料,相當於 HTTPS 中的
master key
用來確保安全連線。 - 閘道器資訊,比如雙方的 IP,port
不過,signaling 這個過程並不是寫死的,即,不管你用哪種協議,只要能確保安全即可。為什麼呢?因為,不同的應用有著其本身最適合的協商方法。比如:
- 單閘道器協議(SIP/Jingle/ISUP)適用於呼叫機制(VoIP,voice over IP)。
- 自定義協議
- 多閘道器協議
我們自己也可以模擬出一個 signaling 通道。它的原理就是將資訊進行傳輸而已,通常為了方便,我們可以直接使用 socket.io 來建立 room
提供資訊交流的通道。
PeerConnection 的建立
假定,我們現在已經通過 socket.io
建立起了一個資訊交流的通道。那麼我們接下來就可以進入 RTCPeerConnection
一節,進行連線的建立。我們首先應該利用 signaling
進行基本資訊的交換。那這些資訊有哪些呢?
WebRTC 已經在底層幫我們做了這些事情-- Session Description Protocol (SDP)
。我們利用 signaling
傳遞相關的 SDP,來確保雙方都能正確匹配,底層引擎會自動解析 SDP (是 JSEP 幫的忙),而不需要我們手動進行解析,突然感覺世界好美妙。。。我們來看一下怎麼傳遞。
// 利用已經建立好的通道。
var signalingChannel = new SignalingChannel();
// 正式進入 RTC connection。這相當於建立了一個 peer 端。
var pc = new RTCPeerConnection({});
navigator.getUserMedia({ "audio": true })
.then(gotStream).catch(logError);
function gotStream(stream) {
pc.addStream(stream);
// 通過 createOffer 來生成本地的 SDP
pc.createOffer(function(offer) {
pc.setLocalDescription(offer);
signalingChannel.send(offer.sdp);
});
}
function logError() { ... }
那 SDP 的具體格式是啥呢?
看一下格式就 ok,這不用過多瞭解:
v=0
o=- 1029325693179593971 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:nHtT
a=ice-pwd:cuwglAha5fBmGljFXWntH1VN
a=fingerprint:sha-256 24:63:EB:DD:18:1B:BB:5E:B3:E8:C5:D7:92:F7:0B:44:EC:22:96:63:64:76:1A:56:64:DE:6B:CE:85:C6:64:78
a=setup:active
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=inactive
a=rtcp-mux
...
上面的過程,就是 peer-to-peer 的協商流程。這裡有兩個基本的概念,offer
,answer
。
- offer: 主播端向其他使用者提供其本省視訊直播的基本資訊
- answer: 使用者端反饋給主播端,檢查能否正常播放
具體過程為:
- 主播端通過 createOffer 生成 SDP 描述
- 主播通過 setLocalDescription,設定本地的描述資訊
- 主播將 offer SDP 傳送給使用者
- 使用者通過 setRemoteDescription,設定遠端的描述資訊
- 使用者通過 createAnswer 創建出自己的 SDP 描述
- 使用者通過 setLocalDescription,設定本地的描述資訊
- 使用者將 anwser SDP 傳送給主播
- 主播通過 setRemoteDescription,設定遠端的描述資訊。
不過,上面只是簡單確立了兩端的連線資訊而已,還沒有涉及到視訊資訊的傳輸,也就是說 UDP 傳輸。UDP 傳輸本來就是一個非常讓人蛋疼的活,如果是 client-server 的模型話還好,直接傳就可以了,但這偏偏是 peer-to-peer 的模型。想想,你現在是要把你的電腦當做一個伺服器使用,中間還需要經歷如果突破防火牆,如果找到埠,如何跨網段進行?所以,這裡我們就需要額外的協議,即,STUN/TURN/ICE ,來幫助我們完成這樣的傳輸任務。
NAT/STUN/TURN/ICE
在 UDP 傳輸中,我們不可避免的會遇見 NAT
(Network address translator)伺服器。即,它主要是將其它網段的訊息傳遞給它負責網段內的機器。不過,我們的 UDP 包在傳遞時,一般只會帶上 NAT 的 host
。如果,此時你沒有目標機器的 entry
的話,那麼該次
UDP 包將不會被轉發成功。不過,如果你是 client-server 的形式的話,就不會遇見這樣的問題。但,這裡我們是 peer-to-peer 的方式進行傳輸,無法避免的會遇見這樣的問題。
為了解決這樣的問題,我們就需要建立 end-to-end 的連線。那辦法是什麼呢?很簡單,就是在中間設立一個 server
用來保留目標機器在 NAT 中的 entry
。常用協議有 STUN, TURN 和 ICE
。那他們有什麼區別嗎?
- STUN:作為最基本的
NAT traversal
伺服器,保留指定機器的entry
- TURN:當 STUN 出錯的時候,作為重試伺服器的存在。
- ICE:在眾多 STUN + TURN 伺服器中,選擇最有效的傳遞通道。
所以,上面三者通常是結合在一起使用的。它們在 PeerConnection 中的角色如下圖:
如果,涉及到 ICE 的話,我們在例項化 Peer Connection 時,還需要預先設定好指定的 STUN/TRUN 伺服器。
var ice = {"iceServers": [
{"url": "stun:stun.l.google.com:19302"},
// TURN 一般需要自己去定義
{
'url': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'url': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]};
var signalingChannel = new SignalingChannel();
var pc = new RTCPeerConnection(ice); // 在例項化 Peer Connection 時完成。
navigator.getUserMedia({ "audio": true }, gotStream, logError);
function gotStream(stream) {
pc.addStream(stream); // 將流新增到 connection 中。
pc.createOffer(function(offer) {
pc.setLocalDescription(offer);
});
}
// 通過 ICE,監聽是否有使用者連線
pc.onicecandidate = function(evt) {
if (evt.target.iceGatheringState == "complete") {
local.createOffer(function(offer) {
console.log("Offer with ICE candidates: " + offer.sdp);
signalingChannel.send(offer.sdp);
});
}
}
...
在 ICE 處理中,裡面還分為 iceGatheringState
和 iceConnectionState
。在程式碼中反應的就是:
pc.onicecandidate = function(e) {
evt.target.iceGatheringState;
pc.iceGatheringState
};
pc.oniceconnectionstatechange = function(e) {
evt.target.iceConnectionState;
pc.iceConnectionState;
};
當然,起主要作用的還是 onicecandidate
。
- iceGatheringState: 用來檢測本地 candidate 的狀態。其有以下三種狀態:
- new: 該 candidate 剛剛被建立
- gathering: ICE 正在收集本地的 candidate
- complete: ICE 完成本地 candidate 的收集
- iceConnectionState: 用來檢測遠端 candidate 的狀態。遠端的狀態比較複雜,一共有 7 種: new/checking/connected/completed/failed/disconnected/closed
不過,這裡為了更好的講解 WebRTC 建立連線的基本過程。我們使用單頁的連線來模擬一下。現在假設,有兩個使用者,一個是 pc1,一個是 pc2。pc1 捕獲視訊,然後,pc2 建立與 pc1 的連線,完成偽直播的效果。直接看程式碼吧:
var servers = null;
// Add pc1 to global scope so it's accessible from the browser console
window.pc1 = pc1 = new RTCPeerConnection(servers);
// 監聽是否有新的 candidate 加入
pc1.onicecandidate = function(e) {
onIceCandidate(pc1, e);
};
// Add pc2 to global scope so it's accessible from the browser console
window.pc2 = pc2 = new RTCPeerConnection(servers);
pc2.onicecandidate = function(e) {
onIceCandidate(pc2, e);
};
pc1.oniceconnectionstatechange = function(e) {
onIceStateChange(pc1, e);
};
pc2.oniceconnectionstatechange = function(e) {
onIceStateChange(pc2, e);
};
// 一旦 candidate 新增成功,則將 stream 播放
pc2.onaddstream = gotRemoteStream;
// pc1 作為播放端,先將 stream 加入到 Connection 當中。
pc1.addStream(localStream);
pc1.createOffer(
offerOptions
).then(
onCreateOfferSuccess,
error
);
function onCreateOfferSuccess(desc) {
// desc 就是 sdp 的資料
pc1.setLocalDescription(desc).then(
function() {
onSetLocalSuccess(pc1);
},
onSetSessionDescriptionError
);
trace('pc2 setRemoteDescription start');
// 省去了 offer 的傳送通道
pc2.setRemoteDescription(desc).then(
function() {
onSetRemoteSuccess(pc2);
},
onSetSessionDescriptionError
);
trace('pc2 createAnswer start');
pc2.createAnswer().then(
onCreateAnswerSuccess,
onCreateSessionDescriptionError
);
}
看上面的程式碼,大家估計有點迷茫,來點實的,大家可以參考 單頁直播。在檢視該網頁的時候,可以開啟控制檯觀察具體進行的流程。會發現一個現象,即,onaddstream
會在 SDP
協商還未完成之前就已經開始,這也是,該
API 設計的一些不合理之處,所以,W3C 已經將該 API 移除標準。不過,對於目前來說,問題不大,因為僅僅只是作為演示使用。整個流程我們一步一步來講解下。
- pc1 createOffer start
- pc1 setLocalDescription start // pc1 的 SDP
- pc2 setRemoteDescription start // pc1 的 SDP
- pc2 createAnswer start
- pc1 setLocalDescription complete // pc1 的 SDP
- pc2 setRemoteDescription complete // pc1 的 SDP
- pc2 setLocalDescription start // pc2 的 SDP
- pc1 setRemoteDescription start // pc2 的 SDP
- pc2 received remote stream,此時,接收端已經可以播放視訊。接著,觸發 pc2 的 onaddstream 監聽事件。獲得遠端的 video stream,注意此時 pc2 的 SDP 協商還未完成。
- 此時,本地的 pc1 candidate 的狀態已經改變,觸發 pc1 onicecandidate。開始通過
pc2.addIceCandidate
方法將 pc1 新增進去。 - pc2 setLocalDescription complete // pc2 的 SDP
- pc1 setRemoteDescription complete // pc2 的 SDP
- pc1 addIceCandidate success。pc1 新增成功
- 觸發
oniceconnectionstatechange
檢查 pc1 遠端 candidate 的狀態。當為completed
狀態時,則會觸發 pc2onicecandidate
事件。 - pc2 addIceCandidate success。
此外,還有另外一個概念,RTCDataChannel
我這裡就不過多涉及了。如果有興趣的可以參閱 webrtc,web
效能優化 進行深入的學習。
相關推薦
騰訊IVWEB團隊:WebRTC 點對點直播
WebRTC 全稱為:Web Real-Time Communication。它是為了解決 Web 端無法捕獲音視訊的能力,並且提供了 peer-to-peer(就是瀏覽器間)的視訊互動。實際上,細分看來,它包含三個部分: MediaStream:捕獲音視訊流RTCPee
騰訊輿情團隊談:如何發現下一個現象級遊戲?
轟轟烈烈的 ChinaJoy 剛結束,各大遊戲廠商又投入了新一輪產品研發和優化。回顧ChinaJoy,最受玩家追捧的當屬目前最火爆的現象級遊戲 IP,如《魔獸世界》、《火影忍者手遊》、《冒險島 2》等,上海 40 度的高溫天也阻止不了玩家前往現場“朝聖”一把這些
騰訊課堂1:使用Jmeter內置的錄制功能進行錄制
bsp family logs -1 figure mil 宋體 報錯 conf 1、設置http代理服務器 打開火狐——點擊選項——高級——網絡——設置 設置完成點擊確定 2、查看端口是否被占用的命令 netstat -ano 3、排除模式 .*\.gif .*
分析比特幣網絡:一種去中心化、點對點的網絡架構
比特幣 區塊鏈 比特幣采用了基於互聯網的點對點(P2P:peer-to-peer)分布式網絡架構。比特幣網絡可以認為是按照比特幣P2P協議運行的一系列節點的集合。本文來分析下比特幣網絡,了解它跟傳統中心化網絡的區別,以及比特幣網絡是如何發現相鄰節點的。中心化網絡為了更好的理解P2P網絡,我們先來看看傳
比特幣:一種點對點的電子現金系統
三方 就是 金融 pap tps 重新 環境 coin 電子 摘要: 本文提出了一種完全通過點對點技術實現的電子現金系統,它使得在線支付能夠直接由一方發起並支付給另外一方,中間不需要通過任何的金融機構。雖然數字簽名部分解決了這個問題,但是如果仍然需要第三方的支
騰訊聶晶:數據資產助力企業發展
人工智 掌握 view 應用中心 內容整理 廣東省 層次 生成 大牛 歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐幹貨哦~ 演講人:聶晶 騰訊雲大數據應用產品總經理 背景:5月23-24日,以“煥啟”為主題的騰訊“雲+未來”峰會在廣州召開,廣東省各級政府機構領導、海
騰訊技術分享:GIF動圖技術詳解及手機QQ動態表情壓縮技術實踐
表示 pack iii 技巧總結 fff 設備 思路 表情包 作用 本文來自騰訊前端開發工程師“ wendygogogo”的技術分享,作者自評:“在Web前端摸爬滾打的碼農一枚,對技術充滿熱情的菜鳥,致力為手Q的建設添磚加瓦。” 1、GIF格式的歷史 GIF ( Graph
程式設計師跳槽到國企後,表示打死不去阿里騰訊,網友:請國企毀了我
作為程式設計師,是繼續在網際網路打拼,還是投入國企懷抱,這一直是個頗受爭議的話題。最近有位網友,就在社群裡發出了自己從網際網路創業公司,跳槽到國企後的感慨。他原本在一家創業公司做前端,每天被老闆嫌棄工作沒做好,加班不夠多,所以一怒之下,離職加入國企,沒想到,新工作不僅工作輕鬆,月薪也非常可觀,達到驚
騰訊朱華:資料中心下一個風向的探索
導讀:朱華,騰訊資料中心技術發展中心總監,中國工程建設標準化協會資料中心技術委員會副主任委員,中國通訊標準化協會開放資料中心委員會資料中心工作組組長,榮獲中國工程建設標準化協會頒發的2018資料中心青年科技人才獎。11月30日,朱華在2018資料中心年度峰會上發表了演講,以下為演講內容。
【AMQ】 二:點對點模式Dome
AMQ通訊分為兩種,一種是點對點模式,另一種是釋出訂閱模式,本文主要介紹點對點模式和簡單實現。 什麼是點對點模式? 點對點模式是AMQ的一種通過佇列方式通訊的模式, 即生產者會把生產的訊息放在某個佇列中,消費者從佇列中取得訊息進行通訊的方式。 基本實現: 生產者
webrtc 點對點會話建立過程分析
關於 webrtc 建立點對點連線的文章很多,其中都提到了如何利用 stun 伺服器獲取本機的公網地址,本文側重區域網(兩臺裝置之間可以直接 ping 通)下webrtc 點對點連線建立問題分析。 1.區域網內連線建立過程 瞭解過 webrtc 的都知道,要在公
騰訊雲安全:移動 APP 安全行業報告(轉)
移動 APP 已逐步滲透入我們的生活,據統計,2016年,APP 發行數量僅電商、金融、遊戲這三大類共計高達2萬左右,國內移動網際網路活躍使用者數已經突破10億,移動網際網路這樣快速的推移,移動網際網路的安全問題更為嚴峻,基於騰訊雲樂固和騰訊平臺的大資料分析, 整個移動應
訊息佇列模式:點對點 與 釋出訂閱
Java訊息服務(Java Message Service,JMS)應用程式介面是一個Java平臺中關於面向訊息中介軟體(MOM)的API,用於在兩個應用程式之間,或分散式系統中傳送訊息,進行非同步通訊。 點對點與釋出訂閱最初是由JMS定義的。這兩種模式主要區別或解決的問題
騰訊產品總監:我工作十年,內心仍無比恐慌
轉載地址:http://www.chinaz.com/manage/2015/1127/476037.shtml; 本文是曹菲在饅頭商學院發表的演講記錄,曹菲是騰訊產品研發中心總監 (騰訊,中國最大的網路公司,QQ 和微信都是它的)。 本文有相當程度的專業性,行外人不一定能夠咀嚼
專訪騰訊蔣傑:深度揭祕騰訊大資料平臺
大資料,這個詞越來越熱,很多人都在談大資料,其實很多張口閉口大資料的人,或許都不知道資料是如何產生、傳遞、儲存、運算到應用的。其實我一直感覺大資料這個東西有時候真的不是一般企業可以玩的溜的,特別是隨著傳統業務增長放緩,以及移動網際網路時代的精細化運營,對於大資料分析和挖掘
騰訊技術指南:H5同層播放器接入規範
(提示:該指南只適用騰訊系產品) H5同層播放器接入規範 x5-video-player-type 啟用H5同層播放器 通過video屬性“x5-video-player-type”宣告啟用同層H5播放器 x5-video-player-type支援的值型別:h5 示例: &
騰訊正式宣佈:1月1日起Web QQ正式下線,網友:別關閉QQ空間!
對我們這些90後、80後來說,QQ陪伴了我們數十年,從當時直板手機只能聊天和刷空間,到機房登入網頁QQ,再到現在人人手機電腦中都會會安裝的 軟體,QQ承載了我們太多的回憶。 而自從微信越來越普及,使用QQ的人越來越少了,主要都是學生,更別說網頁版了,也許現在已經有很多人都不知道QQ還有網頁
比特幣:一個點對點的電子現金系統
本文由我(samuel)基於2009年Satoshi Nakamoto(中本聰)的論文進行翻譯。之前看過別人寫的中文翻譯,總感覺有點晦澀。現在翻譯如下,如有問題,敬請諒解與批評指正!謝謝各位! 0 摘要(Abstract) 一個純粹p2p的電子現
Qt實用技巧:使用Qt給指定手機發送簡訊(點對點、群發等等)
需求 軟體控制簡訊提醒客戶驗證碼等等,如生日提醒、購買提醒、時間限制等等。Demo下載地址Demo效果截圖簡訊平臺介紹 軟體傳送簡訊需要第三方平臺支援,步驟如下: 1.註冊指定雲平臺賬戶,一般有免費簡訊條數,筆者使用“雲通知”;
轉:比特幣白皮書:一種點對點的電子現金系統
[摘要]:本文提出了一種完全通過點對點技術實現的電子現金系統,它使得線上支付能夠直接由一方發起並支付給另外一方,中間不需要通過任何的金融機構。雖然數字簽名(Digital signatures)部分解決了這個問題,但是如果仍然需要第三方的支援才能防止雙重支付