準備工作:
go語言中Channels的用法:在不同的Goroutine中運行的函數之間傳遞數據,可以使用Channel也稱為通道。(Goroutine是協程,和線程類似,共享堆,不共享棧,協程的切換一般由程序員在代碼中顯式控制)
關鍵字“go”。使用這個關鍵字使一個函數被併發的執行,如:
go func() { fmt.Println("666") }()
思路整理
首先明確一下我們期待的網絡通信是什麼樣子的,簡單點說就是單個節點能接收外部傳來的數據並能改變內部數據的狀態,又能將內部數據的最新狀態廣播出去,外部的其它節點都能收到廣播的這樣一個網絡。下面我們具體拆分一下需要實現哪些功能:(我們用一臺電腦上開多個終端來模擬多個節點)
接收處理其它節點廣播信息
更新本節點區塊數據
向其它節點發廣播
需要一個變量來存放全網的公鏈 bcServer = make(chan []Block) //chan是表示Channels
通過開啟一個定時器進行廣播
開啟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)
}
接收處理其它節點廣播信息:
這個併發的函數中做了四個事情:
通過scanner掃描,持續接受TCP中發來的數據,
拿接受到的數據去創建新的區塊
檢查區塊是否有效並更新本節點區塊數據
把本地的鏈指給公鏈
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
閱讀更多 5分鐘機器學習 的文章