程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> RPC實現原理(HSF、dubbo) 從頭開始(一),hsfdubbo

RPC實現原理(HSF、dubbo) 從頭開始(一),hsfdubbo

編輯:JAVA綜合教程

RPC實現原理(HSF、dubbo) 從頭開始(一),hsfdubbo


前言

 

闊別了很久博客園,雖然看了以前寫的很多東西感覺好幼稚,但是還是覺得應該把一些自己覺得有用的東西和大家分享。廢話不多說,現在開始進入正題。

之前的六年工作經驗,呆過了一些大公司,每個在大公司呆過的人應該知道,在一個大型應用中不斷的增加業務和功能,還有基於性能的考慮,使得很多基礎服務必須進行模塊化,從而讓各子系統方便使用而不是每個系統重新再實現一套,也可以使可能成為瓶頸的基礎功能可以單獨進行擴展,比如(以電商系統舉例)用戶信息管理、交易管理中心、商品管理中心等等。  在rpc發展最初,服務進行模塊塊以後,各個子系統、模塊實現的技術五花八門,如:hessian、WebService、Socket、http等進行互相調用,各個子系統之間的交互方式和方法不統一,使得各系統間很難很好的整合。並且這些方式還涉及超時、加密解密、參數的傳遞等各種問題。  在這種情況下,hsf、dubbo這種高性能rpc中間件出現了。  現在我就已最簡單的方式從頭開始講起其中的原理。

我將分為一個系列為大家進行解剖

一、RPC實現原理(HSF、dubbo) 從頭開始(一)

二、RPC實現原理(HSF、dubbo)發布一個服務與訂閱一個服務(三)

三、RPC實現原理(HSF、dubbo)zookeeper進行集群配置管理(二)

四、RPC實現原理(HSF、dubbo)netty替換java socket(四)

五、待補充

NO.1  TCP傳輸協議

為什麼選擇TCP作為傳輸協議?HTTP在TCP的上一層,位於應用層,TCP位於網絡層,以越往底層越快的原理,我就不過多解釋為什麼選擇tcp作為傳輸協議了。 那麼在項目中我們怎麼使用tcp進行調用呢?直接上個例子代碼:

socket服務端:

 

import java.net.*;
import java.io.*;

/**
 * socket編程之:簡單socket server
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketServer {
    private ServerSocket serverSocket;
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;

    public SocketServer() {
        try {
            serverSocket = new ServerSocket(9999);
            while (true) {
                // 此處會阻塞,後面會講到nio的作用 
                socket = serverSocket.accept();
                in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                out = new PrintWriter(socket.getOutputStream(), true);
                String line = in.readLine();
                // 打印出來看看結果
                System.out.println("line:" + line);
                
                // 返回給client端,通知我已收到數據
                out.println("you input is :" + line);
                out.close();
                in.close();
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketServer();
    }
}

 

scoket客戶端:

 

import java.io.*;
import java.net.*;

/**
 * socket編程之:簡單socket client
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketClient {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;

    public SocketClient() {
        try {
            socket = new Socket("127.0.0.1", 9999);
            in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            // 向服務端寫數據
            BufferedReader line = new BufferedReader(new InputStreamReader(
                    System.in));

            out.println(line.readLine());
            line.close();
            // 打印出來服務端發回來的回執
            System.out.println(in.readLine());
            
            in.close();
            out.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketClient();
    }
}

先啟動server,再啟動client,輸入參數,回車,兩者第一次會話完成。

小結總結:

目前例子中我們使用了標准io socket,這裡的很多時候會阻塞,如accept()、read()時都會阻塞。測試的時候可以讓客戶端睡眠幾秒,在這期間啟動第二個客戶端,這個時候第一個客戶端未完成前,第二個客戶端是被阻塞在accept()中的。  這種情況可以給每個客戶端都單獨分配一個線程,但是這樣創建過多的線程,可能會嚴重影響服務器的性能。 第二種解決方案就是使用NIO 非阻塞的通信方式,jdk1.4之後已經引入了這個功能,這樣可以使得服務器只要啟動一個線程就能處理所有的客戶端socket請求。netty就是基於NIO的高性能框架,相比jdk nio做了很多改進,修復了一些缺陷。  (這裡不對netty與jdk nio做過多贅述,這不在我們討論原理細節裡,如果大家對這方面有興趣,我會單獨寫篇隨筆進行深度講解)

 

NO.2 序列化方式

在真正的項目中,很多時候我們傳的都是自己定義的類。在遠程通訊中,類的傳輸我們需要對類進行序列化和反序列化。序列化的方式有多種,如二進制、xml、soap。我們就以用的最多的二進制進行舉例:

socket服務端:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * socket編程之:傳輸對象server
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketObjectSever {

    private ServerSocket serverSocket;
    private ObjectInputStream in;
    private ObjectOutputStream out;

    public SocketObjectSever() {
        try {
            serverSocket = new ServerSocket(9999);

            while (true) {
                // 此處會阻塞,後面會講到nio的作用
                Socket socket = serverSocket.accept();

                in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());

                // 接收server端傳來的數據,並轉為Student
                Student student = (Student) in.readObject();
                // 重寫了toString()方法,打印出來看看
                System.out.println("Server: " + student);

                // 返回給client端,通知我已收到數據
                out.writeObject("yes client, I receive");
                out.flush();

            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketObjectSever();
    }

}

 

socket客戶端:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

 
/**
 * socket編程之:傳輸對象client
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketObjectClient {
    private Socket socket;
    private ObjectInputStream in;
    private ObjectOutputStream out;
     
    public SocketObjectClient() {
        try {
            socket = new Socket("127.0.0.1",9999);
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputStream(socket.getInputStream());
             
            /*
             * 建一個student對象,用於傳輸
             */
            Student s = new Student("chengwei.lcw", 28);
            
            // 把對象寫到管道中,client端進行接收
            out.writeObject(s);
            out.flush();
             
            String receive = (String) in.readObject();
            System.out.println("Client Receive :"+receive);
             
            in.close();
            out.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args) {
        new SocketObjectClient();
    }
 
}

 

另外定義一個要傳輸的類:

import java.io.Serializable;

/**
 * socket編程之:要進行傳輸的類,需要繼承Serializable接口
 * 
 * @author chengwei.lcw 2016-11-27
 * 
 */
public class Student implements Serializable {
    
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String toString() {
        return "name=" + this.name + ", age=" + this.age; 
    }
}

依然先啟動server,再啟動client,server端控制台輸出:

Server: name=chengwei.lcw, age=28

這樣為止,我們的socket可以傳輸對象了。

這裡我們使用的序列化方式為java直接進行序列化,而hessian序列化比Java序列化高效很多,生成的字節流也要短很多,因為hessian在序列化時會把字節流進行壓縮。在後面的升級版中我會使用hessian序列化的方式進行序列化。

 

公司裡還有事,而且我不知道這些是不是各位朋友想看到的內容,忙完今天我會繼續進行補充。 哪裡有講的不對的希望大家來矯正。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved