Maison  >  Article  >  php教程  >  Comment utiliser l'appel de procédure à distance (RPC)

Comment utiliser l'appel de procédure à distance (RPC)

坏嘻嘻
坏嘻嘻original
2018-09-14 11:44:184232parcourir

Quiconque a fait de la programmation Socket dans le style de requête HTTP sait que lorsque nous concevons un protocole de communication, la méthode de division « en-tête de message/corps de message » est très couramment utilisée. L'en-tête de message indique à l'autre partie à quoi sert le message, et le corps du message Dites à l'autre personne quoi faire.

Comparaison du RPC basé sur le protocole HTTP et du RPC basé sur le protocole TCP :

Le RPC entre les systèmes basés sur le protocole HTTP est flexible et facile à mettre en œuvre (une variété d'open support du serveur Web source), ouvert (normes internationales) et prend en charge intrinsèquement les appels entre plates-formes hétérogènes, il a été largement utilisé. À cela correspond la version de mise en œuvre du protocole TCP, qui est plus efficace, mais plus complexe à mettre en œuvre, et en raison des différents protocoles et normes, il est difficile de faciliter la communication multiplateforme et inter-entreprises.

La mise en œuvre du protocole HTTP a ses inconvénients. Puisqu'il s'agit d'un protocole de couche supérieure, envoyant des informations contenant le même contenu, le nombre d'octets occupés par la transmission du protocole HTTP est nettement supérieur au nombre d'octets occupés par le protocole TCP. transmission Plus. Par conséquent, dans le même environnement réseau, l'efficacité de la transmission du même contenu via le protocole HTTP sera inférieure à celle de la transmission de données via le protocole TCP, et la transmission des informations prendra plus de temps. Bien entendu, cet écart peut être réduit en optimisant l’implémentation du code et en utilisant la compression des données gzip. En pesant le pour et le contre et en considérant l’impact de ses performances sur l’expérience utilisateur dans l’environnement réel, le RPC basé sur le protocole HTTP présente encore de grands avantages.

1. Implémenter RPC basé sur le protocole TCP

Interface de service :

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

Implémentation du service :

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

Consommateur de service Code clé du consommateur :

// 接口名称
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();

Code de clé privée du fournisseur de services :

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 basé sur le protocole HTTP

Définition de la demande de protocole :

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

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

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

Définition de la réponse du protocole :

public class Response {

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

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

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

Code clé pour l'implémentation du client :

// 请求
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);

Code clé pour l'implémentation du serveur :

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);
}

Code ProtocolUtil

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;
}

Recommandations associées :

Annotations préliminaires HTTP - Yitoem

http://windows.php.net/ et http : //php.net/ proposent tous deux des téléchargements PHP, quelle est la différence ?


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn