服務(wù)器將用戶(hù)的數(shù)據(jù)包進(jìn)行識(shí)別和區(qū)分

多線(xiàn)程優(yōu)化方案,主線(xiàn)程監(jiān)聽(tīng)在一個(gè)端口,并使用前面提到方案在服務(wù)器將用戶(hù)的數(shù)據(jù)包進(jìn)行識(shí)別和區(qū)分。
首先我們服務(wù)器端主線(xiàn)程會(huì)創(chuàng)建一個(gè)UDP的socket,綁定到7000端口,并注冊(cè)監(jiān)聽(tīng)可讀事件,WebRTC客戶(hù)端會(huì)給服務(wù)端7000端口發(fā)數(shù)據(jù)包。當(dāng)然在之前SDP和ICE Candidate的協(xié)商流程已經(jīng)做完了,我們從stun的第一個(gè)數(shù)據(jù)包(stun binding request)中就可以拿到這個(gè)WebRTC的web address(IP+端口)以及區(qū)分會(huì)議的RoomID和區(qū)分與會(huì)者的UserID。
拿到RoomID以后,我們可以把客戶(hù)端的web address和RoomID綁定,建立一個(gè)映射關(guān)系。為什么要做這個(gè)綁定關(guān)系?
這是為了后續(xù)我們可以把同一個(gè)會(huì)議的用戶(hù)全部投遞到一個(gè)業(yè)務(wù)邏輯處理線(xiàn)程來(lái)處理。如果用戶(hù)的數(shù)據(jù)是在不同邏輯處理線(xiàn)程上處理,我們?cè)谧鰯?shù)據(jù)處理的時(shí)候就要做跨線(xiàn)程的處理,跨線(xiàn)程處理就一定要加鎖,這是我們不太愿意看到的。
如果同一會(huì)議的用戶(hù)數(shù)據(jù)都在一個(gè)邏輯線(xiàn)程里面處理,其實(shí)它是在一個(gè)單線(xiàn)程里面的順序處理,沒(méi)有并發(fā)的問(wèn)題,也不需要加鎖,所以它的性能會(huì)比較高。
有了剛剛我們建立的映射關(guān)系,后續(xù)處理同一個(gè)會(huì)議的用戶(hù)上行的stun包、dtls、SRTP、SRTCP,我們都根據(jù)RoomID做同樣的Hash算法,Hash到我們后面的業(yè)務(wù)主線(xiàn)程里面,這樣每一次主線(xiàn)程把I/O做完后,一次性將主線(xiàn)程收到的各個(gè)數(shù)據(jù)包按照Hash算法投遞給對(duì)應(yīng)的后端的邏輯處理多線(xiàn)程,這樣同一個(gè)會(huì)議的SFU邏輯都在同一個(gè)線(xiàn)程里面處理完了。
這個(gè)是我們一開(kāi)始使用的方案,但是大家也能看到,這個(gè)方案還有一個(gè)缺陷,就是I/O都是在主線(xiàn)程做的,后續(xù)的數(shù)據(jù)都需要通過(guò)跨線(xiàn)程的投遞方式讓后續(xù)的邏輯處理現(xiàn)場(chǎng)來(lái)做,那么有沒(méi)有辦法不要做跨線(xiàn)程的投遞,讓用戶(hù)的數(shù)據(jù)包可以直接在對(duì)應(yīng)的邏輯處理多線(xiàn)程里面處理。

其實(shí)傳統(tǒng)的TCP服務(wù)器是比較容易做到的,它可以在主線(xiàn)程上Accept后為每個(gè)客戶(hù)端創(chuàng)建一些新的fd,并分配一個(gè)子線(xiàn)程處理這個(gè)新fd的讀寫(xiě)。那UDP能不能這么做?UDP在常規(guī)的編程方法是無(wú)法做到的,針對(duì)這個(gè)問(wèn)題,我們?cè)O(shè)計(jì)了一個(gè)進(jìn)階方案。