NO IMAGE

開發分為兩個部分,part A:LSP(Live Sequence Protocol)的開發 , part B:Distributed Bitcoin Miner

文件位置:https://github.com/modiziri/p1

正文:

【首先要說一下低階網路協議,之所以稱之為低階是因為這種IP只能提供不可靠的資料傳遞服務,也就是說,這種簡單的資料傳輸很容易導致延遲,丟包和重複。而且,還有最大位元組的限制。不過,值得慶幸的是,低於1500位元組的傳輸還是相對很安全的,不過要是超過,那就很容易發生上面的問題了。

幾乎沒有應用程式會直接用IP來傳輸資料,相應的,他們會用UDP和TCP代替。

UDP:也就是USER DATAGRAM PROTOCOL,使用者資料包協議。這同樣也是不可靠的資料服務,不過允許資料包在同一臺電腦的不同終端通過埠傳輸。也就是說,一臺電腦就可以執行多個客戶端或者服務端了,這項技術叫做多路發訊。

TCP:也就是Transmission Control Protocol,傳輸控制協議。不同於UDP,這項protocol提供的是可靠的有序的流服務。實現方式是,固定長度的一段流資料被分散到不同的資料包傳輸,到了終端之後再重新組合。TCP會處理好丟包和重包而且阻止sender在發包時覆蓋掉一些資料(多數是後包覆蓋前包),both in 頻寬和緩衝區終端。

 

不過我們這次要做的是LSP(Live Sequence Protocol),與上面兩者既有相同又有不同。

特色:不同於UDP和TCP,LSP是有客戶-終端交流模板的,可以省下許多工程量

而且這項服務是連線一堆客戶端的(這裡終於可以看出挖礦機的苗頭了),而且給每個客戶端都有一個專屬的連線ID。

每個方向的客戶端與服務端連線都是靠一序列的離散(不連續的)資料,也就是說,很難甚至無法破譯。

資料大小被限制在了類似UDP資料包的大小,大概1000位元組左右。

資料傳輸絕對可靠,每個資訊都只能被接受一次並且一定要按照傳送的順序。

客戶端和伺服器是有連線監控的,如果其中一方斷線了會被馬上發現。(再次加上安全度)

 

 

LSP傳輸資料:一般每次傳輸都會包含以下四個資料:

Message Type:只能是以下三種型別

Connect:客戶端建立與伺服器的連線

Data:由客戶端或者伺服器傳送資訊

Ack: 由客戶端或者伺服器建立去獲取connect或者Data(小知識,人家建立了是放在公處你還沒拿到,你要去ack人家才會給你的,跟github上的ADD 與commit關係很像)

Connection ID:一般為非零正數用來區分客戶端-伺服器的連線

Sequence Number:同一條連線在傳輸多個資料時需要用到遞增的佇列數字,用來區別順序,0代表初始請求

Payload:負載,表示可以傳輸的上限,一般為一串位元組,格式由應用軟體決定。(可以自己決定要傳多少)

 

 

以上的資料可以由下面的格式來傳送:

(connect,0, 0):連線請求,前面那個0是連線ID,後面那個0是佇列號(建立連線一般兩個都為0)

(Data,id, sn, D):表示要傳輸資料,id是連線的ID,sn是佇列號,D是payload負載。

(Ack,id, sn): 獲取資料或者連線,id,sn意思同上,若同時為0自然就是獲取連線了。

 

 

下面我講一步步的講述整個連線的過程:

建立連線:在資料傳輸之前,連線必須被建立。連線通常都是由客戶端給伺服器傳送請求的。作為迴應,伺服器會生成並且分配一個唯一的連線ID給這個新的連線,然後就把這個ID連同佇列號0,負載nil(即0),打包傳送給客戶端作為接受訊號。也就是簡單的(connect,0,0)之後客戶端給一個(ack,id,0)

這個連線ID是沒有硬性要求的,而這個專案我們簡單地把開始ID定為1.

 

傳送接收訊號:當連線被建立,資訊就可以從兩端相互傳送了,正如前面說的,是雜湊的佇列資料資訊。假設所有資訊都是合法的,這種情況下客戶端和伺服器都有自己的一套識別佇列的序號,這樣就能區分到底是誰給誰發資訊了。這樣有什麼好處呢?首先,伺服器和客戶端互相發訊號是非同步的,極有可能你還在等待驗證,你就要再發一個了,或者你還沒接受完這個訊號,下一個又來了。這種情況,同步的佇列序號根本無法處理。另外,還有可能你先發的訊號還沒後發的訊號快,也就是後來先至,這個時候要是沒有序列你就亂套了。

 

跟TCP很像,LSP包含一個滑動視窗協議(sliding window protocol)。這個名詞是直譯的,有點彆扭,到底是什麼東西呢,其實就是一個類似於傳輸上限的東西。(個人認為這個名字起得糟透了。。。)形象地說,這個協議就是設立傳輸中的訊號上限。因為我們知道,客戶端與伺服器的傳輸必須是一問一答,有來有往的。所以要是去了還沒回來的訊號肯定是還在路上,還沒處理完或者出問題了(這種情況現在不作考慮)。那我們設立傳輸上限就可以最大程度讓通訊整整有條了,假設設立通訊上限a
= 1,那麼第一個出去了,在還沒收到迴應之前第二個就不能出去,如果a = 2,那麼出去兩個訊號,如果不回來迴應,第三個就不能傳送。

當然了,這種傳送是要按照佇列序號的,不可能序列是3的比序列是1的先處理,一定會按順序來。也就是說一旦有一個訊號(假設是n)卡住了,那麼最大的傳輸限度就是n a – 1.

 

那卡主了是不是就這樣結束了呢?其實並不是,如果卡主了埠會自動隔一段時間再次傳送,當然如果還是卡主了,還是會繼續傳送的,不過就只能繼續卡了。。。這個滑動視窗協議是客戶端和伺服器都會用到的,很常見。

 

 

下面要講的是一個突破性的優化:

隊伍序列傳輸法雖然保證了傳輸的安全性,不會丟包不會重發。但是同時也有問題,要是發生了丟包或者其他故障,那麼客戶端,伺服器或者兩者同時就停止工作了——都在等那個丟的包。

 

要使LSP更加funtional and robust,我們就要用到下面的這個方法了。

我們首先給客戶端和伺服器都建立一個簡單的時間觸發器,這個定時器會定期開始工作,把時間切割成一個佇列的時間點。這裡我們姑且認為時間是有時間點和時間段組成的,設定時間點的個數為b, 我們預設為2000微秒,雖然這個量是會變化的。

 

一旦時間點開始數,那麼客戶端就會做下面的事情:

 

1,  如果連線請求沒有被伺服器迴應,那麼就再發一次時間請求

2,  如果連線請求被髮送並且被迴應,但是沒有資料(data)被接收,那就傳送佇列0的迴應(解釋:如果伺服器已經發出連線回應了還沒有收到資料只有兩個可能,一個是根本沒有資料,這個當然沒有問題,另外一個就是迴應丟包了。這種情況下我們再次傳送佇列0,也就是connect的迴應可以防止丟包終止程式了)

3,每個已經發出但是沒有迴應的資料資訊都會再次傳送。

4,如果卡主了,再次傳送最後a(剛才定義的傳輸上限)個資料包的迴應,注意,只發迴應。

 

而伺服器也會設立一個類似的一些關於連線的機制:

 

1,如果一直收不到客戶端的資料,那就再把連線請求的迴應再發一次。

2,每個傳送的資料如果得不到迴應就再把資料發一次。

3,如果卡主了,再次傳送最後a(剛才定義的傳輸上限)個資料包的迴應,只發迴應。

 

剛才說時間觸發器還不是很清楚,我們就舉個例子好了。假如客戶端想要傳送第i個資料,但是迴應檔案丟包(這是伺服器的問題)。同時,伺服器也想發第j個資料,但是本身檔案丟包,發不出去,跟上面不同,這也是伺服器的問題。但是,這時的時間觸發器時間點在客戶端上,那麼觸發器就會傳送第j – 1個包的迴應,注意,這時觸發器在客戶端上,所以只能傳送j而不是i的迴應。這時伺服器就能接到迴應,同時客戶端也會再次傳送資料i的包。

如果這時時間觸發器的點也在伺服器的話,注意,前面也說過伺服器跟客戶端是非同步的,所以兩個觸發器極有可能會發現同時的情況。也就是兩邊都出現問題但是兩邊同時解決(跟先後解決是有區別的,自己衡量一下),這時伺服器的解決辦法是,把i的迴應再發一遍,然後重發j的資料包。仔細看看,其實兩者都能解決問題,而且都在解決同一個問題。

 

而且上面的例子驗證並且舉出了一種會重包的情況,上面的同時解決其實就是一種重包錯誤。在大多情況下,佇列序號在這裡就能起作用了,每個埠都會有一個計數器來計算並且區分這次要進來的包的序列號,然後拋棄那些對不上號的。這裡講一個重複請求的例子,對於客戶端來說,很有可能會重複傳送連線請求的。這時,伺服器必須跟蹤主地址,記錄每個連線請求的號碼,然後拋棄所有的那些號碼已經被建立連線的和主機被聯合的。

 

之前就講過時間點觸發器,那麼這個時間點是怎麼定義的呢。一般我們都會這樣設計,每個時間點都會最少有一個資料在傳輸中。還有一個重要特徵,我們會追蹤每個連線,在到最後時間點之前,從這頭資訊傳遞到那頭(已經被那頭接收,且不算迴應)之後消耗的時間點(也就是無效時間點)。一旦這個花費超過了一個特殊的時間上限,這裡定義為k,我們就會認定,連線已經丟失了。我們實施的時候預設k的值為5,所以,如果有一個已經建立後的埠在 k*b 的時間段裡一直沒有接收到東西,那麼我們就可以認定這個連線已經丟失了。提示,這裡的b在上文定義為時間點的時間間隔,預設為2000微秒。

 

(未完待續)