Heim >php教程 >php手册 >So verwenden Sie Remote Procedure Call (RPC)

So verwenden Sie Remote Procedure Call (RPC)

坏嘻嘻
坏嘻嘻Original
2018-09-14 11:44:184259Durchsuche

Jeder, der Socket-Programmierung im HTTP-Anforderungsstil durchgeführt hat, weiß, dass beim Entwerfen eines Kommunikationsprotokolls sehr häufig die Aufteilungsmethode „Nachrichtenkopf/Nachrichtentext“ verwendet wird. Der Nachrichtenkopf teilt der anderen Partei mit, wofür die Nachricht bestimmt ist. und der Nachrichtentext Sagen Sie der anderen Person, was sie tun soll.

Vergleich von RPC basierend auf dem HTTP-Protokoll und RPC basierend auf dem TCP-Protokoll:

RPC zwischen Systemen basierend auf dem HTTP-Protokoll ist flexibel und einfach zu implementieren (eine Vielzahl offener). Quell-Webserver-Unterstützung), offen (internationale Standards) und von Natur aus Aufrufe zwischen heterogenen Plattformen unterstützend, ist es weit verbreitet. Dies entspricht der Implementierungsversion des TCP-Protokolls, die effizienter, aber komplexer zu implementieren ist und aufgrund unterschiedlicher Protokolle und Standards schwierig ist, plattformübergreifende und unternehmensübergreifende Kommunikation zu ermöglichen.

Die Implementierung des HTTP-Protokolls hat ihre Nachteile. Da es sich um ein Oberschichtprotokoll handelt, das Informationen mit demselben Inhalt sendet, ist die Anzahl der von der HTTP-Protokollübertragung belegten Bytes definitiv höher als die Anzahl der vom TCP-Protokoll belegten Bytes Übertragung. Mehr. Daher ist in derselben Netzwerkumgebung die Effizienz der Übertragung desselben Inhalts über das HTTP-Protokoll geringer als die der Datenübertragung über das TCP-Protokoll, und die Informationsübertragung dauert länger. Natürlich kann diese Lücke durch eine Optimierung der Code-Implementierung und die Verwendung der gzip-Datenkomprimierung verringert werden. Durch die Abwägung der Vor- und Nachteile und die Berücksichtigung der Auswirkungen seiner Leistung auf die Benutzererfahrung in der tatsächlichen Umgebung bietet RPC auf Basis des HTTP-Protokolls immer noch große Vorteile.

1. Implementieren Sie RPC basierend auf dem TCP-Protokoll

Service-Schnittstelle:

public interface SayHelloService{
     public String sayHello(String helloArg);
}

Service-Implementierung:

public class SayHelloServiceImpl implements SayHelloService {
    
    @Override
    public String sayHello(String helloArg) {
        if(helloArg.equals("Hello")) {
            return "hello";
        }else{
            return "bye bye";
        }
    }          
}

Service-Consumer-Consumer-Schlüsselcode:

// 接口名称
String interfacename = SayHelloService.class.getName();
// 需要远程执行的方法
Method method = SayHelloService.class.getMethod("sayHello", java.lang.String.class);
// 需要传递到远端的参数
Object[] arguments = {"hello"};
Socket socket = new Socket("127.0.0.1", 1234);
// 将方法名称和参数传递到远端
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(interfacename); // 接口名称
output.writeUTF(method.getName()); // 方法名称
output.writeObject(method.getParameterTypes());
output.writeObject(arguments);

// 从远端读取方法的执行结果
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object result = input.readObject();

Dienstanbieter-Privider-Schlüsselcode:

ServiceSocket server = new ServerSocket(1234);
while(true){
    Socket socket = server.accept();

    //读取服务信息
    ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
    String interfacename = input.readUTF();    //接口名称
    String methodName = input.readUTF();    // 方法名称
    Class<?>[] parameterTypes = (Class<?>[])input.readObject(); //参数类型
    Object[] arguments = (Object[]) input.readObject(); //参数对象
    
    // 执行调用
    Class serviceinterfaceclass = Class.forName(interfacename);
    Object service = service.get(interfacename);
    Method method = serviceinterfaceclass.getMethod(methodName, parameterTypes);
    Object result = method.invoke(service, arguments);

    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
    output.writeObject(result);
}

2. RPC basierend auf HTTP-Protokoll

Protokollanforderungsdefinition:

public class Request{
    
    /**
    * 协议编码
    */
    private byte encode;

    /**
    * 命令
    */
    private String command;

    /**
    * 命令长度
    */
    private int commandLength;
}

Protokollantwortdefinition:

public class Response {

    /**
    * 编码
    */
    private byte encode;

    /**
    * 响应长度
    */
    private int responseLength;

    /**
    * 响应
    */
    private String response;
}

Schlüsselcode für Client-Implementierung:

// 请求
Request request = new Request();
request.setCommand("HELLO");
request.setCommandLength(request.getCommand().length());
request.setEncode(Encode.UTF8.getValue());

Socket client = new Socket("127.0.0.1", 4567);
OutputStream output = client.getOutputStream();

// 发送请求
ProtocolUtil.writeRequest(output, request);
InputStream input = client.getInputStream();
Response = response = ProtocolUtil.readResponse(input);

Schlüsselcode für Server-Implementierung:

ServerSocket server = new ServerSocket(4567);
while(true){
    Socket client  = server.accept();
   
    //读取响应数据
    InputStream input = client.getInputStream();
    Request request = ProtocolUtil.readRequest(input);
    OutputStream output = client.getOutputStream();
    
    // 组装响应
    Response response = new Response();
    response.setEncode(Encode.UTF8.getValue());
    if(request.getCommand().equals("HELLO")){
       response.setResponse("hello!"); 
    }else {
        response.setResponse("bye bye");    
    }
    
    resposne.setResponseLength(response.getResponse().length());
    ProtocolUtil.writeResponse(output, response);
}

ProtocolUtil-Code

public class ProtocolUtil {

    public static Request readRequest(InputStream input) throws IOException {
        //读取编码
        byte[] encodeByte = new byte[1];
        input.read(encodeByte);
        byte encode = encodeByte[0];
        
        //读取命令长度
        byte[] commandLengthBytes = new byte[4];
        input.read(commandLengthBytes);
        int commandLength = ByteUtil.bytes2Int(commandLengthBytes);

        //读取命令
        byte[] commandBytes = new byte[commandLength];
        input.read(commandBytes);
        String command = "";
        if(Encode.GBK.getValue() == encode){
            command = new String(commandBytes, "GBK");
        }else{
            command = new String(commandBytes, "UTF8");
        }

        // 组装请求返回
        Request request = new Request();
        request.setCommand(command);
        request.setEncode(encode);
        request.setCommandLength(commandLength);

        return request;
    }

    public static void writeResponse(OutputStream output, Response response) throws IOExceptiono{
        //将response响应返回给客户端
        output.write(response.getEncode());
       // output.write(response.getResponseLength()); 
        //直接write一个int类型会截取低8位传输,丢失高8位
        output.write(ByteUtil.int2ByteArray(response.getResponseLength()));
        if(Encode.GBK.getValue() == resposne.getEncode()){
            output.write(response.getResponse().getBytes("GBK"));
        }else{
            output.write(response.getResponse().getBytes("UTF8"));
        }

        output.flush();
    }
}
public static int bytes2Int(byte[] bytes){
    int num = bytes[3] & 0xFF;
    num |= ((bytes[2] << 8) & 0xFF00;
    num |= ((bytes[1] << 16) & 0xFF0000;
    num |= ((bytes[0] << 24) & oxFF000000;

    return num;
}

Verwandte Empfehlungen:

HTTP vorläufig Hinweise - Yitoem

http://windows.php.net/ und http://php.net/ bieten beide PHP-Downloads, was ist der Unterschied?


Das obige ist der detaillierte Inhalt vonSo verwenden Sie Remote Procedure Call (RPC). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn