Android上kcp協議使用初探

byteli發表於2019-03-19

最近公司要求針對上傳下載提速,打算採用kcp協議進行底層改造,於是對kcp進行了一些調研。

KCP是一個快速可靠協議,能以比 TCP浪費10%-20%的頻寬的代價,換取平均延遲降低 30%-40%,且最大延遲降低三倍的傳輸效果。純演算法實現,並不負責底層協議(如UDP)的收發,需要使用者自己定義下層資料包的傳送方式,以 callback的方式提供給 KCP。 連時鐘都需要外部傳遞進來,內部不會有任何一次系統呼叫。

以上片段來自skywind3000/kcp 對kcp的介紹。而這裡對kcp也不再展開,kcp的具體介紹還是大家自行搜尋理解比較好。

而目前比較成熟完備的解決方案是kcptun,目前在Github上有9.8K star。 kcptun在kcp協議的基礎上,做了很多優化,包括向前就錯(FEC),差異化服務或(DSCP),加解密,壓縮。 接下來,我將會以Android開發者的角度講述kcptun移植到Android端的過程,預設讀者已經配置好Android開發環境,因此不再贅述。

kcptun原理

第一步 Go環境準備

kcptun本身是個Go專案,而Go專案本身是支援移植到Android或iOS客戶端作為第三方庫使用的。像我一樣的Go小白可以先看一下這篇文章:使用 Go 進行 iOS 和 Android 程式設計 已翻譯 100%

1.Go語言環境安裝

請參考:菜鳥教程,記得將go配置到環境變數中方便使用。

2.GoMobile工具安裝

GoMobile工具用於編譯和執行 Android 和 iOS 的應用。 注意⚠️ 該工具下載可能需要科學上網,包括編譯kcptun過程一些依賴庫也是需要科學上網的。如果沒有梯子建議使用國內映象。請參考:國內的go get問題的解決

第二步 Go專案編譯

在真正編譯kcptun之前,可以使用命令列先編譯一下最簡單的 hello專案來確認環境已經全部安裝好。 筆者go的安裝目錄為 /usr/local/go,在安裝好gomobile之後,在/usr/local/go/src/golang.org/x/mobile/example/目錄下會有幾個例子工程,現在對example下的bind專案開始編譯。進入到/usr/local/go/src/golang.org/x/mobile/example/bind/hello目錄下編譯hello.go檔案。 使用gomobile bind -target=android即可,編譯成功會在hello.go所在目錄生成兩個檔案。這兩個檔案我們就可以匯入到Android工程中使用

Android上kcp協議使用初探

下面開始真正編譯kcptun。

我們客戶端所需要的只是kcptun的client部分。現在kcptun,將kcptun下的client資料夾挪到/usr/local/go/src/golang.org/x/mobile/example/目錄下,我這裡將其重新命名為了kcp-client。在開始編譯之前我們需要對go原始碼進行一點小修改才能順利進行。

Android上kcp協議使用初探

修改kcp-client下的三個檔案,將程式碼中的package main改成別的包名,我這裡是改成了`package kcpclient,如圖:

enter description here

這是因為gomobile編譯的go檔案不允許使用package main。這三個檔案修改完成後還需對main.go這最後一點修改:

  • main方法改成名成:Runmain方法是啟動kcp client的唯一入口,將其改名成大寫字母開頭的方法才會暴露出來給Android端使用,否則是無法在Android端啟動kcp client的。
  • 在main.go預定義程式碼中加入一個配置路徑屬性CONFIGPATH,修改Run方法中程式碼片段,將其改為如下:
		if c.String("c") != "" {
			err := parseJSONConfig(&config, c.String("c"))
			checkError(err)
		}else if CONFIGPATH != "" {
			err := parseJSONConfig(&config, CONFIGPATH)
			checkError(err)
		}
複製程式碼

這裡加入了CONFIGPATH屬性,並且暴露給客戶端,可以在啟動kcp client前通過setCONFIGPATH方法,傳入配置的json檔案路徑,對kcp client進行自定義引數配置。具體完整的main.go見Github。

上面都準備好後開始真正編譯kcp client。 進入到kcp-client 所在目錄,執行gomobile bind -target=android命令,如果一切順利會在kcp-client 目錄下生成兩個編譯產物,如下圖,kcpclient.aar以及kcpclient-sources.jar

Android上kcp協議使用初探

ps.如果編譯過程中報錯缺少庫,99%都是因為牆的原因,自行翻牆或者使用國內映象下載。

移植Android端使用

加入kcp依賴

kcpclient.aarkcpclient-sources.jar一直到安卓工程中的libs目錄下,修改模組下的build.gradle檔案以保證kcpclient.aarkcpclient-sources.jar兩個庫能真正引用。

android {
	...
    repositories {
        flatDir {
            dirs 'libs', '../libs'
        }
    }
}

dependencies {
    implementation fileTree(include: '*.jar', dir: 'libs')
    implementation(name: 'kcpclient', ext: 'aar')
}
複製程式碼

啟動kcp client

啟動kcp client是個網路操作,所以要放到子執行緒進行操作。最簡單的做法是如下:

        new Thread() {
            @Override
            public void run() {
                super.run();
				//這裡設定自己的kcp client配置,也可不呼叫,使用預設配置
                Kcpclient.setCONFIGPATH("xxxx");
                Kcpclient.run();
            }
        }.start();
複製程式碼

設定應用層代理

從上面的kcptun原理可以看出,應用層資料先是使用TCP協議封裝,經過kcp client則轉換成了kcp協議。這裡面的轉換是通過本地代理完成的。這也是kcptun的優勢之一,無需改動原有的應用層實現,只需通過本地代理即可實現tcp->kcp的轉換。這裡以OkhttpClient為例,設定socks代理。

		final String hostName = "127.0.0.1";
		//kcp client config中設定的localaddr
        final int port = 12948;
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(hostName, port));
        builder.proxy(proxy);
        mOkHttpClient = builder.build();
複製程式碼

通過該方式建立OkHttpClient之後,請求會使用kcp協議進行請求了。

測試

為了測試kcptun移植後的可用性,需要先搭建一個kcptun server。kcptun server可以直接下載Github 上面的release版,根據對應的系統下載對應的版本。 我這裡使用的是mac,下載了kcptun-darwin-amd64。 下載完成後解壓,直接將server_darwin_amd64拖動命令後即可啟動kcp伺服器。如果需要自定義配置,使用命令server_darwin_amd64 -c 配置路徑即可。

其次,不論kcp client是自定義配置還是預設配置,kcp client的remoteaddr需要改成你電腦本機的IP,方便測試。

啟動伺服器後,還需要給伺服器設定socks 代理,保證請求能通。這裡以Charles為例。

charles socks代理設定

經過以上準備,kcptun就可以正常使用了。以前的請求方式不用做修改,只需保證三點即可:

  • 啟動kcp client&server成功,並且保證兩端配置對應,有問題請參考預設配置以及kcptun github的引數說明,記得kcp client的remoteaddr需要修改成你server端所在的ip。
  • 設定本地代理
  • 電腦需要設定socks代理,保證測試成功。

kcp client啟動成功如圖

通過kcptun代理,每次請求都會有如下日誌顯示,並且在chales可以看到請求的執行情況。

enter description here

總結

在經過上傳下載測試發現,在網路良好的條件下,使用kcp和不使用kcp,速度相差無幾,但是在網路不穩定時,通過kcp協議請求比不使用kcp會有較大的速度提升。但是使用kcp協議耗費流量增加非常明顯,流量增加可能會比不使用kcp增加30%~50%,這也是kcp協議本身決定的,這個無法避免,所以是否使用kcp這本身也是個平衡選擇,想要更快且適應不穩定的網路環境,kcp就是個比較好的選擇,例如遊戲,直播。 說了這麼多,對於kcp我自己的理解也十分有限,所以如有不足之處還請諒解指點。

相關文章