t-io Java構建p2p網絡


Java 構建p2p網絡

這篇文章是一篇關於pbft算法實現的一篇補充文章,但是在這里不會涉及pbft的算法方面,所以可以當做一篇單獨的文章食用。如果想查看關於區塊鏈或者PBFT算法的文章,可以參考一下我的文章

文章實現范圍

這篇文章是構建一個p2p網絡,需要擁有獨立的ip地址(當然如果是在局域網內使用就無所謂了),不會涉及到內網穿透的一些實現方法,也就是說如果你是把自己電腦構建了一個p2p結點,則其他人的電腦是無法鏈接你電腦的結點的。

預備知識

p2p網絡中,一個結點既是客戶端也是服務端,可以實現任意時刻的雙向的通信。因此在每個結點中,會維護一張客戶端的表和一張服務端的表。我們可以從代碼的方面來理解一下這個東西,如下圖所示:


兩個被方框圈住的表則是需要維護的表,如果在代碼中的話,我們就可以使用List去保存這張表

客戶端的表我們可以用來發送消息,而服務端的表我們可以用來控制群發。

這里我們可以解釋和理解一下何為p2p。舉例:

結點1想與結點2進行通信時:A1跑出來說,我有到結點2的通道,然后向結點2發出request,結點2的服務端接收到結點1(A1)發出來的消息的時,進行response。

這個時候,可能就會有人問:為什么不是結點1的服務端向結點2發出request呢,然后結點2再向服務端返回response?yes,這個是可以的,並且能夠成功。那是不是意味着客戶端的表實際上可以不要?當然不是!!!首先我們從哲學的角度理解這個東西,request理所當然應該是client發出來的,response也應當是response發出來的。當然,這個完全是扯蛋。在兩個結點中,一個當做server一個當做client,這樣確實不會出現問題,當時如果是3個節點呢?這樣做能不能實現兩兩單獨發送呢?很抱歉,不能。(注意,在這里是兩個結點直接進行request和response,而不借助其他結點)。

下面這種模式是一個結點只為Server,另外的幾個也只為Client。在這種模式中,C1和其他的結點無法獨自進行兩兩通信,必須借助Server來進行通信。

OK,說了這么多,那么現在讓我們來進行構建P2P網絡

Java構建項目

在這里,我將使用maven構建項目,下面是需要使用的工具類:

  • t-io:進行Socket通信。當然,t-io不是必須的,使用websocket或者netty都是可以的

項目地址: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM