這篇文章是一篇關於pbft算法實現的一篇補充文章,可是在這裏不會涉及pbft的算法方面,因此能夠當作一篇單獨的文章食用。若是想查看關於區塊鏈或者PBFT算法的文章,能夠參考一下個人文章。html
這篇文章是構建一個p2p網絡,須要擁有獨立的ip地址(固然若是是在局域網內使用就無所謂了),不會涉及到內網穿透的一些實現方法,也就是說若是你是把本身電腦構建了一個p2p結點,則其餘人的電腦是沒法連接你電腦的結點的。java
p2p網絡中,一個結點既是客戶端也是服務端,能夠實現任意時刻的雙向的通訊。所以在每一個結點中,會維護一張客戶端的表和一張服務端的表。咱們能夠從代碼的方面來理解一下這個東西,以下圖所示:git
兩個被方框圈住的表則是須要維護的表,若是在代碼中的話,咱們就可使用List去保存這張表github
客戶端的表咱們能夠用來發送消息,而服務端的表咱們能夠用來控制羣發。web
這裏咱們能夠解釋和理解一下何爲p2p。舉例:算法
結點1想與結點2進行通訊時:A1跑出來講,我有到結點2的通道,而後向結點2發出request
,結點2的服務端接收到結點1(A1)發出來的消息的時,進行response。websocket
這個時候,可能就會有人問:爲何不是結點1的服務端向結點2發出request呢,而後結點2再向服務端返回response?yes,這個是能夠的,而且可以成功。那是否是意味着客戶端的表實際上能夠不要?固然不是!!!
首先咱們從哲學的角度理解這個東西,request理所固然應該是client發出來的,response也應當是response發出來的。固然,這個徹底是扯蛋。在兩個結點中,一個當作server一個當作client,這樣確實不會出現問題,當時若是是3個節點呢?這樣作能不能實現兩兩單獨
發送呢?很抱歉,不能。(注意,在這裏是兩個結點直接進行request和response,而不借助其餘結點)。網絡
下面這種模式是一個結點只爲Server,另外的幾個也只爲Client。在這種模式中,C1和其餘的結點沒法獨自進行兩兩通訊,必須藉助Server來進行通訊。
框架
OK,說了這麼多,那麼如今讓咱們來進行構建P2P網絡socket
在這裏,我將使用maven構建項目,下面是須要使用的工具類:
項目地址:github
代碼其實沒什麼好講的,主要是不熟悉tio的使用,這裏,emm,吐槽一下tio,媽耶,文檔也太貴了吧(╮(╯▽╰)╭,學生優惠沒有了,哭唧唧)。
代碼其實很簡單,就是開上幾個server,而後client鏈接Server就好了。
主要代碼以下所示(實際上使用什麼框架都行,本身喜歡就行,把思路弄好就能夠了):
public static void main(String[] args) { Scanner in = new Scanner(System.in); String ip = "127.0.0.1"; // 服務端開始 System.out.println("請輸入服務端初始化端口:"); int port = in.nextInt(); // 處理消息handler ServerAioHandler handler = new P2PServerAioHandler(); // 監聽 ServerAioListener listener = new ServerListener(); // 配置 ServerTioConfig config = new ServerTioConfig("服務端", handler, listener); // 設置timeout config.setHeartbeatTimeout(Const.TIMEOUT *2); TioServer tioServer = new TioServer(config); try { // 啓動 tioServer.start(ip, port); } catch (IOException e) { System.out.println("啓動錯誤:" + e.getMessage()); } // client開始 ClientChannelContext[] contexts = new ClientChannelContext[3]; for (int i = 0; i < 3; i++) { // client的handler ClientAioHandler clientAioHandler = new P2pClientAioHandler(); // client 的配置 ClientTioConfig clientTioConfig = new ClientTioConfig(clientAioHandler, new P2PClientLinstener(),new ReconnConf(Const.TIMEOUT)); clientTioConfig.setHeartbeatTimeout(Const.TIMEOUT); ClientChannelContext context; try { TioClient client = new TioClient(clientTioConfig); System.out.println("輸入端口:"); int serverPort = in.nextInt(); context = client.connect(new Node(ip, serverPort), Const.TIMEOUT); contexts[i] = context; } catch (Exception e) { System.out.println("客戶端啓動錯誤:" + e.getMessage()); } } while (true) { System.out.println("請輸入發送的服務端的index"); int index = in.nextInt(); System.out.println("請輸入發送的內容"); String body = in.next(); try { MsgPacket msgPacket = new MsgPacket(); msgPacket.setBody("測試數據".getBytes(MsgPacket.CHARSET)); Tio.send(contexts[index], msgPacket); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }
思路:
思路仍是蠻簡單的,先進行server建立,並對他進行配置(配置它的消息處理方式和一些超時屬性等等),在tio中,server會在後臺(也就是P2PServerAioHandler這個類)接受並處理消息。而後是配置client,一樣配置一些Handler和timeout等等。在這裏我使用了ClientChannelContext[] contexts = new ClientChannelContext[3]
來保存client。ClientChannelContext能夠理解爲client到server的一根管道,經過他咱們能夠來控制消息的發送。
項目地址:GitHub
原文出處:https://www.cnblogs.com/xiaohuiduan/p/12302024.html