年輕人的第一個區塊鏈項目--完結篇

準備工作:

  1. go語言中Channels的用法:在不同的Goroutine中運行的函數之間傳遞數據,可以使用Channel也稱為通道。(Goroutine是協程,和線程類似,共享堆,不共享棧,協程的切換一般由程序員在代碼中顯式控制)

  2. 關鍵字“go”。使用這個關鍵字使一個函數被併發的執行,如:

go func() { fmt.Println("666") }()

思路整理

首先明確一下我們期待的網絡通信是什麼樣子的,簡單點說就是單個節點能接收外部傳來的數據並能改變內部數據的狀態,又能將內部數據的最新狀態廣播出去,外部的其它節點都能收到廣播的這樣一個網絡。下面我們具體拆分一下需要實現哪些功能:(我們用一臺電腦上開多個終端來模擬多個節點)

  1. 接收處理其它節點廣播信息

  2. 更新本節點區塊數據

  3. 向其它節點發廣播

  4. 需要一個變量來存放全網的公鏈 bcServer = make(chan []Block) //chan是表示Channels

  5. 通過開啟一個定時器進行廣播

  6. 開啟TCP服務監聽端口,看是否有其它節點向這個端口發消息

開啟監聽:

監聽9000端口,如果有消息通過9000端口傳過來,則接受消息,並交給handleConn這個函數去處理

server, err := net.Listen("tcp", ":9000")

if err != nil {

log.Fatal(err)

}

defer server.Close()

for {

conn, err := server.Accept()

if err != nil {

log.Fatal(err)

}

go handleConn(conn)

}

接收處理其它節點廣播信息:

這個併發的函數中做了四個事情:

  1. 通過scanner掃描,持續接受TCP中發來的數據,

  2. 拿接受到的數據去創建新的區塊

  3. 檢查區塊是否有效並更新本節點區塊數據

  4. 把本地的鏈指給公鏈

go func() {

for scanner.Scan() {

content := scanner.Text()

newBlock, err := generateBlock(Blockchain[len(Blockchain)-1], string(content))

if err != nil {

log.Println(err)

continue

}

if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) {

newBlockchain := append(Blockchain, newBlock)

replaceChain(newBlockchain)

}

bcServer

io.WriteString(conn, "\\n請輸入任意內容:")

}

}()

定時器進行廣播

把本地鏈數據轉成json然後廣播,mutex是互斥鎖。

go func() {

for {

time.Sleep(30 * time.Second)

mutex.Lock()

output, err := json.Marshal(Blockchain)

if err != nil {

log.Fatal(err)

}

mutex.Unlock()

io.WriteString(conn, string(output))

}

}()

for _ = range bcServer {

spew.Dump(Blockchain)

}

好的,完成代碼在:https://github.com/sunqichao/blockchainNetwork ,我們現在運行一下 go run main.go 然後再開啟一個終端用 nc localhost 9000 這個命令來連接,如圖:

年輕人的第一個區塊鏈項目--完結篇

過了30秒之後,收到廣播,每個終端都輸出了json數據,如圖:

年輕人的第一個區塊鏈項目--完結篇

總結:

介紹了各個節點之間的通信,接收信息,廣播信息。基本的網絡通信功能有了,這時同學可以嘗試把之前講的POW工作證明的共識算法加入進來,合併一下會更加完整,可以參考比特幣的源碼,地址:https://github.com/bitcoin/bitcoin

參考:https://medium.com/@mycoralhealth/code-your-own-blockchain-in-less-than-200-lines-of-go-e296282bcffc


分享到:


相關文章: